diff options
Diffstat (limited to 'clang')
96 files changed, 2018 insertions, 437 deletions
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 85a3a8ab6970..2eacf1105c18 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1840,7 +1840,8 @@ enum class MultiVersionKind { None, Target, CPUSpecific, - CPUDispatch + CPUDispatch, + TargetClones }; /// Represents a function declaration or definition. @@ -2459,6 +2460,10 @@ public: /// the target functionality. bool isTargetMultiVersion() const; + /// True if this function is a multiversioned dispatch function as a part of + /// the target-clones functionality. + bool isTargetClonesMultiVersion() const; + /// \brief Get the associated-constraints of this function declaration. /// Currently, this will either be a vector of size 1 containing the /// trailing-requires-clause or an empty vector. diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 18468c8ca1c4..2a0a19597391 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -352,7 +352,7 @@ protected: DeclContext *Parent, std::size_t Extra = 0); private: - bool AccessDeclContextSanity() const; + bool AccessDeclContextCheck() const; /// Get the module ownership kind to use for a local lexical child of \p DC, /// which may be either a local or (rarely) an imported declaration. @@ -472,11 +472,11 @@ public: void setAccess(AccessSpecifier AS) { Access = AS; - assert(AccessDeclContextSanity()); + assert(AccessDeclContextCheck()); } AccessSpecifier getAccess() const { - assert(AccessDeclContextSanity()); + assert(AccessDeclContextCheck()); return AccessSpecifier(Access); } diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 991abef73363..2c63406fba18 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6305,8 +6305,10 @@ public: bool isCmpXChg() const { return getOp() == AO__c11_atomic_compare_exchange_strong || getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__hip_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_strong || getOp() == AO__opencl_atomic_compare_exchange_weak || + getOp() == AO__hip_atomic_compare_exchange_weak || getOp() == AO__atomic_compare_exchange || getOp() == AO__atomic_compare_exchange_n; } @@ -6341,6 +6343,8 @@ public: auto Kind = (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max) ? AtomicScopeModelKind::OpenCL + : (Op >= AO__hip_atomic_load && Op <= AO__hip_atomic_fetch_max) + ? AtomicScopeModelKind::HIP : AtomicScopeModelKind::None; return AtomicScopeModel::create(Kind); } diff --git a/clang/include/clang/AST/GlobalDecl.h b/clang/include/clang/AST/GlobalDecl.h index 8cb56fb4ae90..88abba28c991 100644 --- a/clang/include/clang/AST/GlobalDecl.h +++ b/clang/include/clang/AST/GlobalDecl.h @@ -18,6 +18,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Basic/ABI.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMapInfo.h" @@ -129,8 +130,12 @@ public: } KernelReferenceKind getKernelReferenceKind() const { - assert(isa<FunctionDecl>(getDecl()) && - cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>() && + assert(((isa<FunctionDecl>(getDecl()) && + cast<FunctionDecl>(getDecl())->hasAttr<CUDAGlobalAttr>()) || + (isa<FunctionTemplateDecl>(getDecl()) && + cast<FunctionTemplateDecl>(getDecl()) + ->getTemplatedDecl() + ->hasAttr<CUDAGlobalAttr>())) && "Decl is not a GPU kernel!"); return static_cast<KernelReferenceKind>(Value.getInt()); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index d6e5b215462b..5221d05477d0 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4227,8 +4227,8 @@ AST_MATCHER(VarDecl, isInitCapture) { return Node.isInitCapture(); } /// lambdaExpr(forEachLambdaCapture( /// lambdaCapture(capturesVar(varDecl(hasType(isInteger())))))) /// will trigger two matches, binding for 'x' and 'y' respectively. -AST_MATCHER_P(LambdaExpr, forEachLambdaCapture, LambdaCaptureMatcher, - InnerMatcher) { +AST_MATCHER_P(LambdaExpr, forEachLambdaCapture, + internal::Matcher<LambdaCapture>, InnerMatcher) { BoundNodesTreeBuilder Result; bool Matched = false; for (const auto &Capture : Node.captures()) { @@ -4655,7 +4655,8 @@ extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture; /// lambdaExpr(hasAnyCapture(lambdaCapture())) and /// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) /// both match `[=](){ return t; }`. -AST_MATCHER_P(LambdaExpr, hasAnyCapture, LambdaCaptureMatcher, InnerMatcher) { +AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<LambdaCapture>, + InnerMatcher) { for (const LambdaCapture &Capture : Node.captures()) { clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); if (InnerMatcher.matches(Capture, Finder, &Result)) { diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 3b9b22e87f35..b8e453fcc235 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -515,7 +515,7 @@ public: /// of the most derived class while we're in the base class. VirtualBaseBranch, - /// Number of different kinds, for validity checks. We subtract 1 so that + /// Number of different kinds, for assertions. We subtract 1 so that /// to keep receiving compiler warnings when we don't cover all enum values /// in a switch. NumKindsMinusOne = VirtualBaseBranch diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h new file mode 100644 index 000000000000..a5d4a5d6ba40 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -0,0 +1,134 @@ +//===- DataflowAnalysis.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types and functions for building dataflow analyses +// that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H + +#include <iterator> +#include <utility> +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" + +namespace clang { +namespace dataflow { + +/// Base class template for dataflow analyses built on a single lattice type. +/// +/// Requirements: +/// +/// `Derived` must be derived from a specialization of this class template and +/// must provide the following public members: +/// * `LatticeT initialElement()` - returns a lattice element that models the +/// initial state of a basic block; +/// * `LatticeT transfer(const Stmt *, const LatticeT &, Environment &)` - +/// applies the analysis transfer function for a given statement and lattice +/// element. +/// +/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must +/// provide the following public members: +/// * `LatticeJoinEffect join(const LatticeT &)` - joins the object and the +/// argument by computing their least upper bound, modifies the object if +/// necessary, and returns an effect indicating whether any changes were +/// made to it; +/// * `bool operator==(const LatticeT &) const` - returns true if and only if +/// the object is equal to the argument. +template <typename Derived, typename LatticeT> +class DataflowAnalysis : public TypeErasedDataflowAnalysis { +public: + /// Bounded join-semilattice that is used in the analysis. + using Lattice = LatticeT; + + explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} + + ASTContext &getASTContext() final { return Context; } + + TypeErasedLattice typeErasedInitialElement() final { + return {static_cast<Derived *>(this)->initialElement()}; + } + + LatticeJoinEffect joinTypeErased(TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + Lattice &L1 = llvm::any_cast<Lattice &>(E1.Value); + const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value); + return L1.join(L2); + } + + bool isEqualTypeErased(const TypeErasedLattice &E1, + const TypeErasedLattice &E2) final { + const Lattice &L1 = llvm::any_cast<const Lattice &>(E1.Value); + const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value); + return L1 == L2; + } + + TypeErasedLattice transferTypeErased(const Stmt *Stmt, + const TypeErasedLattice &E, + Environment &Env) final { + const Lattice &L = llvm::any_cast<const Lattice &>(E.Value); + return {static_cast<Derived *>(this)->transfer(Stmt, L, Env)}; + } + +private: + ASTContext &Context; +}; + +// Model of the program at a given program point. +template <typename LatticeT> struct DataflowAnalysisState { + // Model of a program property. + LatticeT Lattice; + + // Model of the state of the program (store and heap). + Environment Env; +}; + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. Indices +/// of the returned vector correspond to basic block IDs. +/// +/// Requirements: +/// +/// `Cfg` must have been built with `CFG::BuildOptions::setAllAlwaysAdd()` to +/// ensure that all sub-expressions in a basic block are evaluated. +template <typename AnalysisT> +std::vector<llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>> +runDataflowAnalysis(const CFG &Cfg, AnalysisT &Analysis, + const Environment &InitEnv) { + auto TypeErasedBlockStates = + runTypeErasedDataflowAnalysis(Cfg, Analysis, InitEnv); + std::vector< + llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>> + BlockStates; + BlockStates.reserve(TypeErasedBlockStates.size()); + llvm::transform(std::move(TypeErasedBlockStates), + std::back_inserter(BlockStates), [](auto &OptState) { + return std::move(OptState).map([](auto &&State) { + return DataflowAnalysisState<typename AnalysisT::Lattice>{ + llvm::any_cast<typename AnalysisT::Lattice>( + std::move(State.Lattice.Value)), + std::move(State.Env)}; + }); + }); + return BlockStates; +} + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWANALYSIS_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h new file mode 100644 index 000000000000..69a5c2e47b66 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -0,0 +1,27 @@ +//===-- DataflowEnvironment.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an Environment class that is used by dataflow analyses +// that run over Control-Flow Graphs (CFGs) to keep track of the state of the +// program at given program points. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H + +namespace clang { +namespace dataflow { + +/// Holds the state of the program (store and heap) at a given program point. +class Environment {}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h new file mode 100644 index 000000000000..37d2e0200410 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h @@ -0,0 +1,29 @@ +//===- DataflowLattice.h ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines base types for building lattices to be used in dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H + +namespace clang { +namespace dataflow { + +/// Effect indicating whether a lattice join operation resulted in a new value. +enum class LatticeJoinEffect { + Unchanged, + Changed, +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWLATTICE_H diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h new file mode 100644 index 000000000000..9448b911f471 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -0,0 +1,95 @@ +//===- TypeErasedDataflowAnalysis.h -----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines type-erased base types and functions for building dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H + +#include <vector> + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/DataflowLattice.h" +#include "llvm/ADT/Any.h" +#include "llvm/ADT/Optional.h" + +namespace clang { +namespace dataflow { + +/// Type-erased lattice element container. +/// +/// Requirements: +/// +/// The type of the object stored in the container must be a bounded +/// join-semilattice. +struct TypeErasedLattice { + llvm::Any Value; +}; + +/// Type-erased base class for dataflow analyses built on a single lattice type. +class TypeErasedDataflowAnalysis { +public: + virtual ~TypeErasedDataflowAnalysis() {} + + /// Returns the `ASTContext` that is used by the analysis. + virtual ASTContext &getASTContext() = 0; + + /// Returns a type-erased lattice element that models the initial state of a + /// basic block. + virtual TypeErasedLattice typeErasedInitialElement() = 0; + + /// Joins two type-erased lattice elements by computing their least upper + /// bound. Places the join result in the left element and returns an effect + /// indicating whether any changes were made to it. + virtual LatticeJoinEffect joinTypeErased(TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Returns true if and only if the two given type-erased lattice elements are + /// equal. + virtual bool isEqualTypeErased(const TypeErasedLattice &, + const TypeErasedLattice &) = 0; + + /// Applies the analysis transfer function for a given statement and + /// type-erased lattice element. + virtual TypeErasedLattice transferTypeErased(const Stmt *, + const TypeErasedLattice &, + Environment &) = 0; +}; + +/// Type-erased model of the program at a given program point. +struct TypeErasedDataflowAnalysisState { + /// Type-erased model of a program property. + TypeErasedLattice Lattice; + + /// Model of the state of the program (store and heap). + Environment Env; +}; + +/// Performs dataflow analysis and returns a mapping from basic block IDs to +/// dataflow analysis states that model the respective basic blocks. Indices +/// of the returned vector correspond to basic block IDs. +/// +/// Requirements: +/// +/// `Cfg` must have been built with `CFG::BuildOptions::setAllAlwaysAdd()` to +/// ensure that all sub-expressions in a basic block are evaluated. +std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> +runTypeErasedDataflowAnalysis(const CFG &Cfg, + TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv); + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_TYPEERASEDDATAFLOWANALYSIS_H diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 39588d94cf09..fab3f3edfb83 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2677,6 +2677,40 @@ def Target : InheritableAttr { }]; } +def TargetClones : InheritableAttr { + let Spellings = [GCC<"target_clones">]; + let Args = [VariadicStringArgument<"featuresStrs">]; + let Documentation = [TargetClonesDocs]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let AdditionalMembers = [{ + StringRef getFeatureStr(unsigned Index) const { + return *(featuresStrs_begin() + Index); + } + // 'default' is always moved to the end, so it isn't considered + // when mangling the index. + unsigned getMangledIndex(unsigned Index) const { + if (getFeatureStr(Index) == "default") + return std::count_if(featuresStrs_begin(), featuresStrs_end(), + [](StringRef S) { return S != "default"; }); + + return std::count_if(featuresStrs_begin(), featuresStrs_begin() + Index, + [](StringRef S) { return S != "default"; }); + } + + // True if this is the first of this version to appear in the config string. + // This is used to make sure we don't try to emit this function multiple + // times. + bool isFirstOfVersion(unsigned Index) const { + StringRef FeatureStr(getFeatureStr(Index)); + return 0 == std::count_if( + featuresStrs_begin(), featuresStrs_begin() + Index, + [FeatureStr](StringRef S) { return S == FeatureStr; }); + } + }]; +} + +def : MutualExclusions<[TargetClones, Target, CPUDispatch, CPUSpecific]>; + def MinVectorWidth : InheritableAttr { let Spellings = [Clang<"min_vector_width">]; let Args = [UnsignedArgument<"VectorWidth">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e7afb3699eb1..10cce4c2d689 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2233,6 +2233,40 @@ Additionally, a function may not become multiversioned after its first use. }]; } +def TargetClonesDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``target_clones("OPTIONS")`` attribute. This attribute may be +attached to a function declaration and causes function multiversioning, where +multiple versions of the function will be emitted with different code +generation options. Additionally, these versions will be resolved at runtime +based on the priority of their attribute options. All ``target_clone`` functions +are considered multiversioned functions. + +All multiversioned functions must contain a ``default`` (fallback) +implementation, otherwise usages of the function are considered invalid. +Additionally, a function may not become multiversioned after its first use. + +The options to ``target_clones`` can either be a target-specific architecture +(specified as ``arch=CPU``), or one of a list of subtarget features. + +Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2", +"avx", "xop" and largely correspond to the machine specific options handled by +the front end. + +The versions can either be listed as a comma-separated sequence of string +literals or as a single string literal containing a comma-separated list of +versions. For compatibility with GCC, the two formats can be mixed. For +example, the following will emit 4 versions of the function: + + .. code-block:: c++ + + __attribute__((target_clones("arch=atom,avx2","arch=ivybridge","default"))) + void foo() {} + +}]; +} + def MinVectorWidthDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index b05777889e79..ad8b66aa490b 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -854,6 +854,19 @@ ATOMIC_BUILTIN(__opencl_atomic_fetch_max, "v.", "t") ATOMIC_BUILTIN(__atomic_fetch_min, "v.", "t") ATOMIC_BUILTIN(__atomic_fetch_max, "v.", "t") +// HIP atomic builtins. +ATOMIC_BUILTIN(__hip_atomic_load, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_store, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_compare_exchange_weak, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_compare_exchange_strong, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_min, "v.", "t") +ATOMIC_BUILTIN(__hip_atomic_fetch_max, "v.", "t") + #undef ATOMIC_BUILTIN // Non-overloaded atomic builtins. diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index cd6b2df10e52..70b0184f199f 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -404,6 +404,7 @@ BUILTIN(__builtin_altivec_vbpermd, "V2ULLiV2ULLiV16Uc", "") // P8 Crypto built-ins. BUILTIN(__builtin_altivec_crypto_vsbox, "V2ULLiV2ULLi", "") BUILTIN(__builtin_altivec_crypto_vpermxor, "V16UcV16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_crypto_vpermxor_be, "V16UcV16UcV16UcV16Uc", "") BUILTIN(__builtin_altivec_crypto_vshasigmaw, "V4UiV4UiIiIi", "") BUILTIN(__builtin_altivec_crypto_vshasigmad, "V2ULLiV2ULLiIiIi", "") BUILTIN(__builtin_altivec_crypto_vcipher, "V2ULLiV2ULLiV2ULLi", "") @@ -424,6 +425,12 @@ BUILTIN(__builtin_altivec_vctzh, "V8UsV8Us", "") BUILTIN(__builtin_altivec_vctzw, "V4UiV4Ui", "") BUILTIN(__builtin_altivec_vctzd, "V2ULLiV2ULLi", "") +// P8 BCD builtins. +BUILTIN(__builtin_ppc_bcdadd, "V16UcV16UcV16UcIi", "") +BUILTIN(__builtin_ppc_bcdsub, "V16UcV16UcV16UcIi", "") +BUILTIN(__builtin_ppc_bcdadd_p, "iiV16UcV16Uc", "") +BUILTIN(__builtin_ppc_bcdsub_p, "iiV16UcV16Uc", "") + BUILTIN(__builtin_altivec_vclzlsbb, "SiV16Uc", "") BUILTIN(__builtin_altivec_vctzlsbb, "SiV16Uc", "") BUILTIN(__builtin_altivec_vprtybw, "V4UiV4Ui", "") diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ff8c36910e13..2f50918b527b 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -189,6 +189,12 @@ def err_drv_invalid_mtp : Error< "invalid thread pointer reading mode '%0'">; def err_drv_missing_arg_mtp : Error< "missing argument to '%0'">; +def warn_drv_missing_plugin_name : Warning< + "missing plugin name in %0">, + InGroup<InvalidCommandLineArgument>; +def warn_drv_missing_plugin_arg : Warning< + "missing plugin argument for plugin %0 in %1">, + InGroup<InvalidCommandLineArgument>; def err_drv_invalid_libcxx_deployment : Error< "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; def err_drv_invalid_argument_to_option : Error< @@ -394,6 +400,8 @@ def warn_ignoring_verify_debuginfo_preserve_export : Warning< InGroup<UnusedCommandLineArgument>; def err_invalid_branch_protection: Error < "invalid branch protection option '%0' in '%1'">; +def warn_unsupported_branch_protection: Warning < + "invalid branch protection option '%0' in '%1'">, InGroup<BranchProtection>; def err_invalid_sls_hardening : Error< "invalid sls hardening option '%0' in '%1'">; def err_sls_hardening_arm_not_supported : Error< diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 85d373845c81..90df3a424406 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -56,7 +56,9 @@ def CoroutineMissingUnhandledException : DiagGroup<"coroutine-missing-unhandled-exception">; def DeprecatedExperimentalCoroutine : DiagGroup<"deprecated-experimental-coroutine">; -def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedExperimentalCoroutine]>; +def DeprecatedCoroutine : + DiagGroup<"deprecated-coroutine", [DeprecatedExperimentalCoroutine]>; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedCoroutine]>; def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [BitFieldConstantConversion, @@ -1273,9 +1275,14 @@ def : DiagGroup<"spirv-compat", [SpirCompat]>; // Alias. // Warning for the GlobalISel options. def GlobalISel : DiagGroup<"global-isel">; +// A warning group for the GNU extension to allow mixed specifier types for +// target-clones multiversioning. +def TargetClonesMixedSpecifiers : DiagGroup<"target-clones-mixed-specifiers">; + // A warning group specifically for warnings related to function // multiversioning. -def FunctionMultiVersioning : DiagGroup<"function-multiversion">; +def FunctionMultiVersioning + : DiagGroup<"function-multiversion", [TargetClonesMixedSpecifiers]>; def NoDeref : DiagGroup<"noderef">; @@ -1331,3 +1338,6 @@ def PedanticMacros : DiagGroup<"pedantic-macros", BuiltinMacroRedefined, RestrictExpansionMacro, FinalMacro]>; + +def BranchProtection : DiagGroup<"branch-protection">; + diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index aef86516707c..375930c14848 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -30,7 +30,7 @@ namespace clang { // Size of each of the diagnostic categories. enum { DIAG_SIZE_COMMON = 300, - DIAG_SIZE_DRIVER = 250, + DIAG_SIZE_DRIVER = 300, DIAG_SIZE_FRONTEND = 150, DIAG_SIZE_SERIALIZATION = 120, DIAG_SIZE_LEX = 400, diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 1bc2e8b0c7ef..92e877074ad3 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1548,6 +1548,9 @@ def note_meant_to_use_typename : Note< let CategoryName = "Coroutines Issue" in { def err_for_co_await_not_range_for : Error< "'co_await' modifier can only be applied to range-based for loop">; +def warn_deprecated_for_co_await : Warning< + "'for co_await' belongs to CoroutineTS instead of C++20, which is deprecated">, + InGroup<DeprecatedCoroutine>; } let CategoryName = "Concepts Issue" in { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index dc67f86f25ca..fb5bd53f7432 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2979,9 +2979,13 @@ def err_attribute_requires_opencl_version : Error< "attribute %0 is supported in the OpenCL version %1%select{| onwards}2">; def err_invalid_branch_protection_spec : Error< "invalid or misplaced branch protection specification '%0'">; +def warn_unsupported_branch_protection_spec : Warning< + "unsupported branch protection specification '%0'">, InGroup<BranchProtection>; + def warn_unsupported_target_attribute : Warning<"%select{unsupported|duplicate|unknown}0%select{| architecture|" - " tune CPU}1 '%2' in the 'target' attribute string; 'target' " + " tune CPU}1 '%2' in the '%select{target|target_clones}3' " + "attribute string; '%select{target|target_clones}3' " "attribute ignored">, InGroup<IgnoredAttributes>; def err_attribute_unsupported @@ -9864,6 +9868,8 @@ def warn_duplicate_attribute_exact : Warning< def warn_duplicate_attribute : Warning< "attribute %0 is already applied with different arguments">, InGroup<IgnoredAttributes>; +def err_disallowed_duplicate_attribute : Error< + "attribute %0 cannot appear more than once on a declaration">; def warn_sync_fetch_and_nand_semantics_change : Warning< "the semantics of this intrinsic changed with GCC " @@ -11254,9 +11260,11 @@ def err_multiversion_duplicate : Error< "multiversioned function redeclarations require identical target attributes">; def err_multiversion_noproto : Error< "multiversioned function must have a prototype">; -def err_multiversion_disallowed_other_attr : Error< - "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioning cannot be combined" - " with attribute %1">; +def err_multiversion_disallowed_other_attr + : Error<"attribute " + "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' " + "multiversioning cannot be combined" + " with attribute %1">; def err_multiversion_mismatched_attrs : Error<"attributes on multiversioned functions must all match, attribute " "%0 %select{is missing|has different arguments}1">; @@ -11264,11 +11272,14 @@ def err_multiversion_diff : Error< "multiversioned function declaration has a different %select{calling convention" "|return type|constexpr specification|inline specification|linkage|" "language linkage}0">; -def err_multiversion_doesnt_support : Error< - "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not " - "yet support %select{function templates|virtual functions|" - "deduced return types|constructors|destructors|deleted functions|" - "defaulted functions|constexpr functions|consteval function}1">; +def err_multiversion_doesnt_support + : Error<"attribute " + "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' " + "multiversioned functions do not " + "yet support %select{function templates|virtual functions|" + "deduced return types|constructors|destructors|deleted functions|" + "defaulted functions|constexpr functions|consteval " + "function|lambdas}1">; def err_multiversion_not_allowed_on_main : Error< "'main' cannot be a multiversioned function">; def err_multiversion_not_supported : Error< @@ -11285,6 +11296,19 @@ def warn_multiversion_duplicate_entries : Warning< def warn_dispatch_body_ignored : Warning< "body of cpu_dispatch function will be ignored">, InGroup<FunctionMultiVersioning>; +def err_target_clone_must_have_default + : Error<"'target_clones' multiversioning requires a default target">; +def err_target_clone_doesnt_match + : Error<"'target_clones' attribute does not match previous declaration">; +def warn_target_clone_mixed_values + : ExtWarn< + "mixing 'target_clones' specifier mechanisms is permitted for GCC " + "compatibility; use a comma separated sequence of string literals, " + "or a string literal containing a comma-separated list of versions">, + InGroup<TargetClonesMixedSpecifiers>; +def warn_target_clone_duplicate_options + : Warning<"version list contains duplicate entries">, + InGroup<FunctionMultiVersioning>; // three-way comparison operator diagnostics def err_implied_comparison_category_type_not_found : Error< diff --git a/clang/include/clang/Basic/SyncScope.h b/clang/include/clang/Basic/SyncScope.h index ce8fb9cbed13..34703310af2b 100644 --- a/clang/include/clang/Basic/SyncScope.h +++ b/clang/include/clang/Basic/SyncScope.h @@ -40,6 +40,11 @@ namespace clang { /// Update getAsString. /// enum class SyncScope { + HIPSingleThread, + HIPWavefront, + HIPWorkgroup, + HIPAgent, + HIPSystem, OpenCLWorkGroup, OpenCLDevice, OpenCLAllSVMDevices, @@ -49,6 +54,16 @@ enum class SyncScope { inline llvm::StringRef getAsString(SyncScope S) { switch (S) { + case SyncScope::HIPSingleThread: + return "hip_singlethread"; + case SyncScope::HIPWavefront: + return "hip_wavefront"; + case SyncScope::HIPWorkgroup: + return "hip_workgroup"; + case SyncScope::HIPAgent: + return "hip_agent"; + case SyncScope::HIPSystem: + return "hip_system"; case SyncScope::OpenCLWorkGroup: return "opencl_workgroup"; case SyncScope::OpenCLDevice: @@ -62,7 +77,7 @@ inline llvm::StringRef getAsString(SyncScope S) { } /// Defines the kind of atomic scope models. -enum class AtomicScopeModelKind { None, OpenCL }; +enum class AtomicScopeModelKind { None, OpenCL, HIP }; /// Defines the interface for synch scope model. class AtomicScopeModel { @@ -138,6 +153,58 @@ public: } }; +/// Defines the synch scope model for HIP. +class AtomicScopeHIPModel : public AtomicScopeModel { +public: + /// The enum values match the pre-defined macros + /// __HIP_MEMORY_SCOPE_*, which are used to define memory_scope_* + /// enums in hip-c.h. + enum ID { + SingleThread = 1, + Wavefront = 2, + Workgroup = 3, + Agent = 4, + System = 5, + Last = System + }; + + AtomicScopeHIPModel() {} + + SyncScope map(unsigned S) const override { + switch (static_cast<ID>(S)) { + case SingleThread: + return SyncScope::HIPSingleThread; + case Wavefront: + return SyncScope::HIPWavefront; + case Workgroup: + return SyncScope::HIPWorkgroup; + case Agent: + return SyncScope::HIPAgent; + case System: + return SyncScope::HIPSystem; + } + llvm_unreachable("Invalid language synch scope value"); + } + + bool isValid(unsigned S) const override { + return S >= static_cast<unsigned>(SingleThread) && + S <= static_cast<unsigned>(Last); + } + + ArrayRef<unsigned> getRuntimeValues() const override { + static_assert(Last == System, "Does not include all synch scopes"); + static const unsigned Scopes[] = { + static_cast<unsigned>(SingleThread), static_cast<unsigned>(Wavefront), + static_cast<unsigned>(Workgroup), static_cast<unsigned>(Agent), + static_cast<unsigned>(System)}; + return llvm::makeArrayRef(Scopes); + } + + unsigned getFallBackValue() const override { + return static_cast<unsigned>(System); + } +}; + inline std::unique_ptr<AtomicScopeModel> AtomicScopeModel::create(AtomicScopeModelKind K) { switch (K) { @@ -145,9 +212,11 @@ AtomicScopeModel::create(AtomicScopeModelKind K) { return std::unique_ptr<AtomicScopeModel>{}; case AtomicScopeModelKind::OpenCL: return std::make_unique<AtomicScopeOpenCLModel>(); + case AtomicScopeModelKind::HIP: + return std::make_unique<AtomicScopeHIPModel>(); } llvm_unreachable("Invalid atomic scope model kind"); } -} +} // namespace clang #endif diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9bde64cf49fd..4e6dd2050344 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2504,6 +2504,9 @@ defm rwpi : BoolFOption<"rwpi", NegFlag<SetFalse>>; def fplugin_EQ : Joined<["-"], "fplugin=">, Group<f_Group>, Flags<[NoXarchOption]>, MetaVarName<"<dsopath>">, HelpText<"Load the named plugin (dynamic shared object)">; +def fplugin_arg : Joined<["-"], "fplugin-arg-">, + MetaVarName<"<name>-<arg>">, + HelpText<"Pass <arg> to plugin <name>">; def fpass_plugin_EQ : Joined<["-"], "fpass-plugin=">, Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<dsopath>">, HelpText<"Load pass plugin from a dynamic shared object file (only with new pass manager).">, @@ -2786,10 +2789,11 @@ def fvisibility_ms_compat : Flag<["-"], "fvisibility-ms-compat">, Group<f_Group> def fvisibility_global_new_delete_hidden : Flag<["-"], "fvisibility-global-new-delete-hidden">, Group<f_Group>, HelpText<"Give global C++ operator new and delete declarations hidden visibility">, Flags<[CC1Option]>, MarshallingInfoFlag<LangOpts<"GlobalAllocationFunctionVisibilityHidden">>; -def fnew_infallible : Flag<["-"], "fnew-infallible">, Group<f_Group>, - HelpText<"Treats throwing global C++ operator new as always returning valid memory " - "(annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.">, - Flags<[CC1Option]>, MarshallingInfoFlag<LangOpts<"NewInfallible">>; +defm new_infallible : BoolFOption<"new-infallible", + LangOpts<"NewInfallible">, DefaultFalse, + PosFlag<SetTrue, [], "Enable">, NegFlag<SetFalse, [], "Disable">, + BothFlags<[CC1Option], " treating throwing global C++ operator new as always returning valid memory " + "(annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.">>; defm whole_program_vtables : BoolFOption<"whole-program-vtables", CodeGenOpts<"WholeProgramVTables">, DefaultFalse, PosFlag<SetTrue, [CC1Option], "Enables whole-program vtable optimization. Requires -flto">, @@ -4519,7 +4523,7 @@ def frecord_marker_EQ : Joined<["-"], "frecord-marker=">, Group<gfortran_Group>; defm aggressive_function_elimination : BooleanFFlag<"aggressive-function-elimination">, Group<gfortran_Group>; defm align_commons : BooleanFFlag<"align-commons">, Group<gfortran_Group>; defm all_intrinsics : BooleanFFlag<"all-intrinsics">, Group<gfortran_Group>; -defm automatic : BooleanFFlag<"automatic">, Group<gfortran_Group>; +def fautomatic : Flag<["-"], "fautomatic">; // -fno-automatic is significant defm backtrace : BooleanFFlag<"backtrace">, Group<gfortran_Group>; defm bounds_check : BooleanFFlag<"bounds-check">, Group<gfortran_Group>; defm check_array_temporaries : BooleanFFlag<"check-array-temporaries">, Group<gfortran_Group>; @@ -4616,6 +4620,9 @@ defm backslash : OptInFC1FFlag<"backslash", "Specify that backslash in string in defm xor_operator : OptInFC1FFlag<"xor-operator", "Enable .XOR. as a synonym of .NEQV.">; defm logical_abbreviations : OptInFC1FFlag<"logical-abbreviations", "Enable logical abbreviations">; defm implicit_none : OptInFC1FFlag<"implicit-none", "No implicit typing allowed unless overridden by IMPLICIT statements">; + +def fno_automatic : Flag<["-"], "fno-automatic">, Group<f_Group>, + HelpText<"Implies the SAVE attribute for non-automatic local objects in subprograms unless RECURSIVE">; } def J : JoinedOrSeparate<["-"], "J">, @@ -5059,9 +5066,10 @@ def msmall_data_limit : Separate<["-"], "msmall-data-limit">, def funwind_tables_EQ : Joined<["-"], "funwind-tables=">, HelpText<"Generate unwinding tables for all functions">, MarshallingInfoInt<CodeGenOpts<"UnwindTables">>; -def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">, - HelpText<"Emit complete constructors and destructors as aliases when possible">, - MarshallingInfoFlag<CodeGenOpts<"CXXCtorDtorAliases">>; +defm constructor_aliases : BoolOption<"m", "constructor-aliases", + CodeGenOpts<"CXXCtorDtorAliases">, DefaultFalse, + PosFlag<SetTrue, [], "Enable">, NegFlag<SetFalse, [], "Disable">, + BothFlags<[CC1Option], " emitting complete constructors and destructors as aliases when possible">>; def mlink_bitcode_file : Separate<["-"], "mlink-bitcode-file">, HelpText<"Link the given bitcode file before performing optimizations.">; def mlink_builtin_bitcode : Separate<["-"], "mlink-builtin-bitcode">, @@ -5174,10 +5182,6 @@ defm debug_pass_manager : BoolOption<"f", "debug-pass-manager", CodeGenOpts<"DebugPassManager">, DefaultFalse, PosFlag<SetTrue, [], "Prints debug information for the new pass manager">, NegFlag<SetFalse, [], "Disables debug printing for the new pass manager">>; -def fexperimental_debug_variable_locations : Flag<["-"], - "fexperimental-debug-variable-locations">, - HelpText<"Use experimental new value-tracking variable locations">, - MarshallingInfoFlag<CodeGenOpts<"ValueTrackingVariableLocations">>; def fverify_debuginfo_preserve : Flag<["-"], "fverify-debuginfo-preserve">, HelpText<"Enable Debug Info Metadata preservation testing in " diff --git a/clang/include/clang/Frontend/PrecompiledPreamble.h b/clang/include/clang/Frontend/PrecompiledPreamble.h index bb7fd97fe5df..dacbffef0b12 100644 --- a/clang/include/clang/Frontend/PrecompiledPreamble.h +++ b/clang/include/clang/Frontend/PrecompiledPreamble.h @@ -274,7 +274,7 @@ class PreambleCallbacks { public: virtual ~PreambleCallbacks() = default; - /// Called before FrontendAction::BeginSourceFile. + /// Called before FrontendAction::Execute. /// Can be used to store references to various CompilerInstance fields /// (e.g. SourceManager) that may be interesting to the consumers of other /// callbacks. @@ -291,7 +291,7 @@ public: /// used instead, but having only this method allows a simpler API. virtual void HandleTopLevelDecl(DeclGroupRef DG); /// Creates wrapper class for PPCallbacks so we can also process information - /// about includes that are inside of a preamble + /// about includes that are inside of a preamble. Called after BeforeExecute. virtual std::unique_ptr<PPCallbacks> createPPCallbacks(); /// The returned CommentHandler will be added to the preprocessor if not null. virtual CommentHandler *getCommentHandler(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 43ce5d983217..1a82a9498d1d 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1296,6 +1296,11 @@ public: EK_Decltype, EK_TemplateArgument, EK_Other } ExprContext; + // A context can be nested in both a discarded statement context and + // an immediate function context, so they need to be tracked independently. + bool InDiscardedStatement; + bool InImmediateFunctionContext; + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, @@ -1303,7 +1308,8 @@ public: ExpressionKind ExprContext) : Context(Context), ParentCleanup(ParentCleanup), NumCleanupObjects(NumCleanupObjects), NumTypos(0), - ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext) {} + ManglingContextDecl(ManglingContextDecl), ExprContext(ExprContext), + InDiscardedStatement(false), InImmediateFunctionContext(false) {} bool isUnevaluated() const { return Context == ExpressionEvaluationContext::Unevaluated || @@ -1317,7 +1323,13 @@ public: } bool isImmediateFunctionContext() const { - return Context == ExpressionEvaluationContext::ImmediateFunctionContext; + return Context == ExpressionEvaluationContext::ImmediateFunctionContext || + InImmediateFunctionContext; + } + + bool isDiscardedStatementContext() const { + return Context == ExpressionEvaluationContext::DiscardedStatement || + InDiscardedStatement; } }; @@ -4351,6 +4363,10 @@ public: llvm::Error isValidSectionSpecifier(StringRef Str); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); + bool checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, + const StringLiteral *Literal, + bool &HasDefault, bool &HasCommas, + SmallVectorImpl<StringRef> &Strings); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); @@ -9150,14 +9166,7 @@ public: bool isImmediateFunctionContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); - for (const ExpressionEvaluationContextRecord &context : - llvm::reverse(ExprEvalContexts)) { - if (context.isImmediateFunctionContext()) - return true; - if (context.isUnevaluated()) - return false; - } - return false; + return ExprEvalContexts.back().isImmediateFunctionContext(); } /// RAII class used to determine whether SFINAE has diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index c52da3305f7c..af02fa2e7e87 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -195,15 +195,23 @@ public: llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> openFileForRead(const Twine &Path) override; - void clearIgnoredFiles() { IgnoredFiles.clear(); } - void ignoreFile(StringRef Filename); + /// Disable minimization of the given file. + void disableMinimization(StringRef Filename); + /// Enable minimization of all files. + void enableMinimizationOfAllFiles() { NotToBeMinimized.clear(); } private: - bool shouldIgnoreFile(StringRef Filename); + /// Check whether the file should be minimized. + bool shouldMinimize(StringRef Filename); llvm::ErrorOr<const CachedFileSystemEntry *> getOrCreateFileSystemEntry(const StringRef Filename); + /// Create a cached file system entry based on the initial status result. + CachedFileSystemEntry + createFileSystemEntry(llvm::ErrorOr<llvm::vfs::Status> &&MaybeStatus, + StringRef Filename, bool ShouldMinimize); + /// The global cache shared between worker threads. DependencyScanningFilesystemSharedCache &SharedCache; /// The local cache is used by the worker thread to cache file system queries @@ -214,7 +222,7 @@ private: /// currently active preprocessor. ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; /// The set of files that should not be minimized. - llvm::StringSet<> IgnoredFiles; + llvm::StringSet<> NotToBeMinimized; }; } // end namespace dependencies diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 294cc20f76c5..2d85d72e5b8a 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -11800,6 +11800,15 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) { + std::vector<std::string> Features; + StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); + if (VersionStr.startswith("arch=")) + TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); + else if (VersionStr != "default") + Features.push_back((StringRef{"+"} + VersionStr).str()); + + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else { FeatureMap = Target->getTargetOpts().FeatureMap; } diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index e85feb779190..7fd24e2aa9ad 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1347,6 +1347,42 @@ IsStructurallyEquivalentLambdas(StructuralEquivalenceContext &Context, return true; } +/// Determine if context of a class is equivalent. +static bool IsRecordContextStructurallyEquivalent(RecordDecl *D1, + RecordDecl *D2) { + // The context should be completely equal, including anonymous and inline + // namespaces. + // We compare objects as part of full translation units, not subtrees of + // translation units. + DeclContext *DC1 = D1->getDeclContext()->getNonTransparentContext(); + DeclContext *DC2 = D2->getDeclContext()->getNonTransparentContext(); + while (true) { + // Special case: We allow a struct defined in a function to be equivalent + // with a similar struct defined outside of a function. + if ((DC1->isFunctionOrMethod() && DC2->isTranslationUnit()) || + (DC2->isFunctionOrMethod() && DC1->isTranslationUnit())) + return true; + + if (DC1->getDeclKind() != DC2->getDeclKind()) + return false; + if (DC1->isTranslationUnit()) + break; + if (DC1->isInlineNamespace() != DC2->isInlineNamespace()) + return false; + if (const auto *ND1 = dyn_cast<NamedDecl>(DC1)) { + const auto *ND2 = cast<NamedDecl>(DC2); + if (!DC1->isInlineNamespace() && + !IsStructurallyEquivalent(ND1->getIdentifier(), ND2->getIdentifier())) + return false; + } + + DC1 = DC1->getParent()->getNonTransparentContext(); + DC2 = DC2->getParent()->getNonTransparentContext(); + } + + return true; +} + /// Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { @@ -1386,6 +1422,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } } + // If the records occur in different context (namespace), these should be + // different. This is specially important if the definition of one or both + // records is missing. + if (!IsRecordContextStructurallyEquivalent(D1, D2)) + return false; + // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. const auto *Spec1 = dyn_cast<ClassTemplateSpecializationDecl>(D1); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 5ea091edcf4c..68dfef248f65 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3271,6 +3271,8 @@ MultiVersionKind FunctionDecl::getMultiVersionKind() const { return MultiVersionKind::CPUDispatch; if (hasAttr<CPUSpecificAttr>()) return MultiVersionKind::CPUSpecific; + if (hasAttr<TargetClonesAttr>()) + return MultiVersionKind::TargetClones; return MultiVersionKind::None; } @@ -3286,6 +3288,10 @@ bool FunctionDecl::isTargetMultiVersion() const { return isMultiVersion() && hasAttr<TargetAttr>(); } +bool FunctionDecl::isTargetClonesMultiVersion() const { + return isMultiVersion() && hasAttr<TargetClonesAttr>(); +} + void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDecl(PrevDecl); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 4044404f74ef..064012ba865c 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -964,7 +964,7 @@ SourceLocation Decl::getBodyRBrace() const { return {}; } -bool Decl::AccessDeclContextSanity() const { +bool Decl::AccessDeclContextCheck() const { #ifndef NDEBUG // Suppress this check if any of the following hold: // 1. this is the translation unit (and thus has no parent) @@ -1212,7 +1212,7 @@ bool DeclContext::Encloses(const DeclContext *DC) const { return getPrimaryContext()->Encloses(DC); for (; DC; DC = DC->getParent()) - if (DC->getPrimaryContext() == this) + if (!isa<LinkageSpecDecl>(DC) && DC->getPrimaryContext() == this) return true; return false; } diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 7bd3dce43f4d..d3cb2ff3734c 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -4681,6 +4681,7 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { return 2; case AO__opencl_atomic_load: + case AO__hip_atomic_load: case AO__c11_atomic_store: case AO__c11_atomic_exchange: case AO__atomic_load: @@ -4713,7 +4714,15 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__atomic_fetch_max: return 3; + case AO__hip_atomic_exchange: + case AO__hip_atomic_fetch_add: + case AO__hip_atomic_fetch_and: + case AO__hip_atomic_fetch_or: + case AO__hip_atomic_fetch_xor: + case AO__hip_atomic_fetch_min: + case AO__hip_atomic_fetch_max: case AO__opencl_atomic_store: + case AO__hip_atomic_store: case AO__opencl_atomic_exchange: case AO__opencl_atomic_fetch_add: case AO__opencl_atomic_fetch_sub: @@ -4728,9 +4737,10 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__c11_atomic_compare_exchange_strong: case AO__c11_atomic_compare_exchange_weak: return 5; - + case AO__hip_atomic_compare_exchange_strong: case AO__opencl_atomic_compare_exchange_strong: case AO__opencl_atomic_compare_exchange_weak: + case AO__hip_atomic_compare_exchange_weak: case AO__atomic_compare_exchange: case AO__atomic_compare_exchange_n: return 6; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index fe96db9ca918..99babd58b027 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7483,7 +7483,7 @@ public: const Expr *Source = E->getSourceExpr(); if (!Source) return Error(E); - if (Source == E) { // sanity checking. + if (Source == E) { assert(0 && "OpaqueValueExpr recursively refers to itself"); return Error(E); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 163d4e95386e..79a448a2435c 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/GlobalDecl.h" #include "clang/AST/Mangle.h" #include "clang/AST/VTableBuilder.h" #include "clang/Basic/ABI.h" @@ -39,6 +40,18 @@ using namespace clang; namespace { +// Get GlobalDecl of DeclContext of local entities. +static GlobalDecl getGlobalDeclAsDeclContext(const DeclContext *DC) { + GlobalDecl GD; + if (auto *CD = dyn_cast<CXXConstructorDecl>(DC)) + GD = GlobalDecl(CD, Ctor_Complete); + else if (auto *DD = dyn_cast<CXXDestructorDecl>(DC)) + GD = GlobalDecl(DD, Dtor_Complete); + else + GD = GlobalDecl(cast<FunctionDecl>(DC)); + return GD; +} + struct msvc_hashing_ostream : public llvm::raw_svector_ostream { raw_ostream &OS; llvm::SmallString<64> Buffer; @@ -345,9 +358,9 @@ public: raw_ostream &getStream() const { return Out; } - void mangle(const NamedDecl *D, StringRef Prefix = "?"); - void mangleName(const NamedDecl *ND); - void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); + void mangle(GlobalDecl GD, StringRef Prefix = "?"); + void mangleName(GlobalDecl GD); + void mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD, StringRef Prefix = "$"); @@ -370,7 +383,7 @@ public: const FunctionDecl *D = nullptr, bool ForceThisQuals = false, bool MangleExceptionSpec = true); - void mangleNestedName(const NamedDecl *ND); + void mangleNestedName(GlobalDecl GD); private: bool isStructorDecl(const NamedDecl *ND) const { @@ -384,10 +397,10 @@ private: AddrSpace == LangAS::ptr32_uptr)); } - void mangleUnqualifiedName(const NamedDecl *ND) { - mangleUnqualifiedName(ND, ND->getDeclName()); + void mangleUnqualifiedName(GlobalDecl GD) { + mangleUnqualifiedName(GD, cast<NamedDecl>(GD.getDecl())->getDeclName()); } - void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); + void mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name); void mangleSourceName(StringRef Name); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleCXXDtorType(CXXDtorType T); @@ -396,9 +409,9 @@ private: void manglePointerCVQualifiers(Qualifiers Quals); void manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType); - void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(GlobalDecl GD); void - mangleTemplateInstantiationName(const TemplateDecl *TD, + mangleTemplateInstantiationName(GlobalDecl GD, const TemplateArgumentList &TemplateArgs); void mangleObjCMethodName(const ObjCMethodDecl *MD); @@ -533,7 +546,8 @@ MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) { return true; } -void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { +void MicrosoftCXXNameMangler::mangle(GlobalDecl GD, StringRef Prefix) { + const NamedDecl *D = cast<NamedDecl>(GD.getDecl()); // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. // Therefore it's really important that we don't decorate the // name with leading underscores or leading/trailing at signs. So, by @@ -542,9 +556,9 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { // <mangled-name> ::= ? <name> <type-encoding> Out << Prefix; - mangleName(D); + mangleName(GD); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD)); + mangleFunctionEncoding(GD, Context.shouldMangleDeclName(FD)); else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) mangleVariableEncoding(VD); else if (isa<MSGuidDecl>(D)) @@ -558,8 +572,9 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { llvm_unreachable("Tried to mangle unexpected NamedDecl!"); } -void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD, +void MicrosoftCXXNameMangler::mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); // <type-encoding> ::= <function-class> <function-type> // Since MSVC operates on the type as written and not the canonical type, it @@ -770,13 +785,13 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( mangleCallingConvention(MD->getType()->castAs<FunctionProtoType>()); } -void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { +void MicrosoftCXXNameMangler::mangleName(GlobalDecl GD) { // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ // Always start with the unqualified name. - mangleUnqualifiedName(ND); + mangleUnqualifiedName(GD); - mangleNestedName(ND); + mangleNestedName(GD); // Terminate the whole name with an '@'. Out << '@'; @@ -844,13 +859,14 @@ void MicrosoftCXXNameMangler::mangleBits(llvm::APInt Value) { } } -static const TemplateDecl * -isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { +static GlobalDecl isTemplate(GlobalDecl GD, + const TemplateArgumentList *&TemplateArgs) { + const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); // Check if we have a function template. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { TemplateArgs = FD->getTemplateSpecializationArgs(); - return TD; + return GD.getWithDecl(TD); } } @@ -858,21 +874,22 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { if (const ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(ND)) { TemplateArgs = &Spec->getTemplateArgs(); - return Spec->getSpecializedTemplate(); + return GD.getWithDecl(Spec->getSpecializedTemplate()); } // Check if we have a variable template. if (const VarTemplateSpecializationDecl *Spec = dyn_cast<VarTemplateSpecializationDecl>(ND)) { TemplateArgs = &Spec->getTemplateArgs(); - return Spec->getSpecializedTemplate(); + return GD.getWithDecl(Spec->getSpecializedTemplate()); } - return nullptr; + return GlobalDecl(); } -void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, +void MicrosoftCXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, DeclarationName Name) { + const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); // <unqualified-name> ::= <operator-name> // ::= <ctor-dtor-name> // ::= <source-name> @@ -880,11 +897,11 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; - if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) { // Function templates aren't considered for name back referencing. This // makes sense since function templates aren't likely to occur multiple // times in a symbol. - if (isa<FunctionTemplateDecl>(TD)) { + if (isa<FunctionTemplateDecl>(TD.getDecl())) { mangleTemplateInstantiationName(TD, *TemplateArgs); Out << '@'; return; @@ -945,7 +962,19 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, switch (Name.getNameKind()) { case DeclarationName::Identifier: { if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { - mangleSourceName(II->getName()); + bool IsDeviceStub = + ND && + ((isa<FunctionDecl>(ND) && ND->hasAttr<CUDAGlobalAttr>()) || + (isa<FunctionTemplateDecl>(ND) && + cast<FunctionTemplateDecl>(ND) + ->getTemplatedDecl() + ->hasAttr<CUDAGlobalAttr>())) && + GD.getKernelReferenceKind() == KernelReferenceKind::Stub; + if (IsDeviceStub) + mangleSourceName( + (llvm::Twine("__device_stub__") + II->getName()).str()); + else + mangleSourceName(II->getName()); break; } @@ -1146,7 +1175,8 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // <postfix> ::= <unqualified-name> [<postfix>] // ::= <substitution> [<postfix>] -void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { +void MicrosoftCXXNameMangler::mangleNestedName(GlobalDecl GD) { + const NamedDecl *ND = cast<NamedDecl>(GD.getDecl()); const DeclContext *DC = getEffectiveDeclContext(ND); while (!DC->isTranslationUnit()) { if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) { @@ -1229,7 +1259,7 @@ void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { } else if (isa<NamedDecl>(DC)) { ND = cast<NamedDecl>(DC); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { - mangle(FD, "?"); + mangle(getGlobalDeclAsDeclContext(FD), "?"); break; } else { mangleUnqualifiedName(ND); @@ -1418,7 +1448,7 @@ void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { } void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( - const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { + GlobalDecl GD, const TemplateArgumentList &TemplateArgs) { // <template-name> ::= <unscoped-template-name> <template-args> // ::= <substitution> // Always start with the unqualified name. @@ -1433,8 +1463,8 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( TemplateArgBackReferences.swap(OuterTemplateArgsContext); PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); - mangleUnscopedTemplateName(TD); - mangleTemplateArgs(TD, TemplateArgs); + mangleUnscopedTemplateName(GD); + mangleTemplateArgs(cast<TemplateDecl>(GD.getDecl()), TemplateArgs); // Restore the previous back reference contexts. NameBackReferences.swap(OuterTemplateContext); @@ -1443,11 +1473,10 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( PassObjectSizeArgs.swap(OuterPassObjectSizeArgs); } -void -MicrosoftCXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *TD) { +void MicrosoftCXXNameMangler::mangleUnscopedTemplateName(GlobalDecl GD) { // <unscoped-template-name> ::= ?$ <unqualified-name> Out << "?$"; - mangleUnqualifiedName(TD); + mangleUnqualifiedName(GD); } void MicrosoftCXXNameMangler::mangleIntegerLiteral( @@ -3323,17 +3352,17 @@ void MicrosoftMangleContextImpl::mangleCXXName(GlobalDecl GD, if (auto *CD = dyn_cast<CXXConstructorDecl>(D)) { auto Type = GD.getCtorType(); MicrosoftCXXNameMangler mangler(*this, MHO, CD, Type); - return mangler.mangle(D); + return mangler.mangle(GD); } if (auto *DD = dyn_cast<CXXDestructorDecl>(D)) { auto Type = GD.getDtorType(); MicrosoftCXXNameMangler mangler(*this, MHO, DD, Type); - return mangler.mangle(D); + return mangler.mangle(GD); } MicrosoftCXXNameMangler Mangler(*this, MHO); - return Mangler.mangle(D); + return Mangler.mangle(GD); } void MicrosoftCXXNameMangler::mangleType(const ExtIntType *T, Qualifiers, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index fc267d7006a1..b65a38d1e566 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1691,7 +1691,8 @@ void StmtPrinter::VisitAtomicExpr(AtomicExpr *Node) { PrintExpr(Node->getPtr()); if (Node->getOp() != AtomicExpr::AO__c11_atomic_load && Node->getOp() != AtomicExpr::AO__atomic_load_n && - Node->getOp() != AtomicExpr::AO__opencl_atomic_load) { + Node->getOp() != AtomicExpr::AO__opencl_atomic_load && + Node->getOp() != AtomicExpr::AO__hip_atomic_load) { OS << ", "; PrintExpr(Node->getVal1()); } diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp new file mode 100644 index 000000000000..bb7eb9971068 --- /dev/null +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -0,0 +1,35 @@ +//===- TypeErasedDataflowAnalysis.cpp -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines type-erased base types and functions for building dataflow +// analyses that run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#include <vector> + +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" +#include "llvm/ADT/Optional.h" + +using namespace clang; +using namespace dataflow; + +std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> +runTypeErasedDataflowAnalysis(const CFG &Cfg, + TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv) { + // FIXME: Consider enforcing that `Cfg` meets the requirements that + // are specified in the header. This could be done by remembering + // what options were used to build `Cfg` and asserting on them here. + + // FIXME: Implement work list-based algorithm to compute the fixed + // point of `Analysis::transform` for every basic block in `Cfg`. + return {}; +} diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index f75b8ffcb53d..4d403ae1809d 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -140,8 +140,8 @@ bool AArch64TargetInfo::setABI(const std::string &Name) { bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, BranchProtectionInfo &BPI, StringRef &Err) const { - llvm::AArch64::ParsedBranchProtection PBP; - if (!llvm::AArch64::parseBranchProtection(Spec, PBP, Err)) + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err)) return false; BPI.SignReturnAddr = diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index fc6b01c87fd2..f330780300f2 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -367,6 +367,28 @@ bool ARMTargetInfo::setABI(const std::string &Name) { return false; } +bool ARMTargetInfo::validateBranchProtection(StringRef Spec, + BranchProtectionInfo &BPI, + StringRef &Err) const { + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(Spec, PBP, Err)) + return false; + + BPI.SignReturnAddr = + llvm::StringSwitch<LangOptions::SignReturnAddressScopeKind>(PBP.Scope) + .Case("non-leaf", LangOptions::SignReturnAddressScopeKind::NonLeaf) + .Case("all", LangOptions::SignReturnAddressScopeKind::All) + .Default(LangOptions::SignReturnAddressScopeKind::None); + + // Don't care for the sign key, beyond issuing a warning. + if (PBP.Key == "b_key") + Err = "b-key"; + BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey; + + BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; + return true; +} + // FIXME: This should be based on Arch attributes, not CPU names. bool ARMTargetInfo::initFeatureMap( llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, @@ -874,6 +896,16 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__ARM_BF16_FORMAT_ALTERNATIVE", "1"); } + if (Opts.BranchTargetEnforcement) + Builder.defineMacro("__ARM_FEATURE_BTI_DEFAULT", "1"); + + if (Opts.hasSignReturnAddress()) { + unsigned Value = Opts.isSignReturnAddressWithAKey() ? 1 : 2; + if (Opts.isSignReturnAddressScopeAll()) + Value |= 1 << 2; + Builder.defineMacro("__ARM_FEATURE_PAC_DEFAULT", Twine(Value)); + } + switch (ArchKind) { default: break; diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index d54a049042d6..7d0011d134ea 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -123,6 +123,9 @@ public: StringRef getABI() const override; bool setABI(const std::string &Name) override; + bool validateBranchProtection(StringRef, BranchProtectionInfo &, + StringRef &) const override; + // FIXME: This should be based on Arch attributes, not CPU names. bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp index 7cd4a5190120..53748bf067cd 100644 --- a/clang/lib/Basic/Targets/OSTargets.cpp +++ b/clang/lib/Basic/Targets/OSTargets.cpp @@ -181,8 +181,10 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) { Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { - if (Opts.CPlusPlus20) - Builder.defineMacro("_MSVC_LANG", "201705L"); + if (Opts.CPlusPlus2b) + Builder.defineMacro("_MSVC_LANG", "202004L"); + else if (Opts.CPlusPlus20) + Builder.defineMacro("_MSVC_LANG", "202002L"); else if (Opts.CPlusPlus17) Builder.defineMacro("_MSVC_LANG", "201703L"); else if (Opts.CPlusPlus14) @@ -201,6 +203,14 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) { } Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); + + // Starting with VS 2022 17.1, MSVC predefines the below macro to inform + // users of the execution character set defined at compile time. + // The value given is the Windows Code Page Identifier: + // https://docs.microsoft.com/en-us/windows/win32/intl/code-page-identifiers + // + // Clang currently only supports UTF-8, so we'll use 65001 + Builder.defineMacro("_MSVC_EXECUTION_CHARACTER_SET", "65001"); } void addWindowsDefines(const llvm::Triple &Triple, const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 704b1843dfed..8cf18b6c20f1 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -56,9 +56,14 @@ static const unsigned SPIRDefIsGenMap[] = { 0, // opencl_generic 0, // opencl_global_device 0, // opencl_global_host - 0, // cuda_device - 0, // cuda_constant - 0, // cuda_shared + // 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 + // 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 @@ -74,6 +79,8 @@ class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { protected: BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { + assert((Triple.isSPIR() || Triple.isSPIRV()) && + "Invalid architecture for SPIR or SPIR-V."); assert(getTriple().getOS() == llvm::Triple::UnknownOS && "SPIR(-V) target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && @@ -137,11 +144,16 @@ public: // FIXME: SYCL specification considers unannotated pointers and references // to be pointing to the generic address space. See section 5.9.3 of // SYCL 2020 specification. - // Currently, there is no way of representing SYCL's default address space - // language semantic along with the semantics of embedded C's default - // address space in the same address space map. Hence the map needs to be - // reset to allow mapping to the desired value of 'Default' entry for SYCL. - setAddressSpaceMap(/*DefaultIsGeneric=*/Opts.SYCLIsDevice); + // Currently, there is no way of representing SYCL's and HIP's default + // address space language semantic along with the semantics of embedded C's + // default address space in the same address space map. Hence the map needs + // to be reset to allow mapping to the desired value of 'Default' entry for + // SYCL and HIP. + setAddressSpaceMap( + /*DefaultIsGeneric=*/Opts.SYCLIsDevice || + // The address mapping from HIP language for device code is only defined + // for SPIR-V. + (getTriple().isSPIRV() && Opts.HIP && Opts.CUDAIsDevice)); } void setSupportedOpenCLOpts() override { @@ -159,6 +171,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo { public: SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : BaseSPIRTargetInfo(Triple, Opts) { + assert(Triple.isSPIR() && "Invalid architecture for SPIR."); assert(getTriple().getOS() == llvm::Triple::UnknownOS && "SPIR target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && @@ -177,6 +190,8 @@ class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { public: SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spir && + "Invalid architecture for 32-bit SPIR."); PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = IntPtrType = TargetInfo::SignedInt; @@ -192,6 +207,8 @@ class LLVM_LIBRARY_VISIBILITY SPIR64TargetInfo : public SPIRTargetInfo { public: SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spir64 && + "Invalid architecture for 64-bit SPIR."); PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = IntPtrType = TargetInfo::SignedLong; @@ -207,6 +224,7 @@ class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRTargetInfo { public: SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : BaseSPIRTargetInfo(Triple, Opts) { + assert(Triple.isSPIRV() && "Invalid architecture for SPIR-V."); assert(getTriple().getOS() == llvm::Triple::UnknownOS && "SPIR-V target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && @@ -225,6 +243,8 @@ class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public SPIRVTargetInfo { public: SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRVTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spirv32 && + "Invalid architecture for 32-bit SPIR-V."); PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = IntPtrType = TargetInfo::SignedInt; @@ -240,6 +260,8 @@ class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public SPIRVTargetInfo { public: SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRVTargetInfo(Triple, Opts) { + assert(Triple.getArch() == llvm::Triple::spirv64 && + "Invalid architecture for 64-bit SPIR-V."); PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = IntPtrType = TargetInfo::SignedLong; diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 5e3686893719..5c4bd364b06a 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -239,9 +239,9 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, HasAVX512ER = true; } else if (Feature == "+avx512fp16") { HasAVX512FP16 = true; + HasFloat16 = true; } else if (Feature == "+avx512pf") { HasAVX512PF = true; - HasLegalHalfType = true; } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bitalg") { @@ -369,8 +369,6 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, .Default(NoXOP); XOPLevel = std::max(XOPLevel, XLevel); } - // Turn on _float16 for x86 (feature sse2) - HasFloat16 = SSELevel >= SSE2; // LLVM doesn't have a separate switch for fpmath, so only accept it if it // matches the selected sse level. @@ -384,12 +382,10 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features, SimdDefaultAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; - if (!HasX87) { - if (LongDoubleFormat == &llvm::APFloat::x87DoubleExtended()) - HasLongDouble = false; - if (getTriple().getArch() == llvm::Triple::x86) - HasFPReturn = false; - } + // FIXME: We should allow long double type on 32-bits to match with GCC. + // This requires backend to be able to lower f80 without x87 first. + if (!HasX87 && LongDoubleFormat == &llvm::APFloat::x87DoubleExtended()) + HasLongDouble = false; return true; } diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 648c7b3df8ed..510f3911939c 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1034,8 +1034,9 @@ void EmitAssemblyHelper::EmitAssemblyWithLegacyPassManager( if (!ThinLinkOS) return; } - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", - CodeGenOpts.EnableSplitLTOUnit); + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + CodeGenOpts.EnableSplitLTOUnit); PerModulePasses.add(createWriteThinLTOBitcodePass( *OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr)); } else { @@ -1049,8 +1050,9 @@ void EmitAssemblyHelper::EmitAssemblyWithLegacyPassManager( if (EmitLTOSummary) { if (!TheModule->getModuleFlag("ThinLTO")) TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", - uint32_t(1)); + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + uint32_t(1)); } PerModulePasses.add(createBitcodeWriterPass( @@ -1451,8 +1453,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (!ThinLinkOS) return; } - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", - CodeGenOpts.EnableSplitLTOUnit); + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + CodeGenOpts.EnableSplitLTOUnit); MPM.addPass(ThinLTOBitcodeWriterPass(*OS, ThinLinkOS ? &ThinLinkOS->os() : nullptr)); } else { @@ -1465,8 +1468,9 @@ void EmitAssemblyHelper::RunOptimizationPipeline( if (EmitLTOSummary) { if (!TheModule->getModuleFlag("ThinLTO")) TheModule->addModuleFlag(Module::Error, "ThinLTO", uint32_t(0)); - TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", - uint32_t(1)); + if (!TheModule->getModuleFlag("EnableSplitLTOUnit")) + TheModule->addModuleFlag(Module::Error, "EnableSplitLTOUnit", + uint32_t(1)); } MPM.addPass( BitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists, EmitLTOSummary)); diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index 326ca8d50533..b68e6328acdf 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -524,12 +524,14 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, llvm_unreachable("Already handled!"); case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: emitAtomicCmpXchgFailureSet(CGF, E, false, Dest, Ptr, Val1, Val2, FailureOrder, Size, Order, Scope); return; case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: emitAtomicCmpXchgFailureSet(CGF, E, true, Dest, Ptr, Val1, Val2, FailureOrder, Size, Order, Scope); return; @@ -565,6 +567,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, } case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: { llvm::LoadInst *Load = CGF.Builder.CreateLoad(Ptr); @@ -576,6 +579,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: { llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); @@ -586,6 +590,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, } case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__atomic_exchange: @@ -597,6 +602,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, : llvm::Instruction::Add; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: Op = E->getValueType()->isFloatingType() ? llvm::AtomicRMWInst::FAdd @@ -618,6 +624,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOpMinMax = true; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_min: Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min @@ -628,6 +635,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOpMinMax = true; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_max: Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max @@ -638,6 +646,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::And; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: Op = llvm::AtomicRMWInst::And; @@ -647,6 +656,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Or; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: Op = llvm::AtomicRMWInst::Or; @@ -656,6 +666,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, PostOp = llvm::Instruction::Xor; LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__opencl_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_xor: Op = llvm::AtomicRMWInst::Xor; @@ -838,6 +849,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__atomic_load_n: break; @@ -857,7 +869,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: case AtomicExpr::AO__atomic_compare_exchange_n: case AtomicExpr::AO__atomic_compare_exchange: Val1 = EmitPointerWithAlignment(E->getVal1()); @@ -873,6 +887,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_sub: + case AtomicExpr::AO__hip_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_sub: if (MemTy->isPointerType()) { @@ -901,7 +916,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__opencl_atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: case AtomicExpr::AO__atomic_store_n: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__c11_atomic_fetch_and: @@ -916,8 +933,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__opencl_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_nand: case AtomicExpr::AO__atomic_and_fetch: case AtomicExpr::AO__atomic_or_fetch: @@ -926,7 +946,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__atomic_min_fetch: case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_min: Val1 = EmitValToTemp(*this, E->getVal1()); break; } @@ -968,11 +990,14 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__atomic_fetch_nand: @@ -984,6 +1009,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__opencl_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__atomic_add_fetch: @@ -993,7 +1019,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_min: case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__atomic_min_fetch: // For these, only library calls for certain sizes exist. @@ -1014,10 +1042,15 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__c11_atomic_compare_exchange_strong: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__opencl_atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_store_n: @@ -1079,7 +1112,9 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_compare_exchange_weak: case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: case AtomicExpr::AO__atomic_compare_exchange: case AtomicExpr::AO__atomic_compare_exchange_n: LibCallName = "__atomic_compare_exchange"; @@ -1101,6 +1136,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: LibCallName = "__atomic_exchange"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), MemTy, E->getExprLoc(), TInfo.Width); @@ -1109,6 +1145,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // void __atomic_store_N(T *mem, T val, int order) case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: LibCallName = "__atomic_store"; @@ -1121,6 +1158,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // T __atomic_load_N(T *mem, int order) case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__atomic_load: case AtomicExpr::AO__atomic_load_n: LibCallName = "__atomic_load"; @@ -1133,6 +1171,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_add: LibCallName = "__atomic_fetch_add"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), LoweredMemTy, E->getExprLoc(), TInfo.Width); @@ -1144,6 +1183,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_and: LibCallName = "__atomic_fetch_and"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -1156,6 +1196,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: LibCallName = "__atomic_fetch_or"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -1180,6 +1221,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_xor: case AtomicExpr::AO__opencl_atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_xor: LibCallName = "__atomic_fetch_xor"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), @@ -1190,6 +1232,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: LibCallName = E->getValueType()->isSignedIntegerType() ? "__atomic_fetch_min" @@ -1202,6 +1245,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LLVM_FALLTHROUGH; case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: LibCallName = E->getValueType()->isSignedIntegerType() ? "__atomic_fetch_max" @@ -1291,10 +1335,12 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store || E->getOp() == AtomicExpr::AO__opencl_atomic_store || + E->getOp() == AtomicExpr::AO__hip_atomic_store || E->getOp() == AtomicExpr::AO__atomic_store || E->getOp() == AtomicExpr::AO__atomic_store_n; bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load || E->getOp() == AtomicExpr::AO__opencl_atomic_load || + E->getOp() == AtomicExpr::AO__hip_atomic_load || E->getOp() == AtomicExpr::AO__atomic_load || E->getOp() == AtomicExpr::AO__atomic_load_n; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 849423c8b9ba..5d6df59cc405 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -170,8 +170,9 @@ static Value *EmitNontemporalStore(CodeGenFunction &CGF, const CallExpr *E) { // Convert the type of the pointer to a pointer to the stored type. Val = CGF.EmitToMemory(Val, E->getArg(0)->getType()); + unsigned SrcAddrSpace = Address->getType()->getPointerAddressSpace(); Value *BC = CGF.Builder.CreateBitCast( - Address, llvm::PointerType::getUnqual(Val->getType()), "cast"); + Address, llvm::PointerType::get(Val->getType(), SrcAddrSpace), "cast"); LValue LV = CGF.MakeNaturalAlignAddrLValue(BC, E->getArg(0)->getType()); LV.setNontemporal(true); CGF.EmitStoreOfScalar(Val, LV, false); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 4f14459e4d28..f6853a22cd36 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4510,6 +4510,9 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( Address Replacement(CGF.Builder.CreateLoad(Pair.second), CGF.getContext().getDeclAlign(Pair.first)); Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; }); + if (auto *DI = CGF.getDebugInfo()) + DI->EmitDeclareOfAutoVariable(Pair.first, Pair.second.getPointer(), + CGF.Builder, /*UsePointerValue*/ true); } // Adjust mapping for internal locals by mapping actual memory instead of // a pointer to this memory. diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 59f3e0270571..9ba1a5c25e81 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -710,10 +710,25 @@ void CodeGenModule::Release() { 1); } - if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 || + // Add module metadata for return address signing (ignoring + // non-leaf/all) and stack tagging. These are actually turned on by function + // attributes, but we use module metadata to emit build attributes. This is + // needed for LTO, where the function attributes are inside bitcode + // serialised into a global variable by the time build attributes are + // emitted, so we can't access them. + if (Context.getTargetInfo().hasFeature("ptrauth") && + LangOpts.getSignReturnAddressScope() != + LangOptions::SignReturnAddressScopeKind::None) + getModule().addModuleFlag(llvm::Module::Override, + "sign-return-address-buildattr", 1); + if (LangOpts.Sanitize.has(SanitizerKind::MemTag)) + getModule().addModuleFlag(llvm::Module::Override, + "tag-stack-memory-buildattr", 1); + + if (Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb || + Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 || Arch == llvm::Triple::aarch64_be) { - getModule().addModuleFlag(llvm::Module::Error, - "branch-target-enforcement", + getModule().addModuleFlag(llvm::Module::Error, "branch-target-enforcement", LangOpts.BranchTargetEnforcement); getModule().addModuleFlag(llvm::Module::Error, "sign-return-address", @@ -722,9 +737,11 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Error, "sign-return-address-all", LangOpts.isSignReturnAddressScopeAll()); - getModule().addModuleFlag(llvm::Module::Error, - "sign-return-address-with-bkey", - !LangOpts.isSignReturnAddressWithAKey()); + if (Arch != llvm::Triple::thumb && Arch != llvm::Triple::thumbeb) { + getModule().addModuleFlag(llvm::Module::Error, + "sign-return-address-with-bkey", + !LangOpts.isSignReturnAddressWithAKey()); + } } if (!CodeGenOpts.MemoryProfileOutput.empty()) { @@ -1266,6 +1283,20 @@ static bool isUniqueInternalLinkageDecl(GlobalDecl GD, (CGM.getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage); } +static void AppendTargetClonesMangling(const CodeGenModule &CGM, + const TargetClonesAttr *Attr, + unsigned VersionIndex, + raw_ostream &Out) { + Out << '.'; + StringRef FeatureStr = Attr->getFeatureStr(VersionIndex); + if (FeatureStr.startswith("arch=")) + Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1); + else + Out << FeatureStr; + + Out << '.' << Attr->getMangledIndex(VersionIndex); +} + static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, const NamedDecl *ND, bool OmitMultiVersionMangling = false) { @@ -1319,6 +1350,10 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD, case MultiVersionKind::Target: AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out); break; + case MultiVersionKind::TargetClones: + AppendTargetClonesMangling(CGM, FD->getAttr<TargetClonesAttr>(), + GD.getMultiVersionIndex(), Out); + break; case MultiVersionKind::None: llvm_unreachable("None multiversion type isn't valid here"); } @@ -1983,8 +2018,9 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD, FD = FD ? FD->getMostRecentDecl() : FD; const auto *TD = FD ? FD->getAttr<TargetAttr>() : nullptr; const auto *SD = FD ? FD->getAttr<CPUSpecificAttr>() : nullptr; + const auto *TC = FD ? FD->getAttr<TargetClonesAttr>() : nullptr; bool AddedAttr = false; - if (TD || SD) { + if (TD || SD || TC) { llvm::StringMap<bool> FeatureMap; getContext().getFunctionFeatureMap(FeatureMap, GD); @@ -3226,6 +3262,12 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD, for (unsigned I = 0; I < Spec->cpus_size(); ++I) EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); // Requires multiple emits. + } else if (FD->isTargetClonesMultiVersion()) { + auto *Clone = FD->getAttr<TargetClonesAttr>(); + for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I) + if (Clone->isFirstOfVersion(I)) + EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); + EmitTargetClonesResolver(GD); } else EmitGlobalFunctionDefinition(GD, GV); } @@ -3307,6 +3349,63 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, return llvm::GlobalValue::WeakODRLinkage; } +void CodeGenModule::EmitTargetClonesResolver(GlobalDecl GD) { + const auto *FD = cast<FunctionDecl>(GD.getDecl()); + assert(FD && "Not a FunctionDecl?"); + const auto *TC = FD->getAttr<TargetClonesAttr>(); + assert(TC && "Not a target_clones Function?"); + + QualType CanonTy = Context.getCanonicalType(FD->getType()); + llvm::Type *DeclTy = getTypes().ConvertType(CanonTy); + + if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) { + const CGFunctionInfo &FInfo = getTypes().arrangeCXXMethodDeclaration(CXXFD); + DeclTy = getTypes().GetFunctionType(FInfo); + } + + llvm::Function *ResolverFunc; + if (getTarget().supportsIFunc()) { + auto *IFunc = cast<llvm::GlobalIFunc>( + GetOrCreateMultiVersionResolver(GD, DeclTy, FD)); + ResolverFunc = cast<llvm::Function>(IFunc->getResolver()); + } else + ResolverFunc = + cast<llvm::Function>(GetOrCreateMultiVersionResolver(GD, DeclTy, FD)); + + SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options; + for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size(); + ++VersionIndex) { + if (!TC->isFirstOfVersion(VersionIndex)) + continue; + StringRef Version = TC->getFeatureStr(VersionIndex); + StringRef MangledName = + getMangledName(GD.getWithMultiVersionIndex(VersionIndex)); + llvm::Constant *Func = GetGlobalValue(MangledName); + assert(Func && + "Should have already been created before calling resolver emit"); + + StringRef Architecture; + llvm::SmallVector<StringRef, 1> Feature; + + if (Version.startswith("arch=")) + Architecture = Version.drop_front(sizeof("arch=") - 1); + else if (Version != "default") + Feature.push_back(Version); + + Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature); + } + + const TargetInfo &TI = getTarget(); + std::stable_sort( + Options.begin(), Options.end(), + [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS, + const CodeGenFunction::MultiVersionResolverOption &RHS) { + return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS); + }); + CodeGenFunction CGF(*this); + CGF.EmitMultiVersionResolver(ResolverFunc, Options); +} + void CodeGenModule::emitMultiVersionFunctions() { std::vector<GlobalDecl> MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -3511,8 +3610,25 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver( // Since this is the first time we've created this IFunc, make sure // that we put this multiversioned function into the list to be // replaced later if necessary (target multiversioning only). - if (!FD->isCPUDispatchMultiVersion() && !FD->isCPUSpecificMultiVersion()) + if (FD->isTargetMultiVersion()) MultiVersionFuncs.push_back(GD); + else if (FD->isTargetClonesMultiVersion()) { + // In target_clones multiversioning, make sure we emit this if used. + auto DDI = + DeferredDecls.find(getMangledName(GD.getWithMultiVersionIndex(0))); + if (DDI != DeferredDecls.end()) { + addDeferredDeclToEmit(GD); + DeferredDecls.erase(DDI); + } else { + // Emit the symbol of the 1st variant, so that the deferred decls know we + // need it, otherwise the only global value will be the resolver/ifunc, + // which end up getting broken if we search for them with GetGlobalValue'. + GetOrCreateLLVMFunction( + getMangledName(GD.getWithMultiVersionIndex(0)), DeclTy, FD, + /*ForVTable=*/false, /*DontDefer=*/true, + /*IsThunk=*/false, llvm::AttributeList(), ForDefinition); + } + } if (getTarget().supportsIFunc()) { llvm::Type *ResolverType = llvm::FunctionType::get( diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index fbed22376c82..e1c7f486d334 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1500,6 +1500,7 @@ private: void EmitAliasDefinition(GlobalDecl GD); void emitIFuncDefinition(GlobalDecl GD); void emitCPUDispatchDefinition(GlobalDecl GD); + void EmitTargetClonesResolver(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 302dc653c46e..36e0319c8ab9 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -6364,6 +6364,26 @@ public: const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; + auto *Fn = cast<llvm::Function>(GV); + + if (const auto *TA = FD->getAttr<TargetAttr>()) { + ParsedTargetAttr Attr = TA->parse(); + if (!Attr.BranchProtection.empty()) { + TargetInfo::BranchProtectionInfo BPI; + StringRef DiagMsg; + (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, + BPI, DiagMsg); + + static const char *SignReturnAddrStr[] = {"none", "non-leaf", "all"}; + assert(static_cast<unsigned>(BPI.SignReturnAddr) <= 2 && + "Unexpected SignReturnAddressScopeKind"); + Fn->addFnAttr("sign-return-address", + SignReturnAddrStr[static_cast<int>(BPI.SignReturnAddr)]); + + Fn->addFnAttr("branch-target-enforcement", + BPI.BranchTargetEnforcement ? "true" : "false"); + } + } const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>(); if (!Attr) @@ -6379,8 +6399,6 @@ public: case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break; } - llvm::Function *Fn = cast<llvm::Function>(GV); - Fn->addFnAttr("interrupt", Kind); ARMABIInfo::ABIKind ABI = cast<ARMABIInfo>(getABIInfo()).getABIKind(); @@ -9339,17 +9357,25 @@ AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, llvm::LLVMContext &Ctx) const { std::string Name; switch (Scope) { + case SyncScope::HIPSingleThread: + Name = "singlethread"; + break; + case SyncScope::HIPWavefront: + case SyncScope::OpenCLSubGroup: + Name = "wavefront"; + break; + case SyncScope::HIPWorkgroup: case SyncScope::OpenCLWorkGroup: Name = "workgroup"; break; + case SyncScope::HIPAgent: case SyncScope::OpenCLDevice: Name = "agent"; break; + case SyncScope::HIPSystem: case SyncScope::OpenCLAllSVMDevices: Name = ""; break; - case SyncScope::OpenCLSubGroup: - Name = "wavefront"; } if (Ordering != llvm::AtomicOrdering::SequentiallyConsistent) { diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 8023d03013a1..d501bd026219 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -38,6 +38,7 @@ #include "ToolChains/NaCl.h" #include "ToolChains/NetBSD.h" #include "ToolChains/OpenBSD.h" +#include "ToolChains/PPCFreeBSD.h" #include "ToolChains/PPCLinux.h" #include "ToolChains/PS4CPU.h" #include "ToolChains/RISCVToolchain.h" @@ -5302,7 +5303,11 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, TC = std::make_unique<toolchains::NetBSD>(*this, Target, Args); break; case llvm::Triple::FreeBSD: - TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args); + if (Target.isPPC()) + TC = std::make_unique<toolchains::PPCFreeBSDToolChain>(*this, Target, + Args); + else + TC = std::make_unique<toolchains::FreeBSD>(*this, Target, Args); break; case llvm::Triple::Minix: TC = std::make_unique<toolchains::Minix>(*this, Target, Args); diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 0b60d097b9ca..abc32f22d2a1 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -225,7 +225,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, bool success = true; // Enable NEON by default. Features.push_back("+neon"); - llvm::StringRef WaMArch = ""; + llvm::StringRef WaMArch; if (ForAS) for (const auto *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) @@ -235,7 +235,7 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, // Call getAArch64ArchFeaturesFromMarch only if "-Wa,-march=" or // "-Xassembler -march" is detected. Otherwise it may return false // and causes Clang to error out. - if (WaMArch.size()) + if (!WaMArch.empty()) success = getAArch64ArchFeaturesFromMarch(D, WaMArch, Args, Features); else if ((A = Args.getLastArg(options::OPT_march_EQ))) success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features); @@ -259,8 +259,15 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, success = getAArch64MicroArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); - if (!success) - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + if (!success) { + auto Diag = D.Diag(diag::err_drv_clang_unsupported); + // If "-Wa,-march=" is used, 'WaMArch' will contain the argument's value, + // while 'A' is uninitialized. Only dereference 'A' in the other case. + if (!WaMArch.empty()) + Diag << "-march=" + WaMArch.str(); + else + Diag << A->getAsString(Args); + } if (Args.getLastArg(options::OPT_mgeneral_regs_only)) { Features.push_back("-fp-armv8"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 55518cd7926f..c5aaa067c4f5 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -403,7 +403,7 @@ shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, } /// Adds exception related arguments to the driver command arguments. There's a -/// master flag, -fexceptions and also language specific flags to enable/disable +/// main flag, -fexceptions and also language specific flags to enable/disable /// C++ and Objective-C exceptions. This makes it possible to for example /// disable C++ exceptions but enable Objective-C exceptions. static bool addExceptionArgs(const ArgList &Args, types::ID InputType, @@ -1603,6 +1603,49 @@ void RenderARMABI(const Driver &D, const llvm::Triple &Triple, } } +static void CollectARMPACBTIOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs, bool isAArch64) { + const Arg *A = isAArch64 + ? Args.getLastArg(options::OPT_msign_return_address_EQ, + options::OPT_mbranch_protection_EQ) + : Args.getLastArg(options::OPT_mbranch_protection_EQ); + if (!A) + return; + + StringRef Scope, Key; + bool IndirectBranches; + + if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { + Scope = A->getValue(); + if (!Scope.equals("none") && !Scope.equals("non-leaf") && + !Scope.equals("all")) + D.Diag(diag::err_invalid_branch_protection) + << Scope << A->getAsString(Args); + Key = "a_key"; + IndirectBranches = false; + } else { + StringRef DiagMsg; + llvm::ARM::ParsedBranchProtection PBP; + if (!llvm::ARM::parseBranchProtection(A->getValue(), PBP, DiagMsg)) + D.Diag(diag::err_invalid_branch_protection) + << DiagMsg << A->getAsString(Args); + if (!isAArch64 && PBP.Key == "b_key") + D.Diag(diag::warn_unsupported_branch_protection) + << "b-key" << A->getAsString(Args); + Scope = PBP.Scope; + Key = PBP.Key; + IndirectBranches = PBP.BranchTargetEnforcement; + } + + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address=") + Scope)); + if (!Scope.equals("none")) + CmdArgs.push_back( + Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); + if (IndirectBranches) + CmdArgs.push_back("-mbranch-target-enforce"); +} + void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { RenderARMABI(getToolChain().getDriver(), Triple, Args, CmdArgs); @@ -1644,6 +1687,10 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, CmdArgs.push_back("-mcmse"); AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); + + // Enable/disable return address signing and indirect branch targets. + CollectARMPACBTIOptions(getToolChain().getDriver(), Args, CmdArgs, + false /*isAArch64*/); } void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, @@ -1783,40 +1830,8 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } // Enable/disable return address signing and indirect branch targets. - if (Arg *A = Args.getLastArg(options::OPT_msign_return_address_EQ, - options::OPT_mbranch_protection_EQ)) { - - const Driver &D = getToolChain().getDriver(); - - StringRef Scope, Key; - bool IndirectBranches; - - if (A->getOption().matches(options::OPT_msign_return_address_EQ)) { - Scope = A->getValue(); - if (!Scope.equals("none") && !Scope.equals("non-leaf") && - !Scope.equals("all")) - D.Diag(diag::err_invalid_branch_protection) - << Scope << A->getAsString(Args); - Key = "a_key"; - IndirectBranches = false; - } else { - StringRef Err; - llvm::AArch64::ParsedBranchProtection PBP; - if (!llvm::AArch64::parseBranchProtection(A->getValue(), PBP, Err)) - D.Diag(diag::err_invalid_branch_protection) - << Err << A->getAsString(Args); - Scope = PBP.Scope; - Key = PBP.Key; - IndirectBranches = PBP.BranchTargetEnforcement; - } - - CmdArgs.push_back( - Args.MakeArgString(Twine("-msign-return-address=") + Scope)); - CmdArgs.push_back( - Args.MakeArgString(Twine("-msign-return-address-key=") + Key)); - if (IndirectBranches) - CmdArgs.push_back("-mbranch-target-enforce"); - } + CollectARMPACBTIOptions(getToolChain().getDriver(), Args, CmdArgs, + true /*isAArch64*/); // Handle -msve_vector_bits=<bits> if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { @@ -5821,9 +5836,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var, options::OPT_fno_visibility_inlines_hidden_static_local_var); Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); - Args.AddLastArg(CmdArgs, options::OPT_fnew_infallible); Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); + if (Args.hasFlag(options::OPT_fnew_infallible, + options::OPT_fno_new_infallible, false)) + CmdArgs.push_back("-fnew-infallible"); + if (Args.hasFlag(options::OPT_fno_operator_names, options::OPT_foperator_names, false)) CmdArgs.push_back("-fno-operator-names"); @@ -5886,7 +5904,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // runtime. if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime, options::OPT_fno_openmp_target_new_runtime, - /*Default=*/false)) + /*Default=*/!getToolChain().getTriple().isAMDGCN())) CmdArgs.push_back("-fopenmp-target-new-runtime"); // When in OpenMP offloading mode, enable debugging on the device. @@ -6659,6 +6677,35 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + // Turn -fplugin-arg-pluginname-key=value into + // -plugin-arg-pluginname key=value + // GCC has an actual plugin_argument struct with key/value pairs that it + // passes to its plugins, but we don't, so just pass it on as-is. + // + // The syntax for -fplugin-arg- is ambiguous if both plugin name and + // argument key are allowed to contain dashes. GCC therefore only + // allows dashes in the key. We do the same. + for (const Arg *A : Args.filtered(options::OPT_fplugin_arg)) { + auto ArgValue = StringRef(A->getValue()); + auto FirstDashIndex = ArgValue.find('-'); + StringRef PluginName = ArgValue.substr(0, FirstDashIndex); + StringRef Arg = ArgValue.substr(FirstDashIndex + 1); + + A->claim(); + if (FirstDashIndex == StringRef::npos || Arg.empty()) { + if (PluginName.empty()) { + D.Diag(diag::warn_drv_missing_plugin_name) << A->getAsString(Args); + } else { + D.Diag(diag::warn_drv_missing_plugin_arg) + << PluginName << A->getAsString(Args); + } + continue; + } + + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-arg-") + PluginName)); + CmdArgs.push_back(Args.MakeArgString(Arg)); + } + // Forward -fpass-plugin=name.so to -cc1. for (const Arg *A : Args.filtered(options::OPT_fpass_plugin_EQ)) { CmdArgs.push_back( diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 5397c7a9a0e6..ee573b89bed1 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -745,7 +745,7 @@ void CudaToolChain::addClangTargetOptions( std::string BitcodeSuffix; if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, - options::OPT_fno_openmp_target_new_runtime, false)) + options::OPT_fno_openmp_target_new_runtime, true)) BitcodeSuffix = "new-nvptx-" + GpuArch.str(); else BitcodeSuffix = "nvptx-" + GpuArch.str(); diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index b82c5d7600df..c169e3d45793 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -32,7 +32,8 @@ void Flang::AddFortranDialectOptions(const ArgList &Args, options::OPT_fxor_operator, options::OPT_fno_xor_operator, options::OPT_falternative_parameter_statement, options::OPT_fdefault_real_8, options::OPT_fdefault_integer_8, - options::OPT_fdefault_double_8, options::OPT_flarge_sizes}); + options::OPT_fdefault_double_8, options::OPT_flarge_sizes, + options::OPT_fno_automatic}); } void Flang::AddPreprocessingOptions(const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index dc05f9893465..d08ea282f6df 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -391,7 +391,8 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, } ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { - if (getTriple().getOSMajorVersion() >= 10) + unsigned Major = getTriple().getOSMajorVersion(); + if (Major >= 10 || Major == 0) return ToolChain::CST_Libcxx; return ToolChain::CST_Libstdcxx; } diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 0224383e63a1..198774506e5e 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -421,6 +421,9 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) ArchName += "hf"; + if (Arch == llvm::Triple::ppc && + Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) + ArchName = "powerpc-sf"; return "/lib/ld-musl-" + ArchName + ".so.1"; } diff --git a/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp b/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp new file mode 100644 index 000000000000..8d381c4f1437 --- /dev/null +++ b/clang/lib/Driver/ToolChains/PPCFreeBSD.cpp @@ -0,0 +1,28 @@ +//===-- PPCFreeBSD.cpp - PowerPC ToolChain Implementations ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PPCFreeBSD.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver::toolchains; +using namespace llvm::opt; + +void PPCFreeBSDToolChain::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) && + !DriverArgs.hasArg(options::OPT_nobuiltininc)) { + const Driver &D = getDriver(); + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include", "ppc_wrappers"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + FreeBSD::AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} diff --git a/clang/lib/Driver/ToolChains/PPCFreeBSD.h b/clang/lib/Driver/ToolChains/PPCFreeBSD.h new file mode 100644 index 000000000000..d5d9cf4e83a0 --- /dev/null +++ b/clang/lib/Driver/ToolChains/PPCFreeBSD.h @@ -0,0 +1,33 @@ +//===--- PPCFreeBSD.h - PowerPC ToolChain Implementations -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_FREEBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_FREEBSD_H + +#include "FreeBSD.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY PPCFreeBSDToolChain : public FreeBSD { +public: + PPCFreeBSDToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : FreeBSD(D, Triple, Args) {} + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PPC_FREEBSD_H diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 82f9523f84fb..4bedabaf267c 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -80,6 +80,7 @@ public: return LangOptions::SSPStrong; } + unsigned GetDefaultDwarfVersion() const override { return 4; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::SCE; } diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 1e4f5690ef24..5073f5105d05 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -1984,9 +1984,17 @@ ContinuationIndenter::createBreakableToken(const FormatToken &Current, } else if (Current.is(TT_LineComment) && (Current.Previous == nullptr || Current.Previous->isNot(TT_ImplicitStringLiteral))) { + bool RegularComments = [&]() { + for (const FormatToken *T = &Current; T && T->is(TT_LineComment); + T = T->Next) { + if (!(T->TokenText.startswith("//") || T->TokenText.startswith("#"))) + return false; + } + return true; + }(); if (!Style.ReflowComments || CommentPragmasRegex.match(Current.TokenText.substr(2)) || - switchesFormatting(Current)) + switchesFormatting(Current) || !RegularComments) return nullptr; return std::make_unique<BreakableLineCommentSection>( Current, StartColumn, /*InPPDirective=*/false, Encoding, Style); @@ -2195,11 +2203,10 @@ ContinuationIndenter::breakProtrudingToken(const FormatToken &Current, // When breaking before a tab character, it may be moved by a few columns, // but will still be expanded to the next tab stop, so we don't save any // columns. - if (NewRemainingTokenColumns == RemainingTokenColumns) { + if (NewRemainingTokenColumns >= RemainingTokenColumns) { // FIXME: Do we need to adjust the penalty? break; } - assert(NewRemainingTokenColumns < RemainingTokenColumns); LLVM_DEBUG(llvm::dbgs() << " Breaking at: " << TailOffset + Split.first << ", " << Split.second << "\n"); diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 8ae29c54a762..17de1075aeaa 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2988,9 +2988,8 @@ reformat(const FormatStyle &Style, StringRef Code, // JSON only needs the formatting passing. if (Style.isJson()) { std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); - auto Env = - Environment::make(Code, FileName, Ranges, FirstStartColumn, - NextStartColumn, LastStartColumn); + auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, + NextStartColumn, LastStartColumn); if (!Env) return {}; // Perform the actual formatting pass. @@ -3118,9 +3117,7 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, auto Env = Environment::make(Code, FileName, Ranges); if (!Env) return {}; - return NamespaceEndCommentsFixer(*Env, Style) - .process() - .first; + return NamespaceEndCommentsFixer(*Env, Style).process().first; } tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, @@ -3130,9 +3127,7 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, auto Env = Environment::make(Code, FileName, Ranges); if (!Env) return {}; - return UsingDeclarationsSorter(*Env, Style) - .process() - .first; + return UsingDeclarationsSorter(*Env, Style).process().first; } LangOptions getFormattingLangOpts(const FormatStyle &Style) { diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 06d51dd95f50..1a2858018fde 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -76,6 +76,7 @@ namespace format { TYPE(LineComment) \ TYPE(MacroBlockBegin) \ TYPE(MacroBlockEnd) \ + TYPE(ModulePartitionColon) \ TYPE(NamespaceMacro) \ TYPE(NonNullAssertion) \ TYPE(NullCoalescingEqual) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 8075756cca03..64fbd2d5d45b 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -37,27 +37,40 @@ FormatTokenLexer::FormatTokenLexer( getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); - for (const std::string &ForEachMacro : Style.ForEachMacros) - Macros.insert({&IdentTable.get(ForEachMacro), TT_ForEachMacro}); - for (const std::string &IfMacro : Style.IfMacros) - Macros.insert({&IdentTable.get(IfMacro), TT_IfMacro}); - for (const std::string &AttributeMacro : Style.AttributeMacros) - Macros.insert({&IdentTable.get(AttributeMacro), TT_AttributeMacro}); - for (const std::string &StatementMacro : Style.StatementMacros) - Macros.insert({&IdentTable.get(StatementMacro), TT_StatementMacro}); - for (const std::string &TypenameMacro : Style.TypenameMacros) - Macros.insert({&IdentTable.get(TypenameMacro), TT_TypenameMacro}); - for (const std::string &NamespaceMacro : Style.NamespaceMacros) - Macros.insert({&IdentTable.get(NamespaceMacro), TT_NamespaceMacro}); + for (const std::string &ForEachMacro : Style.ForEachMacros) { + auto Identifier = &IdentTable.get(ForEachMacro); + Macros.insert({Identifier, TT_ForEachMacro}); + } + for (const std::string &IfMacro : Style.IfMacros) { + auto Identifier = &IdentTable.get(IfMacro); + Macros.insert({Identifier, TT_IfMacro}); + } + for (const std::string &AttributeMacro : Style.AttributeMacros) { + auto Identifier = &IdentTable.get(AttributeMacro); + Macros.insert({Identifier, TT_AttributeMacro}); + } + for (const std::string &StatementMacro : Style.StatementMacros) { + auto Identifier = &IdentTable.get(StatementMacro); + Macros.insert({Identifier, TT_StatementMacro}); + } + for (const std::string &TypenameMacro : Style.TypenameMacros) { + auto Identifier = &IdentTable.get(TypenameMacro); + Macros.insert({Identifier, TT_TypenameMacro}); + } + for (const std::string &NamespaceMacro : Style.NamespaceMacros) { + auto Identifier = &IdentTable.get(NamespaceMacro); + Macros.insert({Identifier, TT_NamespaceMacro}); + } for (const std::string &WhitespaceSensitiveMacro : Style.WhitespaceSensitiveMacros) { - Macros.insert( - {&IdentTable.get(WhitespaceSensitiveMacro), TT_UntouchableMacroFunc}); + auto Identifier = &IdentTable.get(WhitespaceSensitiveMacro); + Macros.insert({Identifier, TT_UntouchableMacroFunc}); } for (const std::string &StatementAttributeLikeMacro : - Style.StatementAttributeLikeMacros) - Macros.insert({&IdentTable.get(StatementAttributeLikeMacro), - TT_StatementAttributeLikeMacro}); + Style.StatementAttributeLikeMacros) { + auto Identifier = &IdentTable.get(StatementAttributeLikeMacro); + Macros.insert({Identifier, TT_StatementAttributeLikeMacro}); + } } ArrayRef<FormatToken *> FormatTokenLexer::lex() { @@ -739,6 +752,8 @@ bool FormatTokenLexer::tryMerge_TMacro() { Tokens.pop_back(); Tokens.pop_back(); Tokens.back() = String; + if (FirstInLineIndex >= Tokens.size()) + FirstInLineIndex = Tokens.size() - 1; return true; } diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index 515cfce725a4..77dc0d683e5f 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -553,9 +553,7 @@ tooling::Replacements sortJavaScriptImports(const FormatStyle &Style, auto Env = Environment::make(Code, FileName, Ranges); if (!Env) return {}; - return JavaScriptImportSorter(*Env, Style) - .process() - .first; + return JavaScriptImportSorter(*Env, Style).process().first; } } // end namespace format diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp index a619c6d939e9..d83e837ca134 100644 --- a/clang/lib/Format/TokenAnalyzer.cpp +++ b/clang/lib/Format/TokenAnalyzer.cpp @@ -37,7 +37,7 @@ namespace format { // FIXME: Instead of printing the diagnostic we should store it and have a // better way to return errors through the format APIs. -class FatalDiagnosticConsumer: public DiagnosticConsumer { +class FatalDiagnosticConsumer : public DiagnosticConsumer { public: void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override { @@ -71,7 +71,8 @@ Environment::make(StringRef Code, StringRef FileName, } // Validate that we can get the buffer data without a fatal error. Env->SM.getBufferData(Env->ID); - if (Diags.fatalError()) return nullptr; + if (Diags.fatalError()) + return nullptr; return Env; } @@ -80,8 +81,7 @@ Environment::Environment(StringRef Code, StringRef FileName, unsigned LastStartColumn) : VirtualSM(new SourceManagerForFile(FileName, Code)), SM(VirtualSM->get()), ID(VirtualSM->get().getMainFileID()), FirstStartColumn(FirstStartColumn), - NextStartColumn(NextStartColumn), LastStartColumn(LastStartColumn) { -} + NextStartColumn(NextStartColumn), LastStartColumn(LastStartColumn) {} TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) : Style(Style), Env(Env), diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 3897241cb858..a94d8cdc3b04 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -314,10 +314,11 @@ private: // // void (*FunctionPointer)(void); // void (&FunctionReference)(void); + // void (&&FunctionReference)(void); // void (^ObjCBlock)(void); bool MightBeFunctionType = !Contexts[Contexts.size() - 2].IsExpression; bool ProbablyFunctionType = - CurrentToken->isOneOf(tok::star, tok::amp, tok::caret); + CurrentToken->isOneOf(tok::star, tok::amp, tok::ampamp, tok::caret); bool HasMultipleLines = false; bool HasMultipleParametersOnALine = false; bool MightBeObjCForRangeLoop = @@ -902,9 +903,13 @@ private: break; } } - if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto || - Style.Language == FormatStyle::LK_TextProto) { + if (Line.First->isOneOf(Keywords.kw_module, Keywords.kw_import) || + Line.First->startsSequence(tok::kw_export, Keywords.kw_module) || + Line.First->startsSequence(tok::kw_export, Keywords.kw_import)) { + Tok->setType(TT_ModulePartitionColon); + } else if (Contexts.back().ColonIsDictLiteral || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { Tok->setType(TT_DictLiteral); if (Style.Language == FormatStyle::LK_TextProto) { if (FormatToken *Previous = Tok->getPreviousNonComment()) @@ -946,11 +951,15 @@ private: !Line.First->isOneOf(tok::kw_enum, tok::kw_case, tok::kw_default)) { FormatToken *Prev = Tok->getPreviousNonComment(); + if (!Prev) + break; if (Prev->isOneOf(tok::r_paren, tok::kw_noexcept)) Tok->setType(TT_CtorInitializerColon); else if (Prev->is(tok::kw_try)) { // Member initializer list within function try block. FormatToken *PrevPrev = Prev->getPreviousNonComment(); + if (!PrevPrev) + break; if (PrevPrev && PrevPrev->isOneOf(tok::r_paren, tok::kw_noexcept)) Tok->setType(TT_CtorInitializerColon); } else @@ -995,6 +1004,8 @@ private: if (CurrentToken && CurrentToken->is(Keywords.kw_await)) next(); } + if (Style.isCpp() && CurrentToken && CurrentToken->is(tok::kw_co_await)) + next(); Contexts.back().ColonIsForRangeExpr = true; next(); if (!parseParens()) @@ -1578,6 +1589,8 @@ private: if (TemplateCloser->is(tok::l_paren)) { // No Matching Paren yet so skip to matching paren TemplateCloser = untilMatchingParen(TemplateCloser); + if (!TemplateCloser) + break; } if (TemplateCloser->is(tok::less)) NestingLevel++; @@ -2336,16 +2349,15 @@ void TokenAnnotator::setCommentLineLevels( if (NextNonCommentLine && CommentLine && NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == - AL->First->OriginalColumn) { + AL->First->OriginalColumn) { // Align comments for preprocessor lines with the # in column 0 if // preprocessor lines are not indented. Otherwise, align with the next // line. - AL->Level = - (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && - (NextNonCommentLine->Type == LT_PreprocessorDirective || - NextNonCommentLine->Type == LT_ImportStatement)) - ? 0 - : NextNonCommentLine->Level; + AL->Level = (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && + (NextNonCommentLine->Type == LT_PreprocessorDirective || + NextNonCommentLine->Type == LT_ImportStatement)) + ? 0 + : NextNonCommentLine->Level; } else { NextNonCommentLine = AL->First->isNot(tok::r_brace) ? AL : nullptr; } @@ -2639,8 +2651,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { if (Current->Role) Current->Role->precomputeFormattingInfos(Current); if (Current->MatchingParen && - Current->MatchingParen->opensBlockOrBlockTypeList(Style)) { - assert(IndentLevel > 0); + Current->MatchingParen->opensBlockOrBlockTypeList(Style) && + IndentLevel > 0) { --IndentLevel; } Current->IndentLevel = IndentLevel; @@ -2942,6 +2954,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) return false; + // operator co_await(x) + if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && Left.Previous && + Left.Previous->is(tok::kw_operator)) + return false; + // co_await (x), co_yield (x), co_return (x) + if (Left.isOneOf(tok::kw_co_await, tok::kw_co_yield, tok::kw_co_return) && + Right.isNot(tok::semi)) + return true; // requires clause Concept1<T> && Concept2<T> if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier)) return true; @@ -3159,9 +3179,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.isIf(Line.Type != LT_PreprocessorDirective)) return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); + + // TODO add Operator overloading specific Options to + // SpaceBeforeParensOptions + if (Right.is(TT_OverloadedOperatorLParen)) + return spaceRequiredBeforeParens(Right); // Function declaration or definition - if (Line.MightBeFunctionDecl && (Left.is(TT_FunctionDeclarationName) || - Right.is(TT_OverloadedOperatorLParen))) { + if (Line.MightBeFunctionDecl && (Left.is(TT_FunctionDeclarationName))) { if (Line.mightBeFunctionDefinition()) return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || spaceRequiredBeforeParens(Right); @@ -3238,9 +3262,35 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, auto HasExistingWhitespace = [&Right]() { return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); }; + if (Right.Tok.getIdentifierInfo() && Left.Tok.getIdentifierInfo()) return true; // Never ever merge two identifiers. + + // Leave a space between * and /* to avoid C4138 `comment end` found outside + // of comment. + if (Left.is(tok::star) && Right.is(tok::comment)) + return true; + if (Style.isCpp()) { + // Space between import <iostream>. + // or import .....; + if (Left.is(Keywords.kw_import) && Right.isOneOf(tok::less, tok::ellipsis)) + return true; + // No space between module :. + if (Left.isOneOf(Keywords.kw_module, Keywords.kw_import) && + Right.is(TT_ModulePartitionColon)) + return true; + // No space between import foo:bar but keep a space between import :bar; + if (Left.is(tok::identifier) && Right.is(TT_ModulePartitionColon)) + return false; + // No space between :bar; + if (Left.is(TT_ModulePartitionColon) && + Right.isOneOf(tok::identifier, tok::kw_private)) + return false; + if (Left.is(tok::ellipsis) && Right.is(tok::identifier) && + Line.First->is(Keywords.kw_import)) + return false; + if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); if (Right.is(tok::l_brace) && Right.is(BK_BracedInit) && diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 299536cd806e..d099cfee9dea 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -320,9 +320,9 @@ private: } // Try to merge a control statement block with left brace wrapped if (I[1]->First->is(tok::l_brace) && - (TheLine->First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_for, - tok::kw_switch, tok::kw_try, tok::kw_do, - TT_ForEachMacro) || + (TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, + tok::kw_for, tok::kw_switch, tok::kw_try, + tok::kw_do, TT_ForEachMacro) || (TheLine->First->is(tok::r_brace) && TheLine->First->Next && TheLine->First->Next->isOneOf(tok::kw_else, tok::kw_catch))) && Style.BraceWrapping.AfterControlStatement == @@ -335,7 +335,7 @@ private: ? 1 : 0; } else if (I[1]->First->is(tok::l_brace) && - TheLine->First->isOneOf(tok::kw_if, tok::kw_while, + TheLine->First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_for)) { return (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) @@ -569,7 +569,7 @@ private: // Check that the current line allows merging. This depends on whether we // are in a control flow statements as well as several style flags. - if (Line.First->isOneOf(tok::kw_else, tok::kw_case) || + if (Line.First->is(tok::kw_case) || (Line.First->Next && Line.First->Next->is(tok::kw_else))) return 0; // default: in switch statement @@ -578,20 +578,21 @@ private: if (Tok && Tok->is(tok::colon)) return 0; } - if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try, - tok::kw___try, tok::kw_catch, tok::kw___finally, - tok::kw_for, tok::r_brace, Keywords.kw___except)) { + if (Line.First->isOneOf(tok::kw_if, tok::kw_else, tok::kw_while, tok::kw_do, + tok::kw_try, tok::kw___try, tok::kw_catch, + tok::kw___finally, tok::kw_for, tok::r_brace, + Keywords.kw___except)) { if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return 0; // Don't merge when we can't except the case when // the control statement block is empty if (!Style.AllowShortIfStatementsOnASingleLine && - Line.startsWith(tok::kw_if) && + Line.First->isOneOf(tok::kw_if, tok::kw_else) && !Style.BraceWrapping.AfterControlStatement && !I[1]->First->is(tok::r_brace)) return 0; if (!Style.AllowShortIfStatementsOnASingleLine && - Line.startsWith(tok::kw_if) && + Line.First->isOneOf(tok::kw_if, tok::kw_else) && Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always && I + 2 != E && !I[2]->First->is(tok::r_brace)) @@ -676,7 +677,7 @@ private: // { <-- current Line // baz(); // } - if (Line.First == Line.Last && + if (Line.First == Line.Last && Line.First->isNot(TT_FunctionLBrace) && Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_MultiLine) return 0; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 28d925858f77..5b9fe267aae6 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -28,9 +28,28 @@ namespace format { class FormatTokenSource { public: virtual ~FormatTokenSource() {} + + // Returns the next token in the token stream. virtual FormatToken *getNextToken() = 0; + // Returns the token precedint the token returned by the last call to + // getNextToken() in the token stream, or nullptr if no such token exists. + virtual FormatToken *getPreviousToken() = 0; + + // Returns the token that would be returned by the next call to + // getNextToken(). + virtual FormatToken *peekNextToken() = 0; + + // Returns whether we are at the end of the file. + // This can be different from whether getNextToken() returned an eof token + // when the FormatTokenSource is a view on a part of the token stream. + virtual bool isEOF() = 0; + + // Gets the current position in the token stream, to be used by setPosition(). virtual unsigned getPosition() = 0; + + // Resets the token stream to the state it was in when getPosition() returned + // Position, and return the token at that position in the stream. virtual FormatToken *setPosition(unsigned Position) = 0; }; @@ -108,6 +127,18 @@ public: return Token; } + FormatToken *getPreviousToken() override { + return PreviousTokenSource->getPreviousToken(); + } + + FormatToken *peekNextToken() override { + if (eof()) + return &FakeEOF; + return PreviousTokenSource->peekNextToken(); + } + + bool isEOF() override { return PreviousTokenSource->isEOF(); } + unsigned getPosition() override { return PreviousTokenSource->getPosition(); } FormatToken *setPosition(unsigned Position) override { @@ -199,16 +230,45 @@ public: : Tokens(Tokens), Position(-1) {} FormatToken *getNextToken() override { + if (Position >= 0 && Tokens[Position]->is(tok::eof)) { + LLVM_DEBUG({ + llvm::dbgs() << "Next "; + dbgToken(Position); + }); + return Tokens[Position]; + } ++Position; + LLVM_DEBUG({ + llvm::dbgs() << "Next "; + dbgToken(Position); + }); return Tokens[Position]; } + FormatToken *getPreviousToken() override { + assert(Position > 0); + return Tokens[Position - 1]; + } + + FormatToken *peekNextToken() override { + int Next = Position + 1; + LLVM_DEBUG({ + llvm::dbgs() << "Peeking "; + dbgToken(Next); + }); + return Tokens[Next]; + } + + bool isEOF() override { return Tokens[Position]->is(tok::eof); } + unsigned getPosition() override { + LLVM_DEBUG(llvm::dbgs() << "Getting Position: " << Position << "\n"); assert(Position >= 0); return Position; } FormatToken *setPosition(unsigned P) override { + LLVM_DEBUG(llvm::dbgs() << "Setting Position: " << P << "\n"); Position = P; return Tokens[Position]; } @@ -216,6 +276,13 @@ public: void reset() { Position = -1; } private: + void dbgToken(int Position, llvm::StringRef Indent = "") { + FormatToken *Tok = Tokens[Position]; + llvm::dbgs() << Indent << "[" << Position + << "] Token: " << Tok->Tok.getName() << " / " << Tok->TokenText + << ", Macro: " << !!Tok->MacroCtx << "\n"; + } + ArrayRef<FormatToken *> Tokens; int Position; }; @@ -399,7 +466,7 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { FormatToken *Next; do { Next = Tokens->getNextToken(); - } while (Next && Next->is(tok::comment)); + } while (Next->is(tok::comment)); FormatTok = Tokens->setPosition(StoredPosition); if (Next && Next->isNot(tok::colon)) { // default not followed by ':' is not a case label; treat it like @@ -875,10 +942,7 @@ void UnwrappedLineParser::parsePPEndIf() { parsePPUnknown(); // If the #endif of a potential include guard is the last thing in the file, // then we found an include guard. - unsigned TokenPosition = Tokens->getPosition(); - FormatToken *PeekNext = AllTokens[TokenPosition]; - if (IncludeGuard == IG_Defined && PPBranchLevel == -1 && - PeekNext->is(tok::eof) && + if (IncludeGuard == IG_Defined && PPBranchLevel == -1 && Tokens->isEOF() && Style.IndentPPDirectives != FormatStyle::PPDIS_None) IncludeGuard = IG_Found; } @@ -1050,6 +1114,35 @@ static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, return Tok->Previous && Tok->Previous->isOneOf(tok::l_paren, tok::comma); } +void UnwrappedLineParser::parseModuleImport() { + nextToken(); + while (!eof()) { + if (FormatTok->is(tok::colon)) { + FormatTok->setType(TT_ModulePartitionColon); + } + // Handle import <foo/bar.h> as we would an include statement. + else if (FormatTok->is(tok::less)) { + nextToken(); + while (!FormatTok->isOneOf(tok::semi, tok::greater, tok::eof)) { + // Mark tokens up to the trailing line comments as implicit string + // literals. + if (FormatTok->isNot(tok::comment) && + !FormatTok->TokenText.startswith("//")) + FormatTok->setType(TT_ImplicitStringLiteral); + nextToken(); + } + } + if (FormatTok->is(tok::semi)) { + nextToken(); + break; + } + nextToken(); + } + + addUnwrappedLine(); + return; +} + // readTokenWithJavaScriptASI reads the next token and terminates the current // line if JavaScript Automatic Semicolon Insertion must // happen between the current token and the next token. @@ -1097,7 +1190,6 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { } void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { - assert(!FormatTok->is(tok::l_brace)); if (Style.Language == FormatStyle::LK_TableGen && FormatTok->is(tok::pp_include)) { nextToken(); @@ -1249,6 +1341,10 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { addUnwrappedLine(); return; } + if (Style.isCpp()) { + parseModuleImport(); + return; + } } if (Style.isCpp() && FormatTok->isOneOf(Keywords.kw_signals, Keywords.kw_qsignals, @@ -1402,9 +1498,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { // declaration. if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof)) break; - const unsigned Position = Tokens->getPosition() + 1; - assert(Position < AllTokens.size()); - if (isC78ParameterDecl(FormatTok, AllTokens[Position], Previous)) { + if (isC78ParameterDecl(FormatTok, Tokens->peekNextToken(), Previous)) { addUnwrappedLine(); return; } @@ -1488,7 +1582,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { unsigned StoredPosition = Tokens->getPosition(); FormatToken *Next = Tokens->getNextToken(); FormatTok = Tokens->setPosition(StoredPosition); - if (Next && !mustBeJSIdent(Keywords, Next)) { + if (!mustBeJSIdent(Keywords, Next)) { nextToken(); break; } @@ -2099,8 +2193,8 @@ void UnwrappedLineParser::parseIfThenElse() { parseBlock(); addUnwrappedLine(); } else if (FormatTok->Tok.is(tok::kw_if)) { - FormatToken *Previous = AllTokens[Tokens->getPosition() - 1]; - bool PrecededByComment = Previous->is(tok::comment); + FormatToken *Previous = Tokens->getPreviousToken(); + bool PrecededByComment = Previous && Previous->is(tok::comment); if (PrecededByComment) { addUnwrappedLine(); ++Line->Level; @@ -2305,6 +2399,8 @@ void UnwrappedLineParser::parseForOrWhileLoop() { if (Style.Language == FormatStyle::LK_JavaScript && FormatTok->is(Keywords.kw_await)) nextToken(); + if (Style.isCpp() && FormatTok->is(tok::kw_co_await)) + nextToken(); if (FormatTok->Tok.is(tok::l_paren)) parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { @@ -2653,23 +2749,25 @@ bool UnwrappedLineParser::tryToParseSimpleAttribute() { ScopedTokenPosition AutoPosition(Tokens); FormatToken *Tok = Tokens->getNextToken(); // We already read the first [ check for the second. - if (Tok && !Tok->is(tok::l_square)) { + if (!Tok->is(tok::l_square)) { return false; } // Double check that the attribute is just something // fairly simple. - while (Tok) { + while (Tok->isNot(tok::eof)) { if (Tok->is(tok::r_square)) { break; } Tok = Tokens->getNextToken(); } + if (Tok->is(tok::eof)) + return false; Tok = Tokens->getNextToken(); - if (Tok && !Tok->is(tok::r_square)) { + if (!Tok->is(tok::r_square)) { return false; } Tok = Tokens->getNextToken(); - if (Tok && Tok->is(tok::semi)) { + if (Tok->is(tok::semi)) { return false; } return true; @@ -2682,7 +2780,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { unsigned StoredPosition = Tokens->getPosition(); bool IsSimple = true; FormatToken *Tok = Tokens->getNextToken(); - while (Tok) { + while (!Tok->is(tok::eof)) { if (Tok->is(tok::r_brace)) break; if (Tok->isOneOf(tok::l_brace, tok::semi)) { @@ -3292,6 +3390,20 @@ void UnwrappedLineParser::readToken(int LevelDifference) { do { FormatTok = Tokens->getNextToken(); assert(FormatTok); + while (FormatTok->getType() == TT_ConflictStart || + FormatTok->getType() == TT_ConflictEnd || + FormatTok->getType() == TT_ConflictAlternative) { + if (FormatTok->getType() == TT_ConflictStart) { + conditionalCompilationStart(/*Unreachable=*/false); + } else if (FormatTok->getType() == TT_ConflictAlternative) { + conditionalCompilationAlternative(); + } else if (FormatTok->getType() == TT_ConflictEnd) { + conditionalCompilationEnd(); + } + FormatTok = Tokens->getNextToken(); + FormatTok->MustBreakBefore = true; + } + while (!Line->InPPDirective && FormatTok->Tok.is(tok::hash) && (FormatTok->HasUnescapedNewline || FormatTok->IsFirst)) { distributeComments(Comments, FormatTok); @@ -3313,19 +3425,6 @@ void UnwrappedLineParser::readToken(int LevelDifference) { flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); } - while (FormatTok->getType() == TT_ConflictStart || - FormatTok->getType() == TT_ConflictEnd || - FormatTok->getType() == TT_ConflictAlternative) { - if (FormatTok->getType() == TT_ConflictStart) { - conditionalCompilationStart(/*Unreachable=*/false); - } else if (FormatTok->getType() == TT_ConflictAlternative) { - conditionalCompilationAlternative(); - } else if (FormatTok->getType() == TT_ConflictEnd) { - conditionalCompilationEnd(); - } - FormatTok = Tokens->getNextToken(); - FormatTok->MustBreakBefore = true; - } if (!PPStack.empty() && (PPStack.back().Kind == PP_Unreachable) && !Line->InPPDirective) { diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index bcae0f3ad258..b4c082654597 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -110,6 +110,7 @@ private: void parseCaseLabel(); void parseSwitch(); void parseNamespace(); + void parseModuleImport(); void parseNew(); void parseAccessSpecifier(); bool parseEnum(); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 74136d2f5caa..fae8a1c3fdc6 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -372,8 +372,6 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ContinuedStringLiteral) Changes[i].Spaces += Shift; - assert(Shift >= 0); - Changes[i].StartOfTokenColumn += Shift; if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; @@ -915,7 +913,8 @@ void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, Changes[i].StartOfBlockComment->StartOfTokenColumn - Changes[i].StartOfTokenColumn; } - assert(Shift >= 0); + if (Shift < 0) + continue; Changes[i].Spaces += Shift; if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; @@ -1270,10 +1269,10 @@ WhitespaceManager::linkCells(CellDescriptions &&CellDesc) { void WhitespaceManager::generateChanges() { for (unsigned i = 0, e = Changes.size(); i != e; ++i) { const Change &C = Changes[i]; - if (i > 0) { - assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() != - C.OriginalWhitespaceRange.getBegin() && - "Generating two replacements for the same location"); + if (i > 0 && Changes[i - 1].OriginalWhitespaceRange.getBegin() == + C.OriginalWhitespaceRange.getBegin()) { + // Do not generate two replacements for the same location. + continue; } if (C.CreateReplacement) { std::string ReplacementText = C.PreviousLinePostfix; diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 0ecb024fc6b9..0c153446142e 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -505,6 +505,11 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, if (LangOpts.HIP) { Builder.defineMacro("__HIP__"); Builder.defineMacro("__HIPCC__"); + Builder.defineMacro("__HIP_MEMORY_SCOPE_SINGLETHREAD", "1"); + Builder.defineMacro("__HIP_MEMORY_SCOPE_WAVEFRONT", "2"); + Builder.defineMacro("__HIP_MEMORY_SCOPE_WORKGROUP", "3"); + Builder.defineMacro("__HIP_MEMORY_SCOPE_AGENT", "4"); + Builder.defineMacro("__HIP_MEMORY_SCOPE_SYSTEM", "5"); if (LangOpts.CUDAIsDevice) Builder.defineMacro("__HIP_DEVICE_COMPILE__"); } diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index af82ab3f5558..8aa80a4c96fb 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -412,10 +412,13 @@ llvm::ErrorOr<PrecompiledPreamble> PrecompiledPreamble::Build( std::unique_ptr<PrecompilePreambleAction> Act; Act.reset(new PrecompilePreambleAction( StoreInMemory ? &Storage.asMemory().Data : nullptr, Callbacks)); - Callbacks.BeforeExecute(*Clang); if (!Act->BeginSourceFile(*Clang.get(), Clang->getFrontendOpts().Inputs[0])) return BuildPreambleError::BeginSourceFileFailed; + // Performed after BeginSourceFile to ensure Clang->Preprocessor can be + // referenced in the callback. + Callbacks.BeforeExecute(*Clang); + std::unique_ptr<PPCallbacks> DelegatedPPCallbacks = Callbacks.createPPCallbacks(); if (DelegatedPPCallbacks) diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 626ec4d71ccd..b4487f004715 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -633,7 +633,7 @@ static bool IsHeaderFile(const std::string &Filename) { return false; } - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); + std::string Ext = Filename.substr(DotPos + 1); // C header: .h // C++ header: .hh or .H; return Ext == "h" || Ext == "hh" || Ext == "H"; diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index 0750d36b02ac..b2ecb42c43dd 100644 --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -569,7 +569,7 @@ static bool IsHeaderFile(const std::string &Filename) { return false; } - std::string Ext = std::string(Filename.begin()+DotPos+1, Filename.end()); + std::string Ext = Filename.substr(DotPos + 1); // C header: .h // C++ header: .hh or .H; return Ext == "h" || Ext == "hh" || Ext == "H"; diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h index fb808d7b0a4f..55195b0781fb 100644 --- a/clang/lib/Headers/altivec.h +++ b/clang/lib/Headers/altivec.h @@ -19,6 +19,10 @@ #define __CR6_EQ_REV 1 #define __CR6_LT 2 #define __CR6_LT_REV 3 +#define __CR6_GT 4 +#define __CR6_GT_REV 5 +#define __CR6_SO 6 +#define __CR6_SO_REV 7 /* Constants for vec_test_data_class */ #define __VEC_CLASS_FP_SUBNORMAL_N (1 << 0) @@ -8413,9 +8417,20 @@ static __inline__ vector float __ATTRS_o_ai vec_round(vector float __a) { } #ifdef __VSX__ +#ifdef __XL_COMPAT_ALTIVEC__ +static __inline__ vector double __ATTRS_o_ai vec_rint(vector double __a); +static __inline__ vector double __ATTRS_o_ai vec_round(vector double __a) { + double __fpscr = __builtin_readflm(); + __builtin_setrnd(0); + vector double __rounded = vec_rint(__a); + __builtin_setflm(__fpscr); + return __rounded; +} +#else static __inline__ vector double __ATTRS_o_ai vec_round(vector double __a) { return __builtin_vsx_xvrdpi(__a); } +#endif /* vec_rint */ @@ -19026,6 +19041,51 @@ vec_sra(vector signed __int128 __a, vector unsigned __int128 __b) { #endif /* __SIZEOF_INT128__ */ #endif /* __POWER10_VECTOR__ */ +#ifdef __POWER8_VECTOR__ +#define __bcdadd(__a, __b, __ps) __builtin_ppc_bcdadd((__a), (__b), (__ps)) +#define __bcdsub(__a, __b, __ps) __builtin_ppc_bcdsub((__a), (__b), (__ps)) + +static __inline__ long __bcdadd_ofl(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdadd_p(__CR6_SO, __a, __b); +} + +static __inline__ long __bcdsub_ofl(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_SO, __a, __b); +} + +static __inline__ long __bcd_invalid(vector unsigned char __a) { + return __builtin_ppc_bcdsub_p(__CR6_SO, __a, __a); +} + +static __inline__ long __bcdcmpeq(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_EQ, __a, __b); +} + +static __inline__ long __bcdcmplt(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_LT, __a, __b); +} + +static __inline__ long __bcdcmpgt(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_GT, __a, __b); +} + +static __inline__ long __bcdcmple(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_GT_REV, __a, __b); +} + +static __inline__ long __bcdcmpge(vector unsigned char __a, + vector unsigned char __b) { + return __builtin_ppc_bcdsub_p(__CR6_LT_REV, __a, __b); +} + +#endif // __POWER8_VECTOR__ + #undef __ATTRS_o_ai #endif /* __ALTIVEC_H */ diff --git a/clang/lib/Headers/ppc_wrappers/emmintrin.h b/clang/lib/Headers/ppc_wrappers/emmintrin.h index 4dcb8485e2e9..82a71788b27a 100644 --- a/clang/lib/Headers/ppc_wrappers/emmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/emmintrin.h @@ -35,7 +35,7 @@ #ifndef EMMINTRIN_H_ #define EMMINTRIN_H_ -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) #include <altivec.h> @@ -2319,6 +2319,7 @@ _mm_castsi128_pd(__m128i __A) #else #include_next <emmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* EMMINTRIN_H_ */ diff --git a/clang/lib/Headers/ppc_wrappers/mm_malloc.h b/clang/lib/Headers/ppc_wrappers/mm_malloc.h index 24b14c8e07c0..86cf1a0f7618 100644 --- a/clang/lib/Headers/ppc_wrappers/mm_malloc.h +++ b/clang/lib/Headers/ppc_wrappers/mm_malloc.h @@ -10,7 +10,7 @@ #ifndef _MM_MALLOC_H_INCLUDED #define _MM_MALLOC_H_INCLUDED -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) #include <stdlib.h> diff --git a/clang/lib/Headers/ppc_wrappers/mmintrin.h b/clang/lib/Headers/ppc_wrappers/mmintrin.h index c55c44726f00..54e4ee9f4468 100644 --- a/clang/lib/Headers/ppc_wrappers/mmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/mmintrin.h @@ -35,7 +35,7 @@ #ifndef _MMINTRIN_H_INCLUDED #define _MMINTRIN_H_INCLUDED -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) #include <altivec.h> /* The Intel API is flexible enough that we must allow aliasing with other @@ -1445,6 +1445,7 @@ extern __inline __m64 #else #include_next <mmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* _MMINTRIN_H_INCLUDED */ diff --git a/clang/lib/Headers/ppc_wrappers/pmmintrin.h b/clang/lib/Headers/ppc_wrappers/pmmintrin.h index 6d93383d5412..8d4046bd43f1 100644 --- a/clang/lib/Headers/ppc_wrappers/pmmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/pmmintrin.h @@ -38,7 +38,7 @@ #ifndef PMMINTRIN_H_ #define PMMINTRIN_H_ -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) /* We need definitions from the SSE2 and SSE header files*/ #include <emmintrin.h> @@ -145,6 +145,7 @@ _mm_lddqu_si128 (__m128i const *__P) #else #include_next <pmmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* PMMINTRIN_H_ */ diff --git a/clang/lib/Headers/ppc_wrappers/smmintrin.h b/clang/lib/Headers/ppc_wrappers/smmintrin.h index f41264b27584..674703245a69 100644 --- a/clang/lib/Headers/ppc_wrappers/smmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/smmintrin.h @@ -29,7 +29,7 @@ #ifndef SMMINTRIN_H_ #define SMMINTRIN_H_ -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) #include <altivec.h> #include <tmmintrin.h> @@ -104,6 +104,7 @@ extern __inline __m128i #else #include_next <smmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* _SMMINTRIN_H_ */ diff --git a/clang/lib/Headers/ppc_wrappers/tmmintrin.h b/clang/lib/Headers/ppc_wrappers/tmmintrin.h index b5a935d5e47e..ebef7b8192d7 100644 --- a/clang/lib/Headers/ppc_wrappers/tmmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/tmmintrin.h @@ -25,7 +25,7 @@ #ifndef TMMINTRIN_H_ #define TMMINTRIN_H_ -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) #include <altivec.h> @@ -490,6 +490,7 @@ _mm_mulhrs_pi16 (__m64 __A, __m64 __B) #else #include_next <tmmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* TMMINTRIN_H_ */ diff --git a/clang/lib/Headers/ppc_wrappers/xmmintrin.h b/clang/lib/Headers/ppc_wrappers/xmmintrin.h index 0e45b96769f8..956603d36408 100644 --- a/clang/lib/Headers/ppc_wrappers/xmmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/xmmintrin.h @@ -34,7 +34,7 @@ #ifndef _XMMINTRIN_H_INCLUDED #define _XMMINTRIN_H_INCLUDED -#if defined(__linux__) && defined(__ppc64__) +#if defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) /* Define four value permute mask */ #define _MM_SHUFFLE(w,x,y,z) (((w) << 6) | ((x) << 4) | ((y) << 2) | (z)) @@ -1838,6 +1838,7 @@ do { \ #else #include_next <xmmintrin.h> -#endif /* defined(__linux__) && defined(__ppc64__) */ +#endif /* defined(__ppc64__) && (defined(__linux__) || defined(__FreeBSD__)) \ + */ #endif /* _XMMINTRIN_H_INCLUDED */ diff --git a/clang/lib/Headers/stdatomic.h b/clang/lib/Headers/stdatomic.h index 665551ea69a4..1e47bcb2bacf 100644 --- a/clang/lib/Headers/stdatomic.h +++ b/clang/lib/Headers/stdatomic.h @@ -12,8 +12,12 @@ /* If we're hosted, fall back to the system's stdatomic.h. FreeBSD, for * example, already has a Clang-compatible stdatomic.h header. + * + * Exclude the MSVC path as well as the MSVC header as of the 14.31.30818 + * explicitly disallows `stdatomic.h` in the C mode via an `#error`. Fallback + * to the clang resource header until that is fully supported. */ -#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>) +#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>) && !defined(_MSC_VER) # include_next <stdatomic.h> #else diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index a0871062395e..1bdeccc4cbf5 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -6978,13 +6978,13 @@ void Parser::ParseParameterDeclarationClause( // // We care about case 1) where the declarator type should be known, and // the identifier should be null. - if (!ParmDeclarator.isInvalidType() && !ParmDeclarator.hasName()) { - if (Tok.getIdentifierInfo() && - Tok.getIdentifierInfo()->isKeyword(getLangOpts())) { - Diag(Tok, diag::err_keyword_as_parameter) << PP.getSpelling(Tok); - // Consume the keyword. - ConsumeToken(); - } + if (!ParmDeclarator.isInvalidType() && !ParmDeclarator.hasName() && + Tok.isNot(tok::raw_identifier) && !Tok.isAnnotation() && + Tok.getIdentifierInfo() && + Tok.getIdentifierInfo()->isKeyword(getLangOpts())) { + Diag(Tok, diag::err_keyword_as_parameter) << PP.getSpelling(Tok); + // Consume the keyword. + ConsumeToken(); } // Inform the actions module about the parameter declarator, so it gets // added to the current scope. diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index bb8718671bb0..292ab03e8614 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -2108,6 +2108,9 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { CoawaitLoc = SourceLocation(); } + if (CoawaitLoc.isValid() && getLangOpts().CPlusPlus20) + Diag(CoawaitLoc, diag::warn_deprecated_for_co_await); + // We need to perform most of the semantic analysis for a C++0x for-range // statememt before parsing the body, in order to be able to deduce the type // of an auto-typed loop variable. diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 8544a4fccf4c..b4dcc9759b99 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -464,7 +464,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { // No more CFGElements in the block? if (ri == re) { const Stmt *Term = B.getTerminatorStmt(); - if (Term && isa<CXXTryStmt>(Term)) { + if (Term && (isa<CXXTryStmt>(Term) || isa<ObjCAtTryStmt>(Term))) { HasAbnormalEdge = true; continue; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index a0f6702a5f82..33e2b3b5027d 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5297,6 +5297,7 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: return OrderingCABI != llvm::AtomicOrderingCABI::release && @@ -5304,6 +5305,7 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: return OrderingCABI != llvm::AtomicOrderingCABI::consume && @@ -5380,6 +5382,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, "need to update code for modified C11 atomics"); bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init && Op <= AtomicExpr::AO__opencl_atomic_fetch_max; + bool IsHIP = Op >= AtomicExpr::AO__hip_atomic_load && + Op <= AtomicExpr::AO__hip_atomic_fetch_max; bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init && Op <= AtomicExpr::AO__c11_atomic_fetch_min) || IsOpenCL; @@ -5397,6 +5401,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: + case AtomicExpr::AO__hip_atomic_load: case AtomicExpr::AO__atomic_load_n: Form = Load; break; @@ -5407,11 +5412,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__opencl_atomic_store: + case AtomicExpr::AO__hip_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; break; - + case AtomicExpr::AO__hip_atomic_fetch_add: + case AtomicExpr::AO__hip_atomic_fetch_min: + case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_add: @@ -5426,6 +5434,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__hip_atomic_fetch_and: + case AtomicExpr::AO__hip_atomic_fetch_or: + case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_or: @@ -5452,6 +5463,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, break; case AtomicExpr::AO__c11_atomic_exchange: + case AtomicExpr::AO__hip_atomic_exchange: case AtomicExpr::AO__opencl_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: Form = Xchg; @@ -5463,8 +5475,10 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: + case AtomicExpr::AO__hip_atomic_compare_exchange_weak: Form = C11CmpXchg; break; @@ -5475,7 +5489,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } unsigned AdjustedNumArgs = NumArgs[Form]; - if (IsOpenCL && Op != AtomicExpr::AO__opencl_atomic_init) + if ((IsOpenCL || IsHIP) && Op != AtomicExpr::AO__opencl_atomic_init) ++AdjustedNumArgs; // Check we have the right number of arguments. if (Args.size() < AdjustedNumArgs) { @@ -5532,8 +5546,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { - // GCC does not enforce these rules for GNU atomics, but we do, because if - // we didn't it would be very confusing. FIXME: For whom? How so? + // GCC does not enforce these rules for GNU atomics, but we do to help catch + // trivial type errors. auto IsAllowedValueType = [&](QualType ValType) { if (ValType->isIntegerType()) return true; @@ -5574,8 +5588,9 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) && !AtomTy->isScalarType()) { // For GNU atomics, require a trivially-copyable type. This is not part of - // the GNU atomics specification, but we enforce it, because if we didn't it - // would be very confusing. FIXME: For whom? How so? + // the GNU atomics specification but we enforce it for consistency with + // other atomics which generally all require a trivially-copyable type. This + // is because atomics just copy bits. Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_trivial_copy) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); @@ -5614,7 +5629,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, // arguments are actually passed as pointers. QualType ByValType = ValType; // 'CP' bool IsPassedByAddress = false; - if (!IsC11 && !IsN) { + if (!IsC11 && !IsHIP && !IsN) { ByValType = Ptr->getType(); IsPassedByAddress = true; } @@ -5793,11 +5808,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, if ((Op == AtomicExpr::AO__c11_atomic_load || Op == AtomicExpr::AO__c11_atomic_store || Op == AtomicExpr::AO__opencl_atomic_load || - Op == AtomicExpr::AO__opencl_atomic_store ) && + Op == AtomicExpr::AO__hip_atomic_load || + Op == AtomicExpr::AO__opencl_atomic_store || + Op == AtomicExpr::AO__hip_atomic_store) && Context.AtomicUsesUnsupportedLibcall(AE)) Diag(AE->getBeginLoc(), diag::err_atomic_load_store_uses_lib) << ((Op == AtomicExpr::AO__c11_atomic_load || - Op == AtomicExpr::AO__opencl_atomic_load) + Op == AtomicExpr::AO__opencl_atomic_load || + Op == AtomicExpr::AO__hip_atomic_load) ? 0 : 1); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index af174ac1ca1a..7be71ca49ea2 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -10268,13 +10268,9 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, const FunctionDecl *FD, const FunctionDecl *CausedFD, MultiVersionKind MVType) { - bool IsCPUSpecificCPUDispatchMVType = - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific; - const auto Diagnose = [FD, CausedFD, IsCPUSpecificCPUDispatchMVType]( - Sema &S, const Attr *A) { + const auto Diagnose = [FD, CausedFD, MVType](Sema &S, const Attr *A) { S.Diag(FD->getLocation(), diag::err_multiversion_disallowed_other_attr) - << IsCPUSpecificCPUDispatchMVType << A; + << static_cast<unsigned>(MVType) << A; if (CausedFD) S.Diag(CausedFD->getLocation(), diag::note_multiversioning_caused_here); return true; @@ -10292,6 +10288,10 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, if (MVType != MultiVersionKind::Target) return Diagnose(S, A); break; + case attr::TargetClones: + if (MVType != MultiVersionKind::TargetClones) + return Diagnose(S, A); + break; default: if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType)) return Diagnose(S, A); @@ -10318,6 +10318,7 @@ bool Sema::areMultiversionVariantFunctionsCompatible( DefaultedFuncs = 6, ConstexprFuncs = 7, ConstevalFuncs = 8, + Lambda = 9, }; enum Different { CallingConv = 0, @@ -10445,7 +10446,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, S.PDiag(diag::note_multiversioning_caused_here)), PartialDiagnosticAt(NewFD->getLocation(), S.PDiag(diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType), + << static_cast<unsigned>(MVType)), PartialDiagnosticAt(NewFD->getLocation(), S.PDiag(diag::err_multiversion_diff)), /*TemplatesSupported=*/false, @@ -10574,21 +10575,30 @@ static bool CheckTargetCausesMultiVersioning( return false; } +static bool MultiVersionTypesCompatible(MultiVersionKind Old, + MultiVersionKind New) { + if (Old == New || Old == MultiVersionKind::None || + New == MultiVersionKind::None) + return true; + + return (Old == MultiVersionKind::CPUDispatch && + New == MultiVersionKind::CPUSpecific) || + (Old == MultiVersionKind::CPUSpecific && + New == MultiVersionKind::CPUDispatch); +} + /// Check the validity of a new function declaration being added to an existing /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, MultiVersionKind NewMVType, const TargetAttr *NewTA, const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, - bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious, - LookupResult &Previous) { + const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, + bool &MergeTypeWithPrevious, LookupResult &Previous) { MultiVersionKind OldMVType = OldFD->getMultiVersionKind(); // Disallow mixing of multiversioning types. - if ((OldMVType == MultiVersionKind::Target && - NewMVType != MultiVersionKind::Target) || - (NewMVType == MultiVersionKind::Target && - OldMVType != MultiVersionKind::Target)) { + if (!MultiVersionTypesCompatible(OldMVType, NewMVType)) { S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); S.Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); @@ -10613,7 +10623,12 @@ static bool CheckMultiVersionAdditionalDecl( if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; - if (NewMVType == MultiVersionKind::Target) { + switch (NewMVType) { + case MultiVersionKind::None: + assert(OldMVType == MultiVersionKind::TargetClones && + "Only target_clones can be omitted in subsequent declarations"); + break; + case MultiVersionKind::Target: { const auto *CurTA = CurFD->getAttr<TargetAttr>(); if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) { NewFD->setIsMultiVersion(); @@ -10629,7 +10644,30 @@ static bool CheckMultiVersionAdditionalDecl( NewFD->setInvalidDecl(); return true; } - } else { + break; + } + case MultiVersionKind::TargetClones: { + const auto *CurClones = CurFD->getAttr<TargetClonesAttr>(); + Redeclaration = true; + OldDecl = CurFD; + MergeTypeWithPrevious = true; + NewFD->setIsMultiVersion(); + + if (CurClones && NewClones && + (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || + !std::equal(CurClones->featuresStrs_begin(), + CurClones->featuresStrs_end(), + NewClones->featuresStrs_begin()))) { + S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + + return false; + } + case MultiVersionKind::CPUSpecific: + case MultiVersionKind::CPUDispatch: { const auto *CurCPUSpec = CurFD->getAttr<CPUSpecificAttr>(); const auto *CurCPUDisp = CurFD->getAttr<CPUDispatchAttr>(); // Handle CPUDispatch/CPUSpecific versions. @@ -10684,8 +10722,8 @@ static bool CheckMultiVersionAdditionalDecl( } } } - // If the two decls aren't the same MVType, there is no possible error - // condition. + break; + } } } @@ -10721,7 +10759,6 @@ static bool CheckMultiVersionAdditionalDecl( return false; } - /// Check the validity of a mulitversion function declaration. /// Also sets the multiversion'ness' of the function itself. /// @@ -10735,23 +10772,14 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, const auto *NewTA = NewFD->getAttr<TargetAttr>(); const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>(); const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>(); - - // Mixing Multiversioning types is prohibited. - if ((NewTA && NewCPUDisp) || (NewTA && NewCPUSpec) || - (NewCPUDisp && NewCPUSpec)) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); - NewFD->setInvalidDecl(); - return true; - } - - MultiVersionKind MVType = NewFD->getMultiVersionKind(); + const auto *NewClones = NewFD->getAttr<TargetClonesAttr>(); + MultiVersionKind MVType = NewFD->getMultiVersionKind(); // Main isn't allowed to become a multiversion function, however it IS // permitted to have 'main' be marked with the 'target' optimization hint. if (NewFD->isMain()) { - if ((MVType == MultiVersionKind::Target && NewTA->isDefaultVersion()) || - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific) { + if (MVType != MultiVersionKind::None && + !(MVType == MultiVersionKind::Target && !NewTA->isDefaultVersion())) { S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main); NewFD->setInvalidDecl(); return true; @@ -10774,13 +10802,35 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::None) return false; - if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None) { + // Multiversioned redeclarations aren't allowed to omit the attribute, except + // for target_clones. + if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None && + OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) { S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl) << (OldFD->getMultiVersionKind() != MultiVersionKind::Target); NewFD->setInvalidDecl(); return true; } + if (!OldFD->isMultiVersion()) { + switch (MVType) { + case MultiVersionKind::Target: + return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, + Redeclaration, OldDecl, + MergeTypeWithPrevious, Previous); + case MultiVersionKind::TargetClones: + if (OldFD->isUsed(false)) { + NewFD->setInvalidDecl(); + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + } + OldFD->setIsMultiVersion(); + break; + case MultiVersionKind::CPUDispatch: + case MultiVersionKind::CPUSpecific: + case MultiVersionKind::None: + break; + } + } // Handle the target potentially causes multiversioning case. if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::Target) return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA, @@ -10791,8 +10841,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // appropriate attribute in the current function decl. Resolve that these are // still compatible with previous declarations. return CheckMultiVersionAdditionalDecl( - S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, Redeclaration, - OldDecl, MergeTypeWithPrevious, Previous); + S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, NewClones, + Redeclaration, OldDecl, MergeTypeWithPrevious, Previous); } /// Perform semantic checking of a new function declaration. diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index ef889a36bd55..4df8687aff89 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1965,6 +1965,28 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Ensure we don't combine these with themselves, since that causes some + // confusing behavior. + if (AL.getParsedKind() == ParsedAttr::AT_CPUDispatch) { + if (checkAttrMutualExclusion<CPUSpecificAttr>(S, D, AL)) + return; + + if (const auto *Other = D->getAttr<CPUDispatchAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + } else if (AL.getParsedKind() == ParsedAttr::AT_CPUSpecific) { + if (checkAttrMutualExclusion<CPUDispatchAttr>(S, D, AL)) + return; + + if (const auto *Other = D->getAttr<CPUSpecificAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + } + FunctionDecl *FD = cast<FunctionDecl>(D); if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -3211,54 +3233,57 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, Architecture, Tune }; + enum ThirdParam { Target, TargetClones }; if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "fpmath="; + << Unsupported << None << "fpmath=" << Target; // Diagnose use of tune if target doesn't support it. if (!Context.getTargetInfo().supportsTargetAttributeTune() && AttrStr.contains("tune=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "tune="; + << Unsupported << None << "tune=" << Target; ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); if (!ParsedAttrs.Architecture.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Architecture << ParsedAttrs.Architecture; + << Unknown << Architecture << ParsedAttrs.Architecture << Target; if (!ParsedAttrs.Tune.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unknown << Tune << ParsedAttrs.Tune; + << Unknown << Tune << ParsedAttrs.Tune << Target; if (ParsedAttrs.DuplicateArchitecture) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "arch="; + << Duplicate << None << "arch=" << Target; if (ParsedAttrs.DuplicateTune) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Duplicate << None << "tune="; + << Duplicate << None << "tune=" << Target; for (const auto &Feature : ParsedAttrs.Features) { auto CurFeature = StringRef(Feature).drop_front(); // remove + or -. if (!Context.getTargetInfo().isValidFeatureName(CurFeature)) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << CurFeature; + << Unsupported << None << CurFeature << Target; } TargetInfo::BranchProtectionInfo BPI; - StringRef Error; - if (!ParsedAttrs.BranchProtection.empty() && - !Context.getTargetInfo().validateBranchProtection( - ParsedAttrs.BranchProtection, BPI, Error)) { - if (Error.empty()) + StringRef DiagMsg; + if (ParsedAttrs.BranchProtection.empty()) + return false; + if (!Context.getTargetInfo().validateBranchProtection( + ParsedAttrs.BranchProtection, BPI, DiagMsg)) { + if (DiagMsg.empty()) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) - << Unsupported << None << "branch-protection"; - else - return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) - << Error; + << Unsupported << None << "branch-protection" << Target; + return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) + << DiagMsg; } + if (!DiagMsg.empty()) + Diag(LiteralLoc, diag::warn_unsupported_branch_protection_spec) << DiagMsg; return false; } @@ -3274,6 +3299,107 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(NewAttr); } +bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, + const StringLiteral *Literal, + bool &HasDefault, bool &HasCommas, + SmallVectorImpl<StringRef> &Strings) { + enum FirstParam { Unsupported, Duplicate, Unknown }; + enum SecondParam { None, Architecture, Tune }; + enum ThirdParam { Target, TargetClones }; + HasCommas = HasCommas || Str.contains(','); + // Warn on empty at the beginning of a string. + if (Str.size() == 0) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + std::pair<StringRef, StringRef> Parts = {{}, Str}; + while (!Parts.second.empty()) { + Parts = Parts.second.split(','); + StringRef Cur = Parts.first.trim(); + SourceLocation CurLoc = Literal->getLocationOfByte( + Cur.data() - Literal->getString().data(), getSourceManager(), + getLangOpts(), Context.getTargetInfo()); + + bool DefaultIsDupe = false; + if (Cur.empty()) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + + if (Cur.startswith("arch=")) { + if (!Context.getTargetInfo().isValidCPUName( + Cur.drop_front(sizeof("arch=") - 1))) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << Architecture + << Cur.drop_front(sizeof("arch=") - 1) << TargetClones; + } else if (Cur == "default") { + DefaultIsDupe = HasDefault; + HasDefault = true; + } else if (!Context.getTargetInfo().isValidFeatureName(Cur)) + return Diag(CurLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << Cur << TargetClones; + + if (llvm::find(Strings, Cur) != Strings.end() || DefaultIsDupe) + Diag(CurLoc, diag::warn_target_clone_duplicate_options); + // Note: Add even if there are duplicates, since it changes name mangling. + Strings.push_back(Cur); + } + + if (Str.rtrim().endswith(",")) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "" << TargetClones; + return false; +} + +static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // Ensure we don't combine these with themselves, since that causes some + // confusing behavior. + if (const auto *Other = D->getAttr<TargetClonesAttr>()) { + S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL; + S.Diag(Other->getLocation(), diag::note_conflicting_attribute); + return; + } + if (checkAttrMutualExclusion<TargetClonesAttr>(S, D, AL)) + return; + + SmallVector<StringRef, 2> Strings; + bool HasCommas = false, HasDefault = false; + + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef CurStr; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) || + S.checkTargetClonesAttrString( + LiteralLoc, CurStr, + cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()), + HasDefault, HasCommas, Strings)) + return; + } + + if (HasCommas && AL.getNumArgs() > 1) + S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values); + + if (!HasDefault) { + S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default); + return; + } + + // FIXME: We could probably figure out how to get this to work for lambdas + // someday. + if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) { + if (MD->getParent()->isLambda()) { + S.Diag(D->getLocation(), diag::err_multiversion_doesnt_support) + << static_cast<unsigned>(MultiVersionKind::TargetClones) + << /*Lambda*/ 9; + return; + } + } + + cast<FunctionDecl>(D)->setIsMultiVersion(); + TargetClonesAttr *NewAttr = ::new (S.Context) + TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size()); + D->addAttr(NewAttr); +} + static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) { Expr *E = AL.getArgAsExpr(0); uint32_t VecWidth; @@ -8217,6 +8343,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Target: handleTargetAttr(S, D, AL); break; + case ParsedAttr::AT_TargetClones: + handleTargetClonesAttr(S, D, AL); + break; case ParsedAttr::AT_MinVectorWidth: handleMinVectorWidthAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8592335e20d3..b305d4e5b92f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16566,6 +16566,17 @@ Sema::PushExpressionEvaluationContext( ExpressionEvaluationContextRecord::ExpressionKind ExprContext) { ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, LambdaContextDecl, ExprContext); + + // Discarded statements and immediate contexts nested in other + // discarded statements or immediate context are themselves + // a discarded statement or an immediate context, respectively. + ExprEvalContexts.back().InDiscardedStatement = + ExprEvalContexts[ExprEvalContexts.size() - 2] + .isDiscardedStatementContext(); + ExprEvalContexts.back().InImmediateFunctionContext = + ExprEvalContexts[ExprEvalContexts.size() - 2] + .isImmediateFunctionContext(); + Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); @@ -18965,6 +18976,10 @@ bool Sema::DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts, /// during overload resolution or within sizeof/alignof/typeof/typeid. bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef<const Stmt*> Stmts, const PartialDiagnostic &PD) { + + if (ExprEvalContexts.back().isDiscardedStatementContext()) + return false; + switch (ExprEvalContexts.back().Context) { case ExpressionEvaluationContext::Unevaluated: case ExpressionEvaluationContext::UnevaluatedList: diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 635252584562..d25f329f85e4 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1508,8 +1508,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, } // Only construct objects with object types. - // There doesn't seem to be an explicit rule for this but functions are - // not objects, so they cannot take initializers. + // The standard doesn't explicitly forbid function types here, but that's an + // obvious oversight, as there's no way to dynamically construct a function + // in general. if (Ty->isFunctionType()) return ExprError(Diag(TyBeginLoc, diag::err_init_for_function_type) << Ty << FullRange); diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 3c820829864d..1d90759f2406 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -3563,8 +3563,7 @@ StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, bool HasDeducedReturnType = CurLambda && hasDeducedReturnType(CurLambda->CallOperator); - if (ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement && + if (ExprEvalContexts.back().isDiscardedStatementContext() && (HasDeducedReturnType || CurCap->HasImplicitReturnType)) { if (RetValExp) { ExprResult ER = @@ -3880,8 +3879,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, if (RetVal.isInvalid()) return StmtError(); StmtResult R = BuildReturnStmt(ReturnLoc, RetVal.get()); - if (R.isInvalid() || ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement) + if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext()) return R; if (VarDecl *VD = @@ -3966,8 +3964,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // C++1z: discarded return statements are not considered when deducing a // return type. - if (ExprEvalContexts.back().Context == - ExpressionEvaluationContext::DiscardedStatement && + if (ExprEvalContexts.back().isDiscardedStatementContext() && FnRetType->getContainedAutoType()) { if (RetValExp) { ExprResult ER = diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index bc939d252800..d57bab154b61 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -686,8 +686,8 @@ SwitchNodeBuilder::generateDefaultCaseNode(ProgramStateRef St, assert(Src->succ_rbegin() != Src->succ_rend()); CFGBlock *DefaultBlock = *Src->succ_rbegin(); - // Sanity check for default blocks that are unreachable and not caught - // by earlier stages. + // Basic correctness check for default blocks that are unreachable and not + // caught by earlier stages. if (!DefaultBlock) return nullptr; diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 74403a160b8e..23c67c64f975 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -2191,6 +2191,42 @@ LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State, Constraint->getMaxValue(), true); } +// Simplify the given symbol with the help of the SValBuilder. In +// SValBuilder::symplifySval, we traverse the symbol tree and query the +// constraint values for the sub-trees and if a value is a constant we do the +// constant folding. Compound symbols might collapse to simpler symbol tree +// that is still possible to further simplify. Thus, we do the simplification on +// a new symbol tree until we reach the simplest form, i.e. the fixpoint. +// +// Consider the following symbol `(b * b) * b * b` which has this tree: +// * +// / \ +// * b +// / \ +// / b +// (b * b) +// Now, if the `b * b == 1` new constraint is added then during the first +// iteration we have the following transformations: +// * * +// / \ / \ +// * b --> b b +// / \ +// / b +// 1 +// We need another iteration to reach the final result `1`. +LLVM_NODISCARD +static SVal simplifyUntilFixpoint(SValBuilder &SVB, ProgramStateRef State, + const SymbolRef Sym) { + SVal Val = SVB.makeSymbolVal(Sym); + SVal SimplifiedVal = SVB.simplifySVal(State, Val); + // Do the simplification until we can. + while (SimplifiedVal != Val) { + Val = SimplifiedVal; + SimplifiedVal = SVB.simplifySVal(State, Val); + } + return SimplifiedVal; +} + // Iterate over all symbols and try to simplify them. Once a symbol is // simplified then we check if we can merge the simplified symbol's equivalence // class to this class. This way, we simplify not just the symbols but the @@ -2202,7 +2238,8 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F, SymbolSet ClassMembers = Class.getClassMembers(State); for (const SymbolRef &MemberSym : ClassMembers) { - const SVal SimplifiedMemberVal = simplifyToSVal(State, MemberSym); + const SVal SimplifiedMemberVal = + simplifyUntilFixpoint(SVB, State, MemberSym); const SymbolRef SimplifiedMemberSym = SimplifiedMemberVal.getAsSymbol(); // The symbol is collapsed to a constant, check if the current State is diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 681a1f64eadc..4ca35dd06ae5 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -372,6 +372,15 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, NonLoc InputLHS = lhs; NonLoc InputRHS = rhs; + // Constraints may have changed since the creation of a bound SVal. Check if + // the values can be simplified based on those new constraints. + SVal simplifiedLhs = simplifySVal(state, lhs); + SVal simplifiedRhs = simplifySVal(state, rhs); + if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) + lhs = *simplifiedLhsAsNonLoc; + if (auto simplifiedRhsAsNonLoc = simplifiedRhs.getAs<NonLoc>()) + rhs = *simplifiedRhsAsNonLoc; + // Handle trivial case where left-side and right-side are the same. if (lhs == rhs) switch (op) { @@ -619,16 +628,6 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, } } - // Does the symbolic expression simplify to a constant? - // If so, "fold" the constant by setting 'lhs' to a ConcreteInt - // and try again. - SVal simplifiedLhs = simplifySVal(state, lhs); - if (simplifiedLhs != lhs) - if (auto simplifiedLhsAsNonLoc = simplifiedLhs.getAs<NonLoc>()) { - lhs = *simplifiedLhsAsNonLoc; - continue; - } - // Is the RHS a constant? if (const llvm::APSInt *RHSValue = getKnownValue(state, rhs)) return MakeSymIntVal(Sym, op, *RHSValue, resultTy); @@ -1103,7 +1102,6 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, if (SymbolRef Sym = V.getAsSymbol()) return state->getConstraintManager().getSymVal(state, Sym); - // FIXME: Add support for SymExprs. return nullptr; } @@ -1135,6 +1133,24 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return cache(Sym, SVB.makeSymbolVal(Sym)); } + // Return the known const value for the Sym if available, or return Undef + // otherwise. + SVal getConst(SymbolRef Sym) { + const llvm::APSInt *Const = + State->getConstraintManager().getSymVal(State, Sym); + if (Const) + return Loc::isLocType(Sym->getType()) ? (SVal)SVB.makeIntLocVal(*Const) + : (SVal)SVB.makeIntVal(*Const); + return UndefinedVal(); + } + + SVal getConstOrVisit(SymbolRef Sym) { + const SVal Ret = getConst(Sym); + if (Ret.isUndef()) + return Visit(Sym); + return Ret; + } + public: Simplifier(ProgramStateRef State) : State(State), SVB(State->getStateManager().getSValBuilder()) {} @@ -1148,15 +1164,14 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { return SVB.makeSymbolVal(S); } - // TODO: Support SymbolCast. Support IntSymExpr when/if we actually - // start producing them. + // TODO: Support SymbolCast. SVal VisitSymIntExpr(const SymIntExpr *S) { auto I = Cached.find(S); if (I != Cached.end()) return I->second; - SVal LHS = Visit(S->getLHS()); + SVal LHS = getConstOrVisit(S->getLHS()); if (isUnchanged(S->getLHS(), LHS)) return skip(S); @@ -1183,6 +1198,20 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); } + SVal VisitIntSymExpr(const IntSymExpr *S) { + auto I = Cached.find(S); + if (I != Cached.end()) + return I->second; + + SVal RHS = getConstOrVisit(S->getRHS()); + if (isUnchanged(S->getRHS(), RHS)) + return skip(S); + + SVal LHS = SVB.makeIntVal(S->getLHS()); + return cache( + S, SVB.evalBinOp(State, S->getOpcode(), LHS, RHS, S->getType())); + } + SVal VisitSymSymExpr(const SymSymExpr *S) { auto I = Cached.find(S); if (I != Cached.end()) @@ -1196,8 +1225,9 @@ SVal SimpleSValBuilder::simplifySVal(ProgramStateRef State, SVal V) { Loc::isLocType(S->getRHS()->getType())) return skip(S); - SVal LHS = Visit(S->getLHS()); - SVal RHS = Visit(S->getRHS()); + SVal LHS = getConstOrVisit(S->getLHS()); + SVal RHS = getConstOrVisit(S->getRHS()); + if (isUnchanged(S->getLHS(), LHS) && isUnchanged(S->getRHS(), RHS)) return skip(S); diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 31de49033ac2..f692c68045ee 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -591,16 +591,24 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { // - Main source file: run both path-sensitive and non-path-sensitive checks. // - Header files: run non-path-sensitive checks only. // - System headers: don't run any checks. - SourceManager &SM = Ctx->getSourceManager(); - const Stmt *Body = D->getBody(); - SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation(); - SL = SM.getExpansionLoc(SL); - - if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) { - if (SL.isInvalid() || SM.isInSystemHeader(SL)) - return AM_None; + if (Opts->AnalyzeAll) + return Mode; + + const SourceManager &SM = Ctx->getSourceManager(); + + const SourceLocation Loc = [&SM](Decl *D) -> SourceLocation { + const Stmt *Body = D->getBody(); + SourceLocation SL = Body ? Body->getBeginLoc() : D->getLocation(); + return SM.getExpansionLoc(SL); + }(D); + + // Ignore system headers. + if (Loc.isInvalid() || SM.isInSystemHeader(Loc)) + return AM_None; + + // Disable path sensitive analysis in user-headers. + if (!Mgr->isInCodeFile(Loc)) return Mode & ~AM_Path; - } return Mode; } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp index 40e8bd2b8776..f7c711690d7e 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -129,7 +129,7 @@ DependencyScanningFilesystemSharedCache::get(StringRef Key, bool Minimized) { /// /// This is kinda hacky, it would be better if we knew what kind of file Clang /// was expecting instead. -static bool shouldMinimize(StringRef Filename) { +static bool shouldMinimizeBasedOnExtension(StringRef Filename) { StringRef Ext = llvm::sys::path::extension(Filename); if (Ext.empty()) return true; // C++ standard library @@ -147,26 +147,43 @@ static bool shouldCacheStatFailures(StringRef Filename) { StringRef Ext = llvm::sys::path::extension(Filename); if (Ext.empty()) return false; // This may be the module cache directory. - return shouldMinimize(Filename); // Only cache stat failures on source files. + // Only cache stat failures on source files. + return shouldMinimizeBasedOnExtension(Filename); } -void DependencyScanningWorkerFilesystem::ignoreFile(StringRef RawFilename) { +void DependencyScanningWorkerFilesystem::disableMinimization( + StringRef RawFilename) { llvm::SmallString<256> Filename; llvm::sys::path::native(RawFilename, Filename); - IgnoredFiles.insert(Filename); + NotToBeMinimized.insert(Filename); } -bool DependencyScanningWorkerFilesystem::shouldIgnoreFile( - StringRef RawFilename) { +bool DependencyScanningWorkerFilesystem::shouldMinimize(StringRef RawFilename) { + if (!shouldMinimizeBasedOnExtension(RawFilename)) + return false; + llvm::SmallString<256> Filename; llvm::sys::path::native(RawFilename, Filename); - return IgnoredFiles.contains(Filename); + return !NotToBeMinimized.contains(Filename); +} + +CachedFileSystemEntry DependencyScanningWorkerFilesystem::createFileSystemEntry( + llvm::ErrorOr<llvm::vfs::Status> &&MaybeStatus, StringRef Filename, + bool ShouldMinimize) { + if (!MaybeStatus) + return CachedFileSystemEntry(MaybeStatus.getError()); + + if (MaybeStatus->isDirectory()) + return CachedFileSystemEntry::createDirectoryEntry(std::move(*MaybeStatus)); + + return CachedFileSystemEntry::createFileEntry(Filename, getUnderlyingFS(), + ShouldMinimize); } llvm::ErrorOr<const CachedFileSystemEntry *> DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( const StringRef Filename) { - bool ShouldMinimize = !shouldIgnoreFile(Filename) && shouldMinimize(Filename); + bool ShouldMinimize = shouldMinimize(Filename); if (const auto *Entry = Cache.getCachedEntry(Filename, ShouldMinimize)) return Entry; @@ -182,23 +199,15 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( CachedFileSystemEntry &CacheEntry = SharedCacheEntry.Value; if (!CacheEntry.isValid()) { - llvm::vfs::FileSystem &FS = getUnderlyingFS(); - auto MaybeStatus = FS.status(Filename); - if (!MaybeStatus) { - if (!shouldCacheStatFailures(Filename)) - // HACK: We need to always restat non source files if the stat fails. - // This is because Clang first looks up the module cache and module - // files before building them, and then looks for them again. If we - // cache the stat failure, it won't see them the second time. - return MaybeStatus.getError(); - else - CacheEntry = CachedFileSystemEntry(MaybeStatus.getError()); - } else if (MaybeStatus->isDirectory()) - CacheEntry = CachedFileSystemEntry::createDirectoryEntry( - std::move(*MaybeStatus)); - else - CacheEntry = CachedFileSystemEntry::createFileEntry(Filename, FS, - ShouldMinimize); + auto MaybeStatus = getUnderlyingFS().status(Filename); + if (!MaybeStatus && !shouldCacheStatFailures(Filename)) + // HACK: We need to always restat non source files if the stat fails. + // This is because Clang first looks up the module cache and module + // files before building them, and then looks for them again. If we + // cache the stat failure, it won't see them the second time. + return MaybeStatus.getError(); + CacheEntry = createFileSystemEntry(std::move(MaybeStatus), Filename, + ShouldMinimize); } Result = &CacheEntry; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 7fdc49271791..70bb6c5caf87 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -193,20 +193,19 @@ public: // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - DepFS->clearIgnoredFiles(); - // Ignore any files that contributed to prebuilt modules. The implicit - // build validates the modules by comparing the reported sizes of their - // inputs to the current state of the filesystem. Minimization would throw - // this mechanism off. + DepFS->enableMinimizationOfAllFiles(); + // Don't minimize any files that contributed to prebuilt modules. The + // implicit build validates the modules by comparing the reported sizes of + // their inputs to the current state of the filesystem. Minimization would + // throw this mechanism off. for (const auto &File : PrebuiltModulesInputFiles) - DepFS->ignoreFile(File.getKey()); - // Add any filenames that were explicity passed in the build settings and - // that might be opened, as we want to ensure we don't run source - // minimization on them. + DepFS->disableMinimization(File.getKey()); + // Don't minimize any files that were explicitly passed in the build + // settings and that might be opened. for (const auto &E : ScanInstance.getHeaderSearchOpts().UserEntries) - DepFS->ignoreFile(E.Path); + DepFS->disableMinimization(E.Path); for (const auto &F : ScanInstance.getHeaderSearchOpts().VFSOverlayFiles) - DepFS->ignoreFile(F); + DepFS->disableMinimization(F); // Support for virtual file system overlays on top of the caching // filesystem. diff --git a/clang/utils/TableGen/ASTTableGen.cpp b/clang/utils/TableGen/ASTTableGen.cpp index 3f6da40964e0..6aa8b28a942f 100644 --- a/clang/utils/TableGen/ASTTableGen.cpp +++ b/clang/utils/TableGen/ASTTableGen.cpp @@ -107,7 +107,7 @@ static void visitASTNodeRecursive(ASTNode node, ASTNode base, static void visitHierarchy(RecordKeeper &records, StringRef nodeClassName, ASTNodeHierarchyVisitor<ASTNode> visit) { - // Check for the node class, just as a sanity check. + // Check for the node class, just as a basic correctness check. if (!records.getClass(nodeClassName)) { PrintFatalError(Twine("cannot find definition for node class ") + nodeClassName); |