Merge llvm-project main llvmorg-15-init-16436-g18a6ab5b8d1f
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvmorg-15-init-16436-g18a6ab5b8d1f. PR: 265425 MFC after: 2 weeks
This commit is contained in:
commit
753f127f3a
@ -76,7 +76,7 @@ class CommonEntityInfo {
|
||||
}
|
||||
|
||||
void setSwiftPrivate(llvm::Optional<bool> Private) {
|
||||
SwiftPrivateSpecified = Private.hasValue();
|
||||
SwiftPrivateSpecified = Private.has_value();
|
||||
SwiftPrivate = Private ? *Private : 0;
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,7 @@ class TemplateDecl;
|
||||
class TemplateParameterList;
|
||||
class TemplateTemplateParmDecl;
|
||||
class TemplateTypeParmDecl;
|
||||
class TypeConstraint;
|
||||
class UnresolvedSetIterator;
|
||||
class UsingShadowDecl;
|
||||
class VarTemplateDecl;
|
||||
@ -260,7 +261,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
mutable llvm::FoldingSet<DeducedTemplateSpecializationType>
|
||||
DeducedTemplateSpecializationTypes;
|
||||
mutable llvm::FoldingSet<AtomicType> AtomicTypes;
|
||||
llvm::FoldingSet<AttributedType> AttributedTypes;
|
||||
mutable llvm::FoldingSet<AttributedType> AttributedTypes;
|
||||
mutable llvm::FoldingSet<PipeType> PipeTypes;
|
||||
mutable llvm::FoldingSet<BitIntType> BitIntTypes;
|
||||
mutable llvm::FoldingSet<DependentBitIntType> DependentBitIntTypes;
|
||||
@ -1306,11 +1307,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
/// declaration of a function with an exception specification is permitted
|
||||
/// and preserved. Other type sugar (for instance, typedefs) is not.
|
||||
QualType getFunctionTypeWithExceptionSpec(
|
||||
QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI);
|
||||
QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const;
|
||||
|
||||
/// Determine whether two function types are the same, ignoring
|
||||
/// exception specifications in cases where they're part of the type.
|
||||
bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U);
|
||||
bool hasSameFunctionTypeIgnoringExceptionSpec(QualType T, QualType U) const;
|
||||
|
||||
/// Change the exception specification on a function once it is
|
||||
/// delay-parsed, instantiated, or computed.
|
||||
@ -1597,9 +1598,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
|
||||
QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const;
|
||||
|
||||
QualType getAttributedType(attr::Kind attrKind,
|
||||
QualType modifiedType,
|
||||
QualType equivalentType);
|
||||
QualType getAttributedType(attr::Kind attrKind, QualType modifiedType,
|
||||
QualType equivalentType) const;
|
||||
|
||||
QualType getBTFTagAttributedType(const BTFTypeTagAttr *BTFAttr,
|
||||
QualType Wrapped);
|
||||
@ -2654,25 +2654,33 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
||||
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
|
||||
|
||||
/// Determine whether the two declarations refer to the same entity.
|
||||
///
|
||||
/// FIXME: isSameEntity is not const due to its implementation calls
|
||||
/// hasSameFunctionTypeIgnoringExceptionSpec which may alter this.
|
||||
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y);
|
||||
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
|
||||
|
||||
/// Determine whether two template parameter lists are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
///
|
||||
/// FIXME: isSameTemplateParameterList is not const since it calls
|
||||
/// isSameTemplateParameter.
|
||||
bool isSameTemplateParameterList(const TemplateParameterList *X,
|
||||
const TemplateParameterList *Y);
|
||||
const TemplateParameterList *Y) const;
|
||||
|
||||
/// Determine whether two template parameters are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y) const;
|
||||
|
||||
/// Determine whether two 'requires' expressions are similar enough that they
|
||||
/// may be used in re-declarations.
|
||||
///
|
||||
/// FIXME: isSameTemplateParameterList is not const since it calls
|
||||
/// isSameEntity.
|
||||
bool isSameTemplateParameter(const NamedDecl *X, const NamedDecl *Y);
|
||||
/// Use of 'requires' isn't mandatory, works with constraints expressed in
|
||||
/// other ways too.
|
||||
bool isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const;
|
||||
|
||||
/// Determine whether two type contraint are similar enough that they could
|
||||
/// used in declarations of the same template.
|
||||
bool isSameTypeConstraint(const TypeConstraint *XTC,
|
||||
const TypeConstraint *YTC) const;
|
||||
|
||||
/// Determine whether two default template arguments are similar enough
|
||||
/// that they may be used in declarations of the same template.
|
||||
bool isSameDefaultTemplateArgument(const NamedDecl *X,
|
||||
const NamedDecl *Y) const;
|
||||
|
||||
/// Retrieve the "canonical" template argument.
|
||||
///
|
||||
|
@ -19,7 +19,6 @@
|
||||
namespace clang {
|
||||
|
||||
class ASTImportError : public llvm::ErrorInfo<ASTImportError> {
|
||||
|
||||
public:
|
||||
/// \brief Kind of error when importing an AST component.
|
||||
enum ErrorKind {
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define LLVM_CLANG_AST_DECLTEMPLATE_H
|
||||
|
||||
#include "clang/AST/ASTConcept.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
@ -373,11 +374,19 @@ class DefaultArgStorage {
|
||||
|
||||
/// Set that the default argument was inherited from another parameter.
|
||||
void setInherited(const ASTContext &C, ParmDecl *InheritedFrom) {
|
||||
assert(!isInherited() && "default argument already inherited");
|
||||
InheritedFrom = getParmOwningDefaultArg(InheritedFrom);
|
||||
if (!isSet())
|
||||
ValueOrInherited = InheritedFrom;
|
||||
else
|
||||
else if (auto *D = ValueOrInherited.template dyn_cast<ParmDecl *>()) {
|
||||
assert(C.isSameDefaultTemplateArgument(D, InheritedFrom));
|
||||
ValueOrInherited =
|
||||
new (allocateDefaultArgStorageChain(C)) Chain{InheritedFrom, get()};
|
||||
} else if (auto *Inherited =
|
||||
ValueOrInherited.template dyn_cast<Chain *>()) {
|
||||
assert(C.isSameDefaultTemplateArgument(Inherited->PrevDeclWithDefaultArg,
|
||||
InheritedFrom));
|
||||
Inherited->PrevDeclWithDefaultArg = InheritedFrom;
|
||||
} else
|
||||
ValueOrInherited = new (allocateDefaultArgStorageChain(C))
|
||||
Chain{InheritedFrom, ValueOrInherited.template get<ArgType>()};
|
||||
}
|
||||
|
@ -520,15 +520,15 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
||||
if (hasBase) {
|
||||
if (isTypeInfo) {
|
||||
base = APValue::LValueBase::getTypeInfo(
|
||||
TypeInfoLValue(typeInfo.getValue().getTypePtr()), type.getValue());
|
||||
TypeInfoLValue(typeInfo.value().getTypePtr()), type.value());
|
||||
elemTy = base.getTypeInfoType();
|
||||
} else if (isExpr) {
|
||||
base = APValue::LValueBase(cast<Expr>(stmt.getValue()),
|
||||
callIndex.getValue(), version.getValue());
|
||||
base = APValue::LValueBase(cast<Expr>(stmt.value()),
|
||||
callIndex.value(), version.value());
|
||||
elemTy = base.get<const Expr *>()->getType();
|
||||
} else {
|
||||
base = APValue::LValueBase(cast<ValueDecl>(decl.getValue()),
|
||||
callIndex.getValue(), version.getValue());
|
||||
base = APValue::LValueBase(cast<ValueDecl>(decl.value()),
|
||||
callIndex.value(), version.value());
|
||||
elemTy = base.get<const ValueDecl *>()->getType();
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +155,7 @@ class DataflowAnalysisContext {
|
||||
|
||||
/// Returns a pointer value that represents a null pointer. Calls with
|
||||
/// `PointeeType` that are canonically equivalent will return the same result.
|
||||
/// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
|
||||
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
|
||||
|
||||
/// Returns a symbolic boolean value that models a boolean literal equal to
|
||||
@ -251,6 +252,17 @@ class DataflowAnalysisContext {
|
||||
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
|
||||
|
||||
private:
|
||||
struct NullableQualTypeDenseMapInfo : private llvm::DenseMapInfo<QualType> {
|
||||
static QualType getEmptyKey() {
|
||||
// Allow a NULL `QualType` by using a different value as the empty key.
|
||||
return QualType::getFromOpaquePtr(reinterpret_cast<Type *>(1));
|
||||
}
|
||||
|
||||
using DenseMapInfo::getHashValue;
|
||||
using DenseMapInfo::getTombstoneKey;
|
||||
using DenseMapInfo::isEqual;
|
||||
};
|
||||
|
||||
/// Adds all constraints of the flow condition identified by `Token` and all
|
||||
/// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
|
||||
/// to track tokens of flow conditions that were already visited by recursive
|
||||
@ -259,17 +271,18 @@ class DataflowAnalysisContext {
|
||||
AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints,
|
||||
llvm::DenseSet<AtomicBoolValue *> &VisitedTokens);
|
||||
|
||||
/// Returns the result of satisfiability checking on `Constraints`.
|
||||
/// Possible return values are:
|
||||
/// - `Satisfiable`: There exists a satisfying assignment for `Constraints`.
|
||||
/// - `Unsatisfiable`: There is no satisfying assignment for `Constraints`.
|
||||
/// - `TimedOut`: The solver gives up on finding a satisfying assignment.
|
||||
/// Returns the outcome of satisfiability checking on `Constraints`.
|
||||
/// Possible outcomes are:
|
||||
/// - `Satisfiable`: A satisfying assignment exists and is returned.
|
||||
/// - `Unsatisfiable`: A satisfying assignment does not exist.
|
||||
/// - `TimedOut`: The search for a satisfying assignment was not completed.
|
||||
Solver::Result querySolver(llvm::DenseSet<BoolValue *> Constraints);
|
||||
|
||||
/// Returns true if the solver is able to prove that there is no satisfying
|
||||
/// assignment for `Constraints`
|
||||
bool isUnsatisfiable(llvm::DenseSet<BoolValue *> Constraints) {
|
||||
return querySolver(std::move(Constraints)) == Solver::Result::Unsatisfiable;
|
||||
return querySolver(std::move(Constraints)).getStatus() ==
|
||||
Solver::Result::Status::Unsatisfiable;
|
||||
}
|
||||
|
||||
/// Returns a boolean value as a result of substituting `Val` and its sub
|
||||
@ -311,7 +324,8 @@ class DataflowAnalysisContext {
|
||||
// required to initialize the `PointeeLoc` field in `PointerValue`. Consider
|
||||
// creating a type-independent `NullPointerValue` without a `PointeeLoc`
|
||||
// field.
|
||||
llvm::DenseMap<QualType, PointerValue *> NullPointerVals;
|
||||
llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo>
|
||||
NullPointerVals;
|
||||
|
||||
AtomicBoolValue &TrueVal;
|
||||
AtomicBoolValue &FalseVal;
|
||||
|
@ -0,0 +1,63 @@
|
||||
//===-- DebugSupport.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 functions which generate more readable forms of data
|
||||
// structures used in the dataflow analyses, for debugging purposes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/Solver.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
/// Returns a string representation for the boolean value `B`.
|
||||
///
|
||||
/// Atomic booleans appearing in the boolean value `B` are assigned to labels
|
||||
/// either specified in `AtomNames` or created by default rules as B0, B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const BoolValue &B,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
|
||||
/// Returns a string representation for `Constraints` - a collection of boolean
|
||||
/// formulas and the `Result` of satisfiability checking.
|
||||
///
|
||||
/// Atomic booleans appearing in `Constraints` and `Result` are assigned to
|
||||
/// labels either specified in `AtomNames` or created by default rules as B0,
|
||||
/// B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const std::vector<BoolValue *> &Constraints, const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
inline std::string debugString(
|
||||
const llvm::DenseSet<BoolValue *> &Constraints,
|
||||
const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}) {
|
||||
std::vector<BoolValue *> ConstraintsVec(Constraints.begin(),
|
||||
Constraints.end());
|
||||
return debugString(ConstraintsVec, Result, std::move(AtomNames));
|
||||
}
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DEBUGSUPPORT_H_
|
@ -15,7 +15,9 @@
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
@ -23,17 +25,58 @@ namespace dataflow {
|
||||
/// An interface for a SAT solver that can be used by dataflow analyses.
|
||||
class Solver {
|
||||
public:
|
||||
enum class Result {
|
||||
/// Indicates that there exists a satisfying assignment for a boolean
|
||||
struct Result {
|
||||
enum class Status {
|
||||
/// Indicates that there exists a satisfying assignment for a boolean
|
||||
/// formula.
|
||||
Satisfiable,
|
||||
|
||||
/// Indicates that there is no satisfying assignment for a boolean
|
||||
/// formula.
|
||||
Unsatisfiable,
|
||||
|
||||
/// Indicates that the solver gave up trying to find a satisfying
|
||||
/// assignment for a boolean formula.
|
||||
TimedOut,
|
||||
};
|
||||
|
||||
/// A boolean value is set to true or false in a truth assignment.
|
||||
enum class Assignment : uint8_t { AssignedFalse = 0, AssignedTrue = 1 };
|
||||
|
||||
/// Constructs a result indicating that the queried boolean formula is
|
||||
/// satisfiable. The result will hold a solution found by the solver.
|
||||
static Result
|
||||
Satisfiable(llvm::DenseMap<AtomicBoolValue *, Assignment> Solution) {
|
||||
return Result(Status::Satisfiable, std::move(Solution));
|
||||
}
|
||||
|
||||
/// Constructs a result indicating that the queried boolean formula is
|
||||
/// unsatisfiable.
|
||||
static Result Unsatisfiable() { return Result(Status::Unsatisfiable, {}); }
|
||||
|
||||
/// Constructs a result indicating that satisfiability checking on the
|
||||
/// queried boolean formula was not completed.
|
||||
static Result TimedOut() { return Result(Status::TimedOut, {}); }
|
||||
|
||||
/// Returns the status of satisfiability checking on the queried boolean
|
||||
/// formula.
|
||||
Satisfiable,
|
||||
Status getStatus() const { return SATCheckStatus; }
|
||||
|
||||
/// Indicates that there is no satisfying assignment for a boolean formula.
|
||||
Unsatisfiable,
|
||||
/// Returns a truth assignment to boolean values that satisfies the queried
|
||||
/// boolean formula if available. Otherwise, an empty optional is returned.
|
||||
llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>>
|
||||
getSolution() const {
|
||||
return Solution;
|
||||
}
|
||||
|
||||
/// Indicates that the solver gave up trying to find a satisfying assignment
|
||||
/// for a boolean formula.
|
||||
TimedOut,
|
||||
private:
|
||||
Result(
|
||||
enum Status SATCheckStatus,
|
||||
llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution)
|
||||
: SATCheckStatus(SATCheckStatus), Solution(std::move(Solution)) {}
|
||||
|
||||
Status SATCheckStatus;
|
||||
llvm::Optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution;
|
||||
};
|
||||
|
||||
virtual ~Solver() = default;
|
||||
@ -44,9 +87,6 @@ class Solver {
|
||||
/// Requirements:
|
||||
///
|
||||
/// All elements in `Vals` must not be null.
|
||||
///
|
||||
/// FIXME: Consider returning a model in case the conjunction of `Vals` is
|
||||
/// satisfiable so that it can be used to generate warning messages.
|
||||
virtual Result solve(llvm::DenseSet<BoolValue *> Vals) = 0;
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace clang {
|
||||
template <typename... IdentifierInfos>
|
||||
static inline Selector getKeywordSelector(ASTContext &Ctx,
|
||||
IdentifierInfos *... IIs) {
|
||||
static_assert(sizeof...(IdentifierInfos),
|
||||
static_assert(sizeof...(IdentifierInfos) > 0,
|
||||
"keyword selectors must have at least one argument");
|
||||
SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
|
||||
|
||||
|
@ -26,8 +26,8 @@ inline llvm::VersionTuple alignedAllocMinVersion(llvm::Triple::OSType OS) {
|
||||
default:
|
||||
break;
|
||||
case llvm::Triple::Darwin:
|
||||
case llvm::Triple::MacOSX: // Earliest supporting version is 10.14.
|
||||
return llvm::VersionTuple(10U, 14U);
|
||||
case llvm::Triple::MacOSX: // Earliest supporting version is 10.13.
|
||||
return llvm::VersionTuple(10U, 13U);
|
||||
case llvm::Triple::IOS:
|
||||
case llvm::Triple::TvOS: // Earliest supporting version is 11.0.0.
|
||||
return llvm::VersionTuple(11U);
|
||||
|
@ -4036,3 +4036,14 @@ def NoRandomizeLayout : InheritableAttr {
|
||||
let LangOpts = [COnly];
|
||||
}
|
||||
def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>;
|
||||
|
||||
def FunctionReturnThunks : InheritableAttr,
|
||||
TargetSpecificAttr<TargetAnyX86> {
|
||||
let Spellings = [GCC<"function_return">];
|
||||
let Args = [EnumArgument<"ThunkType", "Kind",
|
||||
["keep", "thunk-extern"],
|
||||
["Keep", "Extern"]
|
||||
>];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [FunctionReturnThunksDocs];
|
||||
}
|
||||
|
@ -3088,8 +3088,8 @@ def FormatDocs : Documentation {
|
||||
let Content = [{
|
||||
|
||||
Clang supports the ``format`` attribute, which indicates that the function
|
||||
accepts a ``printf`` or ``scanf``-like format string and corresponding
|
||||
arguments or a ``va_list`` that contains these arguments.
|
||||
accepts (among other possibilities) a ``printf`` or ``scanf``-like format string
|
||||
and corresponding arguments or a ``va_list`` that contains these arguments.
|
||||
|
||||
Please see `GCC documentation about format attribute
|
||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ to find details
|
||||
@ -3143,6 +3143,27 @@ Clang implements two kinds of checks with this attribute.
|
||||
In this case Clang does not warn because the format string ``s`` and
|
||||
the corresponding arguments are annotated. If the arguments are
|
||||
incorrect, the caller of ``foo`` will receive a warning.
|
||||
|
||||
As an extension to GCC's behavior, Clang accepts the ``format`` attribute on
|
||||
non-variadic functions. Clang checks non-variadic format functions for the same
|
||||
classes of issues that can be found on variadic functions, as controlled by the
|
||||
same warning flags, except that the types of formatted arguments is forced by
|
||||
the function signature. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
__attribute__((__format__(__printf__, 1, 2)))
|
||||
void fmt(const char *s, const char *a, int b);
|
||||
|
||||
void bar(void) {
|
||||
fmt("%s %i", "hello", 123); // OK
|
||||
fmt("%i %g", "hello", 123); // warning: arguments don't match format
|
||||
extern const char *fmt;
|
||||
fmt(fmt, "hello", 123); // warning: format string is not a string literal
|
||||
}
|
||||
|
||||
Using the ``format`` attribute on a non-variadic function emits a GCC
|
||||
compatibility diagnostic.
|
||||
}];
|
||||
}
|
||||
|
||||
@ -6585,6 +6606,28 @@ evaluate to NULL.
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
def FunctionReturnThunksDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The attribute ``function_return`` can replace return instructions with jumps to
|
||||
target-specific symbols. This attribute supports 2 possible values,
|
||||
corresponding to the values supported by the ``-mfunction-return=`` command
|
||||
line flag:
|
||||
|
||||
* ``__attribute__((function_return("keep")))`` to disable related transforms.
|
||||
This is useful for undoing global setting from ``-mfunction-return=`` locally
|
||||
for individual functions.
|
||||
* ``__attribute__((function_return("thunk-extern")))`` to replace returns with
|
||||
jumps, while NOT emitting the thunk.
|
||||
|
||||
The values ``thunk`` and ``thunk-inline`` from GCC are not supported.
|
||||
|
||||
The symbol used for ``thunk-extern`` is target specific:
|
||||
* X86: ``__x86_return_thunk``
|
||||
|
||||
As such, this function attribute is currently only supported on X86 targets.
|
||||
}];
|
||||
}
|
||||
|
@ -825,6 +825,7 @@ BUILTIN(__rdtsc, "UOi", "")
|
||||
BUILTIN(__builtin_ia32_rdtscp, "UOiUi*", "")
|
||||
|
||||
TARGET_BUILTIN(__builtin_ia32_rdpid, "Ui", "n", "rdpid")
|
||||
TARGET_BUILTIN(__builtin_ia32_rdpru, "ULLii", "n", "rdpru")
|
||||
|
||||
// PKU
|
||||
TARGET_BUILTIN(__builtin_ia32_rdpkru, "Ui", "n", "pku")
|
||||
|
@ -107,6 +107,7 @@ CODEGENOPT(CFProtectionReturn , 1, 0) ///< if -fcf-protection is
|
||||
CODEGENOPT(CFProtectionBranch , 1, 0) ///< if -fcf-protection is
|
||||
///< set to full or branch.
|
||||
CODEGENOPT(IBTSeal, 1, 0) ///< set to optimize CFProtectionBranch.
|
||||
CODEGENOPT(FunctionReturnThunks, 1, 0) ///< -mfunction-return={keep|thunk-extern}
|
||||
|
||||
CODEGENOPT(XRayInstrumentFunctions , 1, 0) ///< Set when -fxray-instrument is
|
||||
///< enabled.
|
||||
|
@ -389,6 +389,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
|
||||
/// On AArch64 this can only be "sp_el0".
|
||||
std::string StackProtectorGuardReg;
|
||||
|
||||
/// Specify a symbol to be the guard value.
|
||||
std::string StackProtectorGuardSymbol;
|
||||
|
||||
/// Path to ignorelist file specifying which objects
|
||||
/// (files, functions) listed for instrumentation by sanitizer
|
||||
/// coverage pass should actually not be instrumented.
|
||||
|
@ -60,8 +60,6 @@ def err_drv_no_cuda_libdevice : Error<
|
||||
"cannot find libdevice for %0; provide path to different CUDA installation "
|
||||
"via '--cuda-path', or pass '-nocudalib' to build without linking with "
|
||||
"libdevice">;
|
||||
def err_drv_no_rdc_new_driver : Error<
|
||||
"Using '--offload-new-driver' requires '-fgpu-rdc'">;
|
||||
|
||||
def err_drv_no_rocm_device_lib : Error<
|
||||
"cannot find ROCm device library%select{| for %1|for ABI version %1}0; provide its path via "
|
||||
|
@ -31,6 +31,7 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
|
||||
def GNUAutoType : DiagGroup<"gnu-auto-type">;
|
||||
def ArrayBounds : DiagGroup<"array-bounds">;
|
||||
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
|
||||
def ArrayParameter : DiagGroup<"array-parameter">;
|
||||
def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">;
|
||||
def Availability : DiagGroup<"availability">;
|
||||
def Section : DiagGroup<"section">;
|
||||
@ -187,6 +188,7 @@ def UnguardedAvailability : DiagGroup<"unguarded-availability",
|
||||
def : DiagGroup<"partial-availability", [UnguardedAvailability]>;
|
||||
def DeprecatedDynamicExceptionSpec
|
||||
: DiagGroup<"deprecated-dynamic-exception-spec">;
|
||||
def DeprecatedBuiltins : DiagGroup<"deprecated-builtins">;
|
||||
def DeprecatedImplementations :DiagGroup<"deprecated-implementations">;
|
||||
def DeprecatedIncrementBool : DiagGroup<"deprecated-increment-bool">;
|
||||
def DeprecatedRegister : DiagGroup<"deprecated-register">;
|
||||
@ -209,6 +211,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
|
||||
DeprecatedEnumCompareConditional,
|
||||
DeprecatedEnumEnumConversion,
|
||||
DeprecatedEnumFloatConversion,
|
||||
DeprecatedBuiltins,
|
||||
DeprecatedIncrementBool,
|
||||
DeprecatedPragma,
|
||||
DeprecatedRegister,
|
||||
@ -978,6 +981,7 @@ def Extra : DiagGroup<"extra", [
|
||||
]>;
|
||||
|
||||
def Most : DiagGroup<"most", [
|
||||
ArrayParameter,
|
||||
BoolOperation,
|
||||
CharSubscript,
|
||||
Comment,
|
||||
|
@ -113,6 +113,8 @@ def warn_four_char_character_literal : Warning<
|
||||
// Unicode and UCNs
|
||||
def err_invalid_utf8 : Error<
|
||||
"source file is not valid UTF-8">;
|
||||
def warn_invalid_utf8_in_comment : Extension<
|
||||
"invalid UTF-8 in comment">, InGroup<DiagGroup<"invalid-utf8">>;
|
||||
def err_character_not_allowed : Error<
|
||||
"unexpected character <U+%0>">;
|
||||
def err_character_not_allowed_identifier : Error<
|
||||
@ -128,8 +130,15 @@ def warn_utf8_symbol_zero_width : Warning<
|
||||
"some environments">, InGroup<DiagGroup<"unicode-zero-width">>;
|
||||
|
||||
def ext_delimited_escape_sequence : Extension<
|
||||
"%select{delimited|named}0 escape sequences are a Clang extension">,
|
||||
"%select{delimited|named}0 escape sequences are a "
|
||||
"%select{Clang|C++2b}1 extension">,
|
||||
InGroup<DiagGroup<"delimited-escape-sequence-extension">>;
|
||||
|
||||
def warn_cxx2b_delimited_escape_sequence : Warning<
|
||||
"%select{delimited|named}0 escape sequences are "
|
||||
"incompatible with C++ standards before C++2b">,
|
||||
InGroup<CXXPre2bCompat>, DefaultIgnore;
|
||||
|
||||
def err_delimited_escape_empty : Error<
|
||||
"delimited escape sequence cannot be empty">;
|
||||
def err_delimited_escape_missing_brace: Error<
|
||||
|
@ -3115,8 +3115,6 @@ def note_ownership_returns_index_mismatch : Note<
|
||||
"declared with index %0 here">;
|
||||
def err_format_strftime_third_parameter : Error<
|
||||
"strftime format attribute requires 3rd parameter to be 0">;
|
||||
def err_format_attribute_requires_variadic : Error<
|
||||
"format attribute requires variadic function">;
|
||||
def err_format_attribute_not : Error<"format argument not a string type">;
|
||||
def err_format_attribute_result_not : Error<"function does not return %0">;
|
||||
def err_format_attribute_implicit_this_format_string : Error<
|
||||
@ -3343,10 +3341,11 @@ def warn_assume_aligned_too_great
|
||||
"alignment assumed">,
|
||||
InGroup<DiagGroup<"builtin-assume-aligned-alignment">>;
|
||||
def warn_not_xl_compatible
|
||||
: Warning<"requesting an alignment of 16 bytes or greater for struct"
|
||||
" members is not binary compatible with IBM XL C/C++ for AIX"
|
||||
" 16.1.0 and older">,
|
||||
: Warning<"alignment of 16 bytes for a struct member is not binary "
|
||||
"compatible with IBM XL C/C++ for AIX 16.1.0 or older">,
|
||||
InGroup<AIXCompat>;
|
||||
def note_misaligned_member_used_here : Note<
|
||||
"passing byval argument %0 with potentially incompatible alignment here">;
|
||||
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
|
||||
"%q0 redeclared without %1 attribute: previous %1 ignored">,
|
||||
InGroup<MicrosoftInconsistentDllImport>;
|
||||
@ -4127,6 +4126,9 @@ def err_attribute_not_supported_on_arch
|
||||
def warn_gcc_ignores_type_attr : Warning<
|
||||
"GCC does not allow the %0 attribute to be written on a type">,
|
||||
InGroup<GccCompat>;
|
||||
def warn_gcc_requires_variadic_function : Warning<
|
||||
"GCC requires a function with the %0 attribute to be variadic">,
|
||||
InGroup<GccCompat>;
|
||||
|
||||
// Clang-Specific Attributes
|
||||
def warn_attribute_iboutlet : Warning<
|
||||
@ -4829,8 +4831,12 @@ def warn_cxx14_compat_template_nontype_parm_auto_type : Warning<
|
||||
DefaultIgnore, InGroup<CXXPre17Compat>;
|
||||
def err_template_param_default_arg_redefinition : Error<
|
||||
"template parameter redefines default argument">;
|
||||
def err_template_param_default_arg_inconsistent_redefinition : Error<
|
||||
"template parameter default argument is inconsistent with previous definition">;
|
||||
def note_template_param_prev_default_arg : Note<
|
||||
"previous default template argument defined here">;
|
||||
def note_template_param_prev_default_arg_in_other_module : Note<
|
||||
"previous default template argument defined in module %0">;
|
||||
def err_template_param_default_arg_missing : Error<
|
||||
"template parameter missing a default argument">;
|
||||
def ext_template_parameter_default_in_function_template : ExtWarn<
|
||||
@ -5557,6 +5563,9 @@ def warn_deprecated_def : Warning<
|
||||
def warn_unavailable_def : Warning<
|
||||
"implementing unavailable method">,
|
||||
InGroup<DeprecatedImplementations>, DefaultIgnore;
|
||||
def warn_deprecated_builtin : Warning<
|
||||
"builtin %0 is deprecated; use %1 instead">,
|
||||
InGroup<DeprecatedBuiltins>;
|
||||
def err_unavailable : Error<"%0 is unavailable">;
|
||||
def err_property_method_unavailable :
|
||||
Error<"property access is using %0 method which is unavailable">;
|
||||
@ -6605,13 +6614,16 @@ def warn_addition_in_bitshift : Warning<
|
||||
"'%1' will be evaluated first">, InGroup<ShiftOpParentheses>;
|
||||
|
||||
def warn_self_assignment_builtin : Warning<
|
||||
"explicitly assigning value of variable of type %0 to itself">,
|
||||
"explicitly assigning value of variable of type %0 to itself%select{|; did "
|
||||
"you mean to assign to member %2?}1">,
|
||||
InGroup<SelfAssignment>, DefaultIgnore;
|
||||
def warn_self_assignment_overloaded : Warning<
|
||||
"explicitly assigning value of variable of type %0 to itself">,
|
||||
"explicitly assigning value of variable of type %0 to itself%select{|; did "
|
||||
"you mean to assign to member %2?}1">,
|
||||
InGroup<SelfAssignmentOverloaded>, DefaultIgnore;
|
||||
def warn_self_move : Warning<
|
||||
"explicitly moving variable of type %0 to itself">,
|
||||
"explicitly moving variable of type %0 to itself%select{|; did you mean to "
|
||||
"move to member %2?}1">,
|
||||
InGroup<SelfMove>, DefaultIgnore;
|
||||
|
||||
def err_builtin_move_forward_unsupported : Error<
|
||||
@ -9395,6 +9407,12 @@ def warn_array_index_exceeds_max_addressable_bounds : Warning<
|
||||
def note_array_declared_here : Note<
|
||||
"array %0 declared here">;
|
||||
|
||||
def warn_inconsistent_array_form : Warning<
|
||||
"argument %0 of type %1 with mismatched bound">,
|
||||
InGroup<ArrayParameter>, DefaultIgnore;
|
||||
def note_previous_declaration_as : Note<
|
||||
"previously declared as %0 here">;
|
||||
|
||||
def warn_printf_insufficient_data_args : Warning<
|
||||
"more '%%' conversions than data arguments">, InGroup<FormatInsufficientArgs>;
|
||||
def warn_printf_data_arg_not_used : Warning<
|
||||
|
23
contrib/llvm-project/clang/include/clang/Basic/MakeSupport.h
Normal file
23
contrib/llvm-project/clang/include/clang/Basic/MakeSupport.h
Normal file
@ -0,0 +1,23 @@
|
||||
//===- MakeSupport.h - Make Utilities ---------------------------*- 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_BASIC_MAKESUPPORT_H
|
||||
#define LLVM_CLANG_BASIC_MAKESUPPORT_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// Quote target names for inclusion in GNU Make dependency files.
|
||||
/// Only the characters '$', '#', ' ', '\t' are quoted.
|
||||
void quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res);
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_MAKESUPPORT_H
|
@ -222,9 +222,7 @@ class TargetInfo : public virtual TransferrableTargetInfo,
|
||||
mutable VersionTuple PlatformMinVersion;
|
||||
|
||||
unsigned HasAlignMac68kSupport : 1;
|
||||
unsigned RealTypeUsesObjCFPRetMask
|
||||
: llvm::BitmaskEnumDetail::bitWidth(
|
||||
(int)FloatModeKind::LLVM_BITMASK_LARGEST_ENUMERATOR);
|
||||
unsigned RealTypeUsesObjCFPRetMask : llvm::BitWidth<FloatModeKind>;
|
||||
unsigned ComplexLongDoubleUsesFP2Ret : 1;
|
||||
|
||||
unsigned HasBuiltinMSVaList : 1;
|
||||
@ -893,7 +891,7 @@ class TargetInfo : public virtual TransferrableTargetInfo,
|
||||
/// Check whether the given real type should use the "fpret" flavor of
|
||||
/// Objective-C message passing on this target.
|
||||
bool useObjCFPRetForRealType(FloatModeKind T) const {
|
||||
return RealTypeUsesObjCFPRetMask & llvm::BitmaskEnumDetail::Underlying(T);
|
||||
return (int)((FloatModeKind)RealTypeUsesObjCFPRetMask & T);
|
||||
}
|
||||
|
||||
/// Check whether _Complex long double should use the "fp2ret" flavor
|
||||
|
@ -582,18 +582,8 @@ class IsFloat<string type> {
|
||||
}
|
||||
|
||||
let HasUnMaskedOverloaded = false,
|
||||
MaskedPolicy = NonePolicy,
|
||||
ManualCodegen = [{
|
||||
IntrinsicTypes = {ResultType, Ops[1]->getType()};
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
|
||||
}],
|
||||
MaskedManualCodegen= [{
|
||||
// Move mask to right before vl.
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
||||
IntrinsicTypes = {ResultType, Ops[3]->getType()};
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
|
||||
}] in {
|
||||
class RVVVLEMaskBuiltin : RVVBuiltin<"m", "mPCUe", "c"> {
|
||||
MaskedPolicy = NonePolicy in {
|
||||
class RVVVLEMaskBuiltin : RVVOutBuiltin<"m", "mPCUe", "c"> {
|
||||
let Name = "vlm_v";
|
||||
let IRName = "vlm";
|
||||
let HasMasked = false;
|
||||
@ -601,26 +591,15 @@ let HasUnMaskedOverloaded = false,
|
||||
}
|
||||
|
||||
let HasUnMaskedOverloaded = false,
|
||||
ManualCodegen = [{
|
||||
IntrinsicTypes = {ResultType, Ops[1]->getType()};
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
|
||||
Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
|
||||
}],
|
||||
MaskedManualCodegen= [{
|
||||
// Move mask to right before vl.
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
|
||||
IntrinsicTypes = {ResultType, Ops[3]->getType()};
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
|
||||
}] in {
|
||||
UnMaskedPolicy = HasPassthruOperand in {
|
||||
multiclass RVVVLEBuiltin<list<string> types> {
|
||||
let Name = NAME # "_v",
|
||||
IRName = "vle",
|
||||
MaskedIRName ="vle_mask" in {
|
||||
foreach type = types in {
|
||||
def : RVVBuiltin<"v", "vPCe", type>;
|
||||
def : RVVOutBuiltin<"v", "vPCe", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def : RVVBuiltin<"Uv", "UvPCUe", type>;
|
||||
def : RVVOutBuiltin<"Uv", "UvPCUe", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -685,61 +664,39 @@ multiclass RVVVLSEBuiltin<list<string> types> {
|
||||
IRName = "vlse",
|
||||
MaskedIRName ="vlse_mask",
|
||||
HasUnMaskedOverloaded = false,
|
||||
ManualCodegen = [{
|
||||
IntrinsicTypes = {ResultType, Ops[2]->getType()};
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
|
||||
Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
|
||||
}],
|
||||
MaskedManualCodegen= [{
|
||||
// Move mask to right before vl.
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
|
||||
IntrinsicTypes = {ResultType, Ops[4]->getType()};
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
|
||||
}] in {
|
||||
UnMaskedPolicy = HasPassthruOperand in {
|
||||
foreach type = types in {
|
||||
def : RVVBuiltin<"v", "vPCet", type>;
|
||||
def : RVVOutBuiltin<"v", "vPCet", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def : RVVBuiltin<"Uv", "UvPCUet", type>;
|
||||
def : RVVOutBuiltin<"Uv", "UvPCUet", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiclass RVVIndexedLoad<string op> {
|
||||
let ManualCodegen = [{
|
||||
IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[2]->getType()};
|
||||
Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo());
|
||||
Ops.insert(Ops.begin(), llvm::UndefValue::get(ResultType));
|
||||
}],
|
||||
MaskedManualCodegen = [{
|
||||
// Move mask to right before vl.
|
||||
std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);
|
||||
Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED));
|
||||
IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops[4]->getType()};
|
||||
Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo());
|
||||
}] in {
|
||||
foreach type = TypeList in {
|
||||
foreach eew_list = EEWList[0-2] in {
|
||||
defvar eew = eew_list[0];
|
||||
defvar eew_type = eew_list[1];
|
||||
let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask" in {
|
||||
def: RVVBuiltin<"v", "vPCe" # eew_type # "Uv", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def: RVVBuiltin<"Uv", "UvPCUe" # eew_type # "Uv", type>;
|
||||
}
|
||||
}
|
||||
let UnMaskedPolicy = HasPassthruOperand in {
|
||||
foreach type = TypeList in {
|
||||
foreach eew_list = EEWList[0-2] in {
|
||||
defvar eew = eew_list[0];
|
||||
defvar eew_type = eew_list[1];
|
||||
let Name = op # eew # "_v", IRName = op, MaskedIRName = op # "_mask" in {
|
||||
def: RVVOutOp1Builtin<"v", "vPCe" # eew_type # "Uv", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew_type # "Uv", type>;
|
||||
}
|
||||
}
|
||||
defvar eew64 = "64";
|
||||
defvar eew64_type = "(Log2EEW:6)";
|
||||
let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
|
||||
RequiredFeatures = ["RV64"] in {
|
||||
def: RVVBuiltin<"v", "vPCe" # eew64_type # "Uv", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def: RVVBuiltin<"Uv", "UvPCUe" # eew64_type # "Uv", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
defvar eew64 = "64";
|
||||
defvar eew64_type = "(Log2EEW:6)";
|
||||
let Name = op # eew64 # "_v", IRName = op, MaskedIRName = op # "_mask",
|
||||
RequiredFeatures = ["RV64"] in {
|
||||
def: RVVOutOp1Builtin<"v", "vPCe" # eew64_type # "Uv", type>;
|
||||
if !not(IsFloat<type>.val) then {
|
||||
def: RVVOutOp1Builtin<"Uv", "UvPCUe" # eew64_type # "Uv", type>;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1998,6 +1998,13 @@ def fcf_protection : Flag<["-"], "fcf-protection">, Group<f_Group>, Flags<[CoreO
|
||||
HelpText<"Enable cf-protection in 'full' mode">;
|
||||
def mibt_seal : Flag<["-"], "mibt-seal">, Group<m_Group>, Flags<[CoreOption, CC1Option]>,
|
||||
HelpText<"Optimize fcf-protection=branch/full (requires LTO).">;
|
||||
def mfunction_return_EQ : Joined<["-"], "mfunction-return=">,
|
||||
Group<m_Group>, Flags<[CoreOption, CC1Option]>,
|
||||
HelpText<"Replace returns with jumps to ``__x86_return_thunk`` (x86 only, error otherwise)">,
|
||||
Values<"keep,thunk-extern">,
|
||||
NormalizedValues<["Keep", "Extern"]>,
|
||||
NormalizedValuesScope<"llvm::FunctionReturnThunksKind">,
|
||||
MarshallingInfoEnum<CodeGenOpts<"FunctionReturnThunks">, "Keep">;
|
||||
|
||||
defm xray_instrument : BoolFOption<"xray-instrument",
|
||||
LangOpts<"XRayInstrument">, DefaultFalse,
|
||||
@ -3338,11 +3345,12 @@ def mhwmult_EQ : Joined<["-"], "mhwmult=">, Group<m_Group>;
|
||||
def mglobal_merge : Flag<["-"], "mglobal-merge">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Enable merging of globals">;
|
||||
def mhard_float : Flag<["-"], "mhard-float">, Group<m_Group>;
|
||||
def miphoneos_version_min_EQ : Joined<["-"], "miphoneos-version-min=">, Group<m_Group>;
|
||||
def mios_version_min_EQ : Joined<["-"], "mios-version-min=">,
|
||||
Alias<miphoneos_version_min_EQ>, HelpText<"Set iOS deployment target">;
|
||||
Group<m_Group>, HelpText<"Set iOS deployment target">;
|
||||
def : Joined<["-"], "miphoneos-version-min=">,
|
||||
Group<m_Group>, Alias<mios_version_min_EQ>;
|
||||
def mios_simulator_version_min_EQ : Joined<["-"], "mios-simulator-version-min=">;
|
||||
def miphonesimulator_version_min_EQ : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
|
||||
def : Joined<["-"], "miphonesimulator-version-min=">, Alias<mios_simulator_version_min_EQ>;
|
||||
def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
|
||||
def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
|
||||
Flags<[NoXarchOption]>;
|
||||
@ -3354,10 +3362,10 @@ def mmlir : Separate<["-"], "mmlir">, Flags<[CoreOption,FC1Option,FlangOption]>,
|
||||
def ffuchsia_api_level_EQ : Joined<["-"], "ffuchsia-api-level=">,
|
||||
Group<m_Group>, Flags<[CC1Option]>, HelpText<"Set Fuchsia API level">,
|
||||
MarshallingInfoInt<LangOpts<"FuchsiaAPILevel">>;
|
||||
def mmacosx_version_min_EQ : Joined<["-"], "mmacosx-version-min=">,
|
||||
Group<m_Group>, HelpText<"Set Mac OS X deployment target">;
|
||||
def mmacos_version_min_EQ : Joined<["-"], "mmacos-version-min=">,
|
||||
Group<m_Group>, Alias<mmacosx_version_min_EQ>;
|
||||
Group<m_Group>, HelpText<"Set macOS deployment target">;
|
||||
def : Joined<["-"], "mmacosx-version-min=">,
|
||||
Group<m_Group>, Alias<mmacos_version_min_EQ>;
|
||||
def mms_bitfields : Flag<["-"], "mms-bitfields">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard">,
|
||||
MarshallingInfoFlag<LangOpts<"MSBitfields">>;
|
||||
@ -3771,6 +3779,9 @@ def mstack_protector_guard_EQ : Joined<["-"], "mstack-protector-guard=">, Group<
|
||||
def mstack_protector_guard_offset_EQ : Joined<["-"], "mstack-protector-guard-offset=">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use the given offset for addressing the stack-protector guard">,
|
||||
MarshallingInfoInt<CodeGenOpts<"StackProtectorGuardOffset">, "INT_MAX", "int">;
|
||||
def mstack_protector_guard_symbol_EQ : Joined<["-"], "mstack-protector-guard-symbol=">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use the given symbol for addressing the stack-protector guard">,
|
||||
MarshallingInfoString<CodeGenOpts<"StackProtectorGuardSymbol">>;
|
||||
def mstack_protector_guard_reg_EQ : Joined<["-"], "mstack-protector-guard-reg=">, Group<m_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Use the given reg for addressing the stack-protector guard">,
|
||||
MarshallingInfoString<CodeGenOpts<"StackProtectorGuardReg">>;
|
||||
@ -3939,7 +3950,7 @@ def module_file_info : Flag<["-"], "module-file-info">, Flags<[NoXarchOption,CC1
|
||||
HelpText<"Provide information about a particular module file">;
|
||||
def mthumb : Flag<["-"], "mthumb">, Group<m_Group>;
|
||||
def mtune_EQ : Joined<["-"], "mtune=">, Group<m_Group>,
|
||||
HelpText<"Only supported on X86 and RISC-V. Otherwise accepted for compatibility with GCC.">;
|
||||
HelpText<"Only supported on X86, RISC-V and SystemZ. Otherwise accepted for compatibility with GCC.">;
|
||||
def multi__module : Flag<["-"], "multi_module">;
|
||||
def multiply__defined__unused : Separate<["-"], "multiply_defined_unused">;
|
||||
def multiply__defined : Separate<["-"], "multiply_defined">;
|
||||
@ -4570,6 +4581,8 @@ def mptwrite : Flag<["-"], "mptwrite">, Group<m_x86_Features_Group>;
|
||||
def mno_ptwrite : Flag<["-"], "mno-ptwrite">, Group<m_x86_Features_Group>;
|
||||
def mrdpid : Flag<["-"], "mrdpid">, Group<m_x86_Features_Group>;
|
||||
def mno_rdpid : Flag<["-"], "mno-rdpid">, Group<m_x86_Features_Group>;
|
||||
def mrdpru : Flag<["-"], "mrdpru">, Group<m_x86_Features_Group>;
|
||||
def mno_rdpru : Flag<["-"], "mno-rdpru">, Group<m_x86_Features_Group>;
|
||||
def mrdrnd : Flag<["-"], "mrdrnd">, Group<m_x86_Features_Group>;
|
||||
def mno_rdrnd : Flag<["-"], "mno-rdrnd">, Group<m_x86_Features_Group>;
|
||||
def mrtm : Flag<["-"], "mrtm">, Group<m_x86_Features_Group>;
|
||||
|
@ -190,6 +190,10 @@ class SyntaxOnlyAction : public ASTFrontendAction {
|
||||
/// Dump information about the given module file, to be used for
|
||||
/// basic debugging and discovery.
|
||||
class DumpModuleInfoAction : public ASTFrontendAction {
|
||||
public:
|
||||
// Allow other tools (ex lldb) to direct output for their use.
|
||||
llvm::raw_ostream *OutputStream = nullptr;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) override;
|
||||
|
@ -385,6 +385,7 @@ class Preprocessor {
|
||||
|
||||
bool atTopLevel() { return S <= 0; }
|
||||
bool afterImportSeq() { return S == AfterImportSeq; }
|
||||
bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; }
|
||||
|
||||
private:
|
||||
State S;
|
||||
@ -397,6 +398,67 @@ class Preprocessor {
|
||||
/// Our current position within a C++20 import-seq.
|
||||
ImportSeq ImportSeqState = ImportSeq::AfterTopLevelTokenSeq;
|
||||
|
||||
/// Track whether we are in a Global Module Fragment
|
||||
class TrackGMF {
|
||||
public:
|
||||
enum GMFState : int {
|
||||
GMFActive = 1,
|
||||
MaybeGMF = 0,
|
||||
BeforeGMFIntroducer = -1,
|
||||
GMFAbsentOrEnded = -2,
|
||||
};
|
||||
|
||||
TrackGMF(GMFState S) : S(S) {}
|
||||
|
||||
/// Saw a semicolon.
|
||||
void handleSemi() {
|
||||
// If it is immediately after the first instance of the module keyword,
|
||||
// then that introduces the GMF.
|
||||
if (S == MaybeGMF)
|
||||
S = GMFActive;
|
||||
}
|
||||
|
||||
/// Saw an 'export' identifier.
|
||||
void handleExport() {
|
||||
// The presence of an 'export' keyword always ends or excludes a GMF.
|
||||
S = GMFAbsentOrEnded;
|
||||
}
|
||||
|
||||
/// Saw an 'import' identifier.
|
||||
void handleImport(bool AfterTopLevelTokenSeq) {
|
||||
// If we see this before any 'module' kw, then we have no GMF.
|
||||
if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer)
|
||||
S = GMFAbsentOrEnded;
|
||||
}
|
||||
|
||||
/// Saw a 'module' identifier.
|
||||
void handleModule(bool AfterTopLevelTokenSeq) {
|
||||
// This was the first module identifier and not preceded by any token
|
||||
// that would exclude a GMF. It could begin a GMF, but only if directly
|
||||
// followed by a semicolon.
|
||||
if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer)
|
||||
S = MaybeGMF;
|
||||
else
|
||||
S = GMFAbsentOrEnded;
|
||||
}
|
||||
|
||||
/// Saw any other token.
|
||||
void handleMisc() {
|
||||
// We saw something other than ; after the 'module' kw, so not a GMF.
|
||||
if (S == MaybeGMF)
|
||||
S = GMFAbsentOrEnded;
|
||||
}
|
||||
|
||||
bool inGMF() { return S == GMFActive; }
|
||||
|
||||
private:
|
||||
/// Track the transitions into and out of a Global Module Fragment,
|
||||
/// if one is present.
|
||||
GMFState S;
|
||||
};
|
||||
|
||||
TrackGMF TrackGMFState = TrackGMF::BeforeGMFIntroducer;
|
||||
|
||||
/// Whether the module import expects an identifier next. Otherwise,
|
||||
/// it expects a '.' or ';'.
|
||||
bool ModuleImportExpectsIdentifier = false;
|
||||
@ -2414,6 +2476,7 @@ class Preprocessor {
|
||||
None,
|
||||
ModuleBegin,
|
||||
ModuleImport,
|
||||
HeaderUnitImport,
|
||||
SkippedModuleImport,
|
||||
Failure,
|
||||
} Kind;
|
||||
|
@ -0,0 +1,41 @@
|
||||
//===--- HLSLExternalSemaSource.h - HLSL Sema Source ------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the HLSLExternalSemaSource interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
|
||||
#define CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
|
||||
|
||||
#include "clang/Sema/ExternalSemaSource.h"
|
||||
|
||||
namespace clang {
|
||||
class NamespaceDecl;
|
||||
class Sema;
|
||||
|
||||
class HLSLExternalSemaSource : public ExternalSemaSource {
|
||||
Sema *SemaPtr = nullptr;
|
||||
NamespaceDecl *HLSLNamespace;
|
||||
|
||||
void defineHLSLVectorAlias();
|
||||
|
||||
public:
|
||||
~HLSLExternalSemaSource() override;
|
||||
|
||||
/// Initialize the semantic source with the Sema instance
|
||||
/// being used to perform semantic analysis on the abstract syntax
|
||||
/// tree.
|
||||
void InitializeSema(Sema &S) override;
|
||||
|
||||
/// Inform the semantic consumer that Sema is no longer available.
|
||||
void ForgetSema() override { SemaPtr = nullptr; }
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // CLANG_SEMA_HLSLEXTERNALSEMASOURCE_H
|
@ -2272,6 +2272,9 @@ class Sema final {
|
||||
|
||||
bool isAcceptableSlow(const NamedDecl *D, AcceptableKind Kind);
|
||||
|
||||
// Determine whether the module M belongs to the current TU.
|
||||
bool isModuleUnitOfCurrentTU(const Module *M) const;
|
||||
|
||||
public:
|
||||
/// Get the module unit whose scope we are currently within.
|
||||
Module *getCurrentModule() const {
|
||||
@ -5167,6 +5170,11 @@ class Sema final {
|
||||
void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
|
||||
SourceLocation OpLoc);
|
||||
|
||||
/// Returns a field in a CXXRecordDecl that has the same name as the decl \p
|
||||
/// SelfAssigned when inside a CXXMethodDecl.
|
||||
const FieldDecl *
|
||||
getSelfAssignmentClassMemberCandidate(const ValueDecl *SelfAssigned);
|
||||
|
||||
/// Warn if we're implicitly casting from a _Nullable pointer type to a
|
||||
/// _Nonnull one.
|
||||
void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType,
|
||||
@ -12997,21 +13005,29 @@ class Sema final {
|
||||
SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL,
|
||||
unsigned ByteNo) const;
|
||||
|
||||
private:
|
||||
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
|
||||
const ArraySubscriptExpr *ASE=nullptr,
|
||||
bool AllowOnePastEnd=true, bool IndexNegated=false);
|
||||
void CheckArrayAccess(const Expr *E);
|
||||
enum FormatArgumentPassingKind {
|
||||
FAPK_Fixed, // values to format are fixed (no C-style variadic arguments)
|
||||
FAPK_Variadic, // values to format are passed as variadic arguments
|
||||
FAPK_VAList, // values to format are passed in a va_list
|
||||
};
|
||||
|
||||
// Used to grab the relevant information from a FormatAttr and a
|
||||
// FunctionDeclaration.
|
||||
struct FormatStringInfo {
|
||||
unsigned FormatIdx;
|
||||
unsigned FirstDataArg;
|
||||
bool HasVAListArg;
|
||||
FormatArgumentPassingKind ArgPassingKind;
|
||||
};
|
||||
|
||||
static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember,
|
||||
FormatStringInfo *FSI);
|
||||
bool IsVariadic, FormatStringInfo *FSI);
|
||||
|
||||
private:
|
||||
void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
|
||||
const ArraySubscriptExpr *ASE = nullptr,
|
||||
bool AllowOnePastEnd = true, bool IndexNegated = false);
|
||||
void CheckArrayAccess(const Expr *E);
|
||||
|
||||
bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall,
|
||||
const FunctionProtoType *Proto);
|
||||
bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc,
|
||||
@ -13023,6 +13039,8 @@ class Sema final {
|
||||
ArrayRef<const Expr *> Args,
|
||||
const FunctionProtoType *Proto, SourceLocation Loc);
|
||||
|
||||
void checkAIXMemberAlignment(SourceLocation Loc, const Expr *Arg);
|
||||
|
||||
void CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl,
|
||||
StringRef ParamName, QualType ArgTy, QualType ParamTy);
|
||||
|
||||
@ -13166,16 +13184,15 @@ class Sema final {
|
||||
|
||||
private:
|
||||
bool CheckFormatArguments(const FormatAttr *Format,
|
||||
ArrayRef<const Expr *> Args,
|
||||
bool IsCXXMember,
|
||||
VariadicCallType CallType,
|
||||
SourceLocation Loc, SourceRange Range,
|
||||
ArrayRef<const Expr *> Args, bool IsCXXMember,
|
||||
VariadicCallType CallType, SourceLocation Loc,
|
||||
SourceRange Range,
|
||||
llvm::SmallBitVector &CheckedVarArgs);
|
||||
bool CheckFormatArguments(ArrayRef<const Expr *> Args,
|
||||
bool HasVAListArg, unsigned format_idx,
|
||||
FormatArgumentPassingKind FAPK, unsigned format_idx,
|
||||
unsigned firstDataArg, FormatStringType Type,
|
||||
VariadicCallType CallType,
|
||||
SourceLocation Loc, SourceRange range,
|
||||
VariadicCallType CallType, SourceLocation Loc,
|
||||
SourceRange range,
|
||||
llvm::SmallBitVector &CheckedVarArgs);
|
||||
|
||||
void CheckAbsoluteValueFunction(const CallExpr *Call,
|
||||
|
@ -414,7 +414,8 @@ class CallEvent {
|
||||
bool isArgumentConstructedDirectly(unsigned Index) const {
|
||||
// This assumes that the object was not yet removed from the state.
|
||||
return ExprEngine::getObjectUnderConstruction(
|
||||
getState(), {getOriginExpr(), Index}, getLocationContext()).hasValue();
|
||||
getState(), {getOriginExpr(), Index}, getLocationContext())
|
||||
.has_value();
|
||||
}
|
||||
|
||||
/// Some calls have parameter numbering mismatched from argument numbering.
|
||||
@ -1018,7 +1019,7 @@ class CXXAllocatorCall : public AnyFunctionCall {
|
||||
SVal getObjectUnderConstruction() const {
|
||||
return ExprEngine::getObjectUnderConstruction(getState(), getOriginExpr(),
|
||||
getLocationContext())
|
||||
.getValue();
|
||||
.value();
|
||||
}
|
||||
|
||||
/// Number of non-placement arguments to the call. It is equal to 2 for
|
||||
|
@ -53,21 +53,17 @@ class ConditionTruthVal {
|
||||
}
|
||||
|
||||
/// Return true if the constraint is perfectly constrained to 'true'.
|
||||
bool isConstrainedTrue() const { return Val && Val.getValue(); }
|
||||
bool isConstrainedTrue() const { return Val && Val.value(); }
|
||||
|
||||
/// Return true if the constraint is perfectly constrained to 'false'.
|
||||
bool isConstrainedFalse() const { return Val && !Val.getValue(); }
|
||||
bool isConstrainedFalse() const { return Val && !Val.value(); }
|
||||
|
||||
/// Return true if the constrained is perfectly constrained.
|
||||
bool isConstrained() const {
|
||||
return Val.hasValue();
|
||||
}
|
||||
bool isConstrained() const { return Val.has_value(); }
|
||||
|
||||
/// Return true if the constrained is underconstrained and we do not know
|
||||
/// if the constraint is true of value.
|
||||
bool isUnderconstrained() const {
|
||||
return !Val.hasValue();
|
||||
}
|
||||
bool isUnderconstrained() const { return !Val.has_value(); }
|
||||
};
|
||||
|
||||
class ConstraintManager {
|
||||
|
@ -344,7 +344,7 @@ class SMTConstraintManager : public clang::ento::SimpleConstraintManager {
|
||||
if (!res)
|
||||
Cached[hash] = ConditionTruthVal();
|
||||
else
|
||||
Cached[hash] = ConditionTruthVal(res.getValue());
|
||||
Cached[hash] = ConditionTruthVal(res.value());
|
||||
|
||||
return Cached[hash];
|
||||
}
|
||||
|
@ -209,8 +209,8 @@ class RVVType {
|
||||
}
|
||||
|
||||
bool isValid() const { return Valid; }
|
||||
bool isScalar() const { return Scale && Scale.getValue() == 0; }
|
||||
bool isVector() const { return Scale && Scale.getValue() != 0; }
|
||||
bool isScalar() const { return Scale && Scale.value() == 0; }
|
||||
bool isVector() const { return Scale && Scale.value() != 0; }
|
||||
bool isVector(unsigned Width) const {
|
||||
return isVector() && ElementBitwidth == Width;
|
||||
}
|
||||
@ -225,6 +225,8 @@ class RVVType {
|
||||
return isFloat() && ElementBitwidth == Width;
|
||||
}
|
||||
|
||||
bool isPointer() const { return IsPointer; }
|
||||
|
||||
private:
|
||||
// Verify RVV vector type and set Valid.
|
||||
bool verifyType() const;
|
||||
|
@ -94,9 +94,9 @@ class CachedFileSystemEntry {
|
||||
assert(!isDirectory() && "not a file");
|
||||
assert(Contents && "contents not initialized");
|
||||
if (auto *Directives = Contents->DepDirectives.load()) {
|
||||
if (Directives->hasValue())
|
||||
if (Directives->has_value())
|
||||
return ArrayRef<dependency_directives_scan::Directive>(
|
||||
Directives->getValue());
|
||||
Directives->value());
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
@ -47,12 +47,12 @@ struct FullDependencies {
|
||||
|
||||
/// Get the full command line.
|
||||
///
|
||||
/// \param LookupPCMPath This function is called to fill in "-fmodule-file="
|
||||
/// arguments and the "-o" argument. It needs to return
|
||||
/// a path for where the PCM for the given module is to
|
||||
/// be located.
|
||||
std::vector<std::string>
|
||||
getCommandLine(std::function<StringRef(ModuleID)> LookupPCMPath) const;
|
||||
/// \param LookupModuleOutput This function is called to fill in
|
||||
/// "-fmodule-file=", "-o" and other output
|
||||
/// arguments for dependencies.
|
||||
std::vector<std::string> getCommandLine(
|
||||
llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
|
||||
LookupOutput) const;
|
||||
|
||||
/// Get the full command line, excluding -fmodule-file=" arguments.
|
||||
std::vector<std::string> getCommandLineWithoutModulePaths() const;
|
||||
|
@ -65,6 +65,19 @@ struct ModuleIDHasher {
|
||||
}
|
||||
};
|
||||
|
||||
/// An output from a module compilation, such as the path of the module file.
|
||||
enum class ModuleOutputKind {
|
||||
/// The module file (.pcm). Required.
|
||||
ModuleFile,
|
||||
/// The path of the dependency file (.d), if any.
|
||||
DependencyFile,
|
||||
/// The null-separated list of names to use as the targets in the dependency
|
||||
/// file, if any. Defaults to the value of \c ModuleFile, as in the driver.
|
||||
DependencyTargets,
|
||||
/// The path of the serialized diagnostic file (.dia), if any.
|
||||
DiagnosticSerializationFile,
|
||||
};
|
||||
|
||||
struct ModuleDeps {
|
||||
/// The identifier of the module.
|
||||
ModuleID ID;
|
||||
@ -104,17 +117,25 @@ struct ModuleDeps {
|
||||
// the primary TU.
|
||||
bool ImportedByMainFile = false;
|
||||
|
||||
/// Whether the TU had a dependency file. The path in \c BuildInvocation is
|
||||
/// cleared to avoid leaking the specific path from the TU into the module.
|
||||
bool HadDependencyFile = false;
|
||||
|
||||
/// Whether the TU had serialized diagnostics. The path in \c BuildInvocation
|
||||
/// is cleared to avoid leaking the specific path from the TU into the module.
|
||||
bool HadSerializedDiagnostics = false;
|
||||
|
||||
/// Compiler invocation that can be used to build this module (without paths).
|
||||
CompilerInvocation BuildInvocation;
|
||||
|
||||
/// Gets the canonical command line suitable for passing to clang.
|
||||
///
|
||||
/// \param LookupPCMPath This function is called to fill in "-fmodule-file="
|
||||
/// arguments and the "-o" argument. It needs to return
|
||||
/// a path for where the PCM for the given module is to
|
||||
/// be located.
|
||||
/// \param LookupModuleOutput This function is called to fill in
|
||||
/// "-fmodule-file=", "-o" and other output
|
||||
/// arguments.
|
||||
std::vector<std::string> getCanonicalCommandLine(
|
||||
std::function<StringRef(ModuleID)> LookupPCMPath) const;
|
||||
llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>
|
||||
LookupModuleOutput) const;
|
||||
|
||||
/// Gets the canonical command line suitable for passing to clang, excluding
|
||||
/// "-fmodule-file=" and "-o" arguments.
|
||||
|
@ -3166,7 +3166,7 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD,
|
||||
/// declaration of a function with an exception specification is permitted
|
||||
/// and preserved. Other type sugar (for instance, typedefs) is not.
|
||||
QualType ASTContext::getFunctionTypeWithExceptionSpec(
|
||||
QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||
QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) const {
|
||||
// Might have some parens.
|
||||
if (const auto *PT = dyn_cast<ParenType>(Orig))
|
||||
return getParenType(
|
||||
@ -3194,7 +3194,7 @@ QualType ASTContext::getFunctionTypeWithExceptionSpec(
|
||||
}
|
||||
|
||||
bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T,
|
||||
QualType U) {
|
||||
QualType U) const {
|
||||
return hasSameType(T, U) ||
|
||||
(getLangOpts().CPlusPlus17 &&
|
||||
hasSameType(getFunctionTypeWithExceptionSpec(T, EST_None),
|
||||
@ -4703,7 +4703,7 @@ QualType ASTContext::getUnresolvedUsingType(
|
||||
|
||||
QualType ASTContext::getAttributedType(attr::Kind attrKind,
|
||||
QualType modifiedType,
|
||||
QualType equivalentType) {
|
||||
QualType equivalentType) const {
|
||||
llvm::FoldingSetNodeID id;
|
||||
AttributedType::Profile(id, attrKind, modifiedType, equivalentType);
|
||||
|
||||
@ -5707,6 +5707,9 @@ QualType ASTContext::getAutoTypeInternal(
|
||||
!TypeConstraintConcept && !IsDependent)
|
||||
return getAutoDeductType();
|
||||
|
||||
if (TypeConstraintConcept)
|
||||
TypeConstraintConcept = TypeConstraintConcept->getCanonicalDecl();
|
||||
|
||||
// Look in the folding set for an existing type.
|
||||
void *InsertPos = nullptr;
|
||||
llvm::FoldingSetNodeID ID;
|
||||
@ -6215,8 +6218,59 @@ bool ASTContext::hasSameTemplateName(const TemplateName &X,
|
||||
getCanonicalTemplateName(Y).getAsVoidPointer();
|
||||
}
|
||||
|
||||
bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const {
|
||||
if (!XCE != !YCE)
|
||||
return false;
|
||||
|
||||
if (!XCE)
|
||||
return true;
|
||||
|
||||
llvm::FoldingSetNodeID XCEID, YCEID;
|
||||
XCE->Profile(XCEID, *this, /*Canonical=*/true);
|
||||
YCE->Profile(YCEID, *this, /*Canonical=*/true);
|
||||
return XCEID == YCEID;
|
||||
}
|
||||
|
||||
bool ASTContext::isSameTypeConstraint(const TypeConstraint *XTC,
|
||||
const TypeConstraint *YTC) const {
|
||||
if (!XTC != !YTC)
|
||||
return false;
|
||||
|
||||
if (!XTC)
|
||||
return true;
|
||||
|
||||
auto *NCX = XTC->getNamedConcept();
|
||||
auto *NCY = YTC->getNamedConcept();
|
||||
if (!NCX || !NCY || !isSameEntity(NCX, NCY))
|
||||
return false;
|
||||
if (XTC->hasExplicitTemplateArgs() != YTC->hasExplicitTemplateArgs())
|
||||
return false;
|
||||
if (XTC->hasExplicitTemplateArgs())
|
||||
if (XTC->getTemplateArgsAsWritten()->NumTemplateArgs !=
|
||||
YTC->getTemplateArgsAsWritten()->NumTemplateArgs)
|
||||
return false;
|
||||
|
||||
// Compare slowly by profiling.
|
||||
//
|
||||
// We couldn't compare the profiling result for the template
|
||||
// args here. Consider the following example in different modules:
|
||||
//
|
||||
// template <__integer_like _Tp, C<_Tp> Sentinel>
|
||||
// constexpr _Tp operator()(_Tp &&__t, Sentinel &&last) const {
|
||||
// return __t;
|
||||
// }
|
||||
//
|
||||
// When we compare the profiling result for `C<_Tp>` in different
|
||||
// modules, it will compare the type of `_Tp` in different modules.
|
||||
// However, the type of `_Tp` in different modules refer to different
|
||||
// types here naturally. So we couldn't compare the profiling result
|
||||
// for the template args directly.
|
||||
return isSameConstraintExpr(XTC->getImmediatelyDeclaredConstraint(),
|
||||
YTC->getImmediatelyDeclaredConstraint());
|
||||
}
|
||||
|
||||
bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
|
||||
const NamedDecl *Y) {
|
||||
const NamedDecl *Y) const {
|
||||
if (X->getKind() != Y->getKind())
|
||||
return false;
|
||||
|
||||
@ -6226,32 +6280,8 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
|
||||
return false;
|
||||
if (TX->hasTypeConstraint() != TY->hasTypeConstraint())
|
||||
return false;
|
||||
const TypeConstraint *TXTC = TX->getTypeConstraint();
|
||||
const TypeConstraint *TYTC = TY->getTypeConstraint();
|
||||
if (!TXTC != !TYTC)
|
||||
return false;
|
||||
if (TXTC && TYTC) {
|
||||
auto *NCX = TXTC->getNamedConcept();
|
||||
auto *NCY = TYTC->getNamedConcept();
|
||||
if (!NCX || !NCY || !isSameEntity(NCX, NCY))
|
||||
return false;
|
||||
if (TXTC->hasExplicitTemplateArgs() != TYTC->hasExplicitTemplateArgs())
|
||||
return false;
|
||||
if (TXTC->hasExplicitTemplateArgs()) {
|
||||
auto *TXTCArgs = TXTC->getTemplateArgsAsWritten();
|
||||
auto *TYTCArgs = TYTC->getTemplateArgsAsWritten();
|
||||
if (TXTCArgs->NumTemplateArgs != TYTCArgs->NumTemplateArgs)
|
||||
return false;
|
||||
llvm::FoldingSetNodeID XID, YID;
|
||||
for (auto &ArgLoc : TXTCArgs->arguments())
|
||||
ArgLoc.getArgument().Profile(XID, X->getASTContext());
|
||||
for (auto &ArgLoc : TYTCArgs->arguments())
|
||||
ArgLoc.getArgument().Profile(YID, Y->getASTContext());
|
||||
if (XID != YID)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return isSameTypeConstraint(TX->getTypeConstraint(),
|
||||
TY->getTypeConstraint());
|
||||
}
|
||||
|
||||
if (auto *TX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
|
||||
@ -6267,8 +6297,8 @@ bool ASTContext::isSameTemplateParameter(const NamedDecl *X,
|
||||
TY->getTemplateParameters());
|
||||
}
|
||||
|
||||
bool ASTContext::isSameTemplateParameterList(const TemplateParameterList *X,
|
||||
const TemplateParameterList *Y) {
|
||||
bool ASTContext::isSameTemplateParameterList(
|
||||
const TemplateParameterList *X, const TemplateParameterList *Y) const {
|
||||
if (X->size() != Y->size())
|
||||
return false;
|
||||
|
||||
@ -6276,19 +6306,46 @@ bool ASTContext::isSameTemplateParameterList(const TemplateParameterList *X,
|
||||
if (!isSameTemplateParameter(X->getParam(I), Y->getParam(I)))
|
||||
return false;
|
||||
|
||||
const Expr *XRC = X->getRequiresClause();
|
||||
const Expr *YRC = Y->getRequiresClause();
|
||||
if (!XRC != !YRC)
|
||||
return isSameConstraintExpr(X->getRequiresClause(), Y->getRequiresClause());
|
||||
}
|
||||
|
||||
bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X,
|
||||
const NamedDecl *Y) const {
|
||||
// If the type parameter isn't the same already, we don't need to check the
|
||||
// default argument further.
|
||||
if (!isSameTemplateParameter(X, Y))
|
||||
return false;
|
||||
if (XRC) {
|
||||
llvm::FoldingSetNodeID XRCID, YRCID;
|
||||
XRC->Profile(XRCID, *this, /*Canonical=*/true);
|
||||
YRC->Profile(YRCID, *this, /*Canonical=*/true);
|
||||
if (XRCID != YRCID)
|
||||
|
||||
if (auto *TTPX = dyn_cast<TemplateTypeParmDecl>(X)) {
|
||||
auto *TTPY = cast<TemplateTypeParmDecl>(Y);
|
||||
if (!TTPX->hasDefaultArgument() || !TTPY->hasDefaultArgument())
|
||||
return false;
|
||||
|
||||
return hasSameType(TTPX->getDefaultArgument(), TTPY->getDefaultArgument());
|
||||
}
|
||||
|
||||
return true;
|
||||
if (auto *NTTPX = dyn_cast<NonTypeTemplateParmDecl>(X)) {
|
||||
auto *NTTPY = cast<NonTypeTemplateParmDecl>(Y);
|
||||
if (!NTTPX->hasDefaultArgument() || !NTTPY->hasDefaultArgument())
|
||||
return false;
|
||||
|
||||
Expr *DefaultArgumentX = NTTPX->getDefaultArgument()->IgnoreImpCasts();
|
||||
Expr *DefaultArgumentY = NTTPY->getDefaultArgument()->IgnoreImpCasts();
|
||||
llvm::FoldingSetNodeID XID, YID;
|
||||
DefaultArgumentX->Profile(XID, *this, /*Canonical=*/true);
|
||||
DefaultArgumentY->Profile(YID, *this, /*Canonical=*/true);
|
||||
return XID == YID;
|
||||
}
|
||||
|
||||
auto *TTPX = cast<TemplateTemplateParmDecl>(X);
|
||||
auto *TTPY = cast<TemplateTemplateParmDecl>(Y);
|
||||
|
||||
if (!TTPX->hasDefaultArgument() || !TTPY->hasDefaultArgument())
|
||||
return false;
|
||||
|
||||
const TemplateArgument &TAX = TTPX->getDefaultArgument().getArgument();
|
||||
const TemplateArgument &TAY = TTPY->getDefaultArgument().getArgument();
|
||||
return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate());
|
||||
}
|
||||
|
||||
static NamespaceDecl *getNamespace(const NestedNameSpecifier *X) {
|
||||
@ -6371,7 +6428,7 @@ static bool hasSameOverloadableAttrs(const FunctionDecl *A,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
|
||||
bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) const {
|
||||
if (X == Y)
|
||||
return true;
|
||||
|
||||
@ -6447,17 +6504,9 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Expr *XRC = FuncX->getTrailingRequiresClause();
|
||||
const Expr *YRC = FuncY->getTrailingRequiresClause();
|
||||
if (!XRC != !YRC)
|
||||
if (!isSameConstraintExpr(FuncX->getTrailingRequiresClause(),
|
||||
FuncY->getTrailingRequiresClause()))
|
||||
return false;
|
||||
if (XRC) {
|
||||
llvm::FoldingSetNodeID XRCID, YRCID;
|
||||
XRC->Profile(XRCID, *this, /*Canonical=*/true);
|
||||
YRC->Profile(YRCID, *this, /*Canonical=*/true);
|
||||
if (XRCID != YRCID)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto GetTypeAsWritten = [](const FunctionDecl *FD) {
|
||||
// Map to the first declaration that we've already merged into this one.
|
||||
@ -6478,8 +6527,6 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
|
||||
if (getLangOpts().CPlusPlus17 && XFPT && YFPT &&
|
||||
(isUnresolvedExceptionSpec(XFPT->getExceptionSpecType()) ||
|
||||
isUnresolvedExceptionSpec(YFPT->getExceptionSpecType())) &&
|
||||
// FIXME: We could make isSameEntity const after we make
|
||||
// hasSameFunctionTypeIgnoringExceptionSpec const.
|
||||
hasSameFunctionTypeIgnoringExceptionSpec(XT, YT))
|
||||
return true;
|
||||
return false;
|
||||
@ -6521,6 +6568,20 @@ bool ASTContext::isSameEntity(const NamedDecl *X, const NamedDecl *Y) {
|
||||
// and patterns match.
|
||||
if (const auto *TemplateX = dyn_cast<TemplateDecl>(X)) {
|
||||
const auto *TemplateY = cast<TemplateDecl>(Y);
|
||||
|
||||
// ConceptDecl wouldn't be the same if their constraint expression differs.
|
||||
if (const auto *ConceptX = dyn_cast<ConceptDecl>(X)) {
|
||||
const auto *ConceptY = cast<ConceptDecl>(Y);
|
||||
const Expr *XCE = ConceptX->getConstraintExpr();
|
||||
const Expr *YCE = ConceptY->getConstraintExpr();
|
||||
assert(XCE && YCE && "ConceptDecl without constraint expression?");
|
||||
llvm::FoldingSetNodeID XID, YID;
|
||||
XCE->Profile(XID, *this, /*Canonical=*/true);
|
||||
YCE->Profile(YID, *this, /*Canonical=*/true);
|
||||
if (XID != YID)
|
||||
return false;
|
||||
}
|
||||
|
||||
return isSameEntity(TemplateX->getTemplatedDecl(),
|
||||
TemplateY->getTemplatedDecl()) &&
|
||||
isSameTemplateParameterList(TemplateX->getTemplateParameters(),
|
||||
|
@ -5667,11 +5667,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
|
||||
D2->setPreviousDecl(Recent);
|
||||
}
|
||||
|
||||
if (FromTemplated->isCompleteDefinition() &&
|
||||
!ToTemplated->isCompleteDefinition()) {
|
||||
// FIXME: Import definition!
|
||||
}
|
||||
|
||||
return D2;
|
||||
}
|
||||
|
||||
@ -5950,11 +5945,6 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) {
|
||||
ToVarTD->setPreviousDecl(Recent);
|
||||
}
|
||||
|
||||
if (DTemplated->isThisDeclarationADefinition() &&
|
||||
!ToTemplated->isThisDeclarationADefinition()) {
|
||||
// FIXME: Import definition!
|
||||
}
|
||||
|
||||
return ToVarTD;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy>
|
||||
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(const ValueDecl *VD) {
|
||||
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
|
||||
if (ActiveAttr)
|
||||
return ActiveAttr.getValue()->getMapType();
|
||||
return ActiveAttr.value()->getMapType();
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ llvm::Optional<OMPDeclareTargetDeclAttr::DevTypeTy>
|
||||
OMPDeclareTargetDeclAttr::getDeviceType(const ValueDecl *VD) {
|
||||
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
|
||||
if (ActiveAttr)
|
||||
return ActiveAttr.getValue()->getDevType();
|
||||
return ActiveAttr.value()->getDevType();
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ llvm::Optional<SourceLocation>
|
||||
OMPDeclareTargetDeclAttr::getLocation(const ValueDecl *VD) {
|
||||
llvm::Optional<OMPDeclareTargetDeclAttr *> ActiveAttr = getActiveAttr(VD);
|
||||
if (ActiveAttr)
|
||||
return ActiveAttr.getValue()->getRange().getBegin();
|
||||
return ActiveAttr.value()->getRange().getBegin();
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
|
@ -1007,6 +1007,12 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
||||
}
|
||||
}
|
||||
|
||||
if (auto *Def = D->getDefinition()) {
|
||||
if (D->hasAttr<FinalAttr>()) {
|
||||
Out << " final";
|
||||
}
|
||||
}
|
||||
|
||||
if (D->isCompleteDefinition()) {
|
||||
// Print the base classes
|
||||
if (D->getNumBases()) {
|
||||
|
@ -321,6 +321,12 @@ bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(
|
||||
|
||||
clang::analyze_format_string::ArgType::MatchKind
|
||||
ArgType::matchesType(ASTContext &C, QualType argTy) const {
|
||||
// When using the format attribute in C++, you can receive a function or an
|
||||
// array that will necessarily decay to a pointer when passed to the final
|
||||
// format consumer. Apply decay before type comparison.
|
||||
if (argTy->canDecayToPointerType())
|
||||
argTy = C.getDecayedType(argTy);
|
||||
|
||||
if (Ptr) {
|
||||
// It has to be a pointer.
|
||||
const PointerType *PT = argTy->getAs<PointerType>();
|
||||
|
@ -496,7 +496,7 @@ ByteCodeExprGen<Emitter>::getGlobalIdx(const VarDecl *VD) {
|
||||
|
||||
template <class Emitter>
|
||||
const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
|
||||
if (auto *PT = dyn_cast<PointerType>(Ty))
|
||||
if (const PointerType *PT = dyn_cast<PointerType>(Ty))
|
||||
return PT->getPointeeType()->getAs<RecordType>();
|
||||
else
|
||||
return Ty->getAs<RecordType>();
|
||||
|
@ -699,7 +699,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D)
|
||||
Stmt *BodyFarm::getBody(const FunctionDecl *D) {
|
||||
Optional<Stmt *> &Val = Bodies[D];
|
||||
if (Val)
|
||||
return Val.getValue();
|
||||
return Val.value();
|
||||
|
||||
Val = nullptr;
|
||||
|
||||
@ -874,7 +874,7 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) {
|
||||
|
||||
Optional<Stmt *> &Val = Bodies[D];
|
||||
if (Val)
|
||||
return Val.getValue();
|
||||
return Val.value();
|
||||
Val = nullptr;
|
||||
|
||||
// For now, we only synthesize getters.
|
||||
|
@ -36,7 +36,7 @@ buildStmtToBasicBlockMap(const CFG &Cfg) {
|
||||
if (!Stmt)
|
||||
continue;
|
||||
|
||||
StmtToBlock[Stmt.getValue().getStmt()] = Block;
|
||||
StmtToBlock[Stmt.value().getStmt()] = Block;
|
||||
}
|
||||
if (const Stmt *TerminatorStmt = Block->getTerminatorStmt())
|
||||
StmtToBlock[TerminatorStmt] = Block;
|
||||
|
@ -24,8 +24,8 @@ namespace dataflow {
|
||||
|
||||
StorageLocation &
|
||||
DataflowAnalysisContext::getStableStorageLocation(QualType Type) {
|
||||
assert(!Type.isNull());
|
||||
if (Type->isStructureOrClassType() || Type->isUnionType()) {
|
||||
if (!Type.isNull() &&
|
||||
(Type->isStructureOrClassType() || Type->isUnionType())) {
|
||||
// FIXME: Explore options to avoid eager initialization of fields as some of
|
||||
// them might not be needed for a particular analysis.
|
||||
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
|
||||
@ -57,8 +57,8 @@ DataflowAnalysisContext::getStableStorageLocation(const Expr &E) {
|
||||
|
||||
PointerValue &
|
||||
DataflowAnalysisContext::getOrCreateNullPointerValue(QualType PointeeType) {
|
||||
assert(!PointeeType.isNull());
|
||||
auto CanonicalPointeeType = PointeeType.getCanonicalType();
|
||||
auto CanonicalPointeeType =
|
||||
PointeeType.isNull() ? PointeeType : PointeeType.getCanonicalType();
|
||||
auto Res = NullPointerVals.try_emplace(CanonicalPointeeType, nullptr);
|
||||
if (Res.second) {
|
||||
auto &PointeeLoc = getStableStorageLocation(CanonicalPointeeType);
|
||||
|
@ -0,0 +1,197 @@
|
||||
//===- DebugSupport.cpp -----------------------------------------*- 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 functions which generate more readable forms of data
|
||||
// structures used in the dataflow analyses, for debugging purposes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/DebugSupport.h"
|
||||
#include "clang/Analysis/FlowSensitive/Solver.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatCommon.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
using llvm::AlignStyle;
|
||||
using llvm::fmt_pad;
|
||||
using llvm::formatv;
|
||||
|
||||
namespace {
|
||||
|
||||
class DebugStringGenerator {
|
||||
public:
|
||||
explicit DebugStringGenerator(
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNamesArg)
|
||||
: Counter(0), AtomNames(std::move(AtomNamesArg)) {
|
||||
#ifndef NDEBUG
|
||||
llvm::StringSet<> Names;
|
||||
for (auto &N : AtomNames) {
|
||||
assert(Names.insert(N.second).second &&
|
||||
"The same name must not assigned to different atoms");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Returns a string representation of a boolean value `B`.
|
||||
std::string debugString(const BoolValue &B, size_t Depth = 0) {
|
||||
std::string S;
|
||||
switch (B.getKind()) {
|
||||
case Value::Kind::AtomicBool: {
|
||||
S = getAtomName(&cast<AtomicBoolValue>(B));
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Conjunction: {
|
||||
auto &C = cast<ConjunctionValue>(B);
|
||||
auto L = debugString(C.getLeftSubValue(), Depth + 1);
|
||||
auto R = debugString(C.getRightSubValue(), Depth + 1);
|
||||
S = formatv("(and\n{0}\n{1})", L, R);
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Disjunction: {
|
||||
auto &D = cast<DisjunctionValue>(B);
|
||||
auto L = debugString(D.getLeftSubValue(), Depth + 1);
|
||||
auto R = debugString(D.getRightSubValue(), Depth + 1);
|
||||
S = formatv("(or\n{0}\n{1})", L, R);
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Negation: {
|
||||
auto &N = cast<NegationValue>(B);
|
||||
S = formatv("(not\n{0})", debugString(N.getSubVal(), Depth + 1));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("Unhandled value kind");
|
||||
}
|
||||
auto Indent = Depth * 4;
|
||||
return formatv("{0}", fmt_pad(S, Indent, 0));
|
||||
}
|
||||
|
||||
/// Returns a string representation of a set of boolean `Constraints` and the
|
||||
/// `Result` of satisfiability checking on the `Constraints`.
|
||||
std::string debugString(const std::vector<BoolValue *> &Constraints,
|
||||
const Solver::Result &Result) {
|
||||
auto Template = R"(
|
||||
Constraints
|
||||
------------
|
||||
{0:$[
|
||||
|
||||
]}
|
||||
------------
|
||||
{1}.
|
||||
{2}
|
||||
)";
|
||||
|
||||
std::vector<std::string> ConstraintsStrings;
|
||||
ConstraintsStrings.reserve(Constraints.size());
|
||||
for (auto &Constraint : Constraints) {
|
||||
ConstraintsStrings.push_back(debugString(*Constraint));
|
||||
}
|
||||
|
||||
auto StatusString = debugString(Result.getStatus());
|
||||
auto Solution = Result.getSolution();
|
||||
auto SolutionString =
|
||||
Solution.hasValue() ? "\n" + debugString(Solution.value()) : "";
|
||||
|
||||
return formatv(
|
||||
Template,
|
||||
llvm::make_range(ConstraintsStrings.begin(), ConstraintsStrings.end()),
|
||||
StatusString, SolutionString);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Returns a string representation of a truth assignment to atom booleans.
|
||||
std::string debugString(
|
||||
const llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
|
||||
&AtomAssignments) {
|
||||
size_t MaxNameLength = 0;
|
||||
for (auto &AtomName : AtomNames) {
|
||||
MaxNameLength = std::max(MaxNameLength, AtomName.second.size());
|
||||
}
|
||||
|
||||
std::vector<std::string> Lines;
|
||||
for (auto &AtomAssignment : AtomAssignments) {
|
||||
auto Line = formatv("{0} = {1}",
|
||||
fmt_align(getAtomName(AtomAssignment.first),
|
||||
AlignStyle::Left, MaxNameLength),
|
||||
debugString(AtomAssignment.second));
|
||||
Lines.push_back(Line);
|
||||
}
|
||||
llvm::sort(Lines.begin(), Lines.end());
|
||||
|
||||
return formatv("{0:$[\n]}", llvm::make_range(Lines.begin(), Lines.end()));
|
||||
}
|
||||
|
||||
/// Returns a string representation of a boolean assignment to true or false.
|
||||
std::string debugString(Solver::Result::Assignment Assignment) {
|
||||
switch (Assignment) {
|
||||
case Solver::Result::Assignment::AssignedFalse:
|
||||
return "False";
|
||||
case Solver::Result::Assignment::AssignedTrue:
|
||||
return "True";
|
||||
}
|
||||
llvm_unreachable("Booleans can only be assigned true/false");
|
||||
}
|
||||
|
||||
/// Returns a string representation of the result status of a SAT check.
|
||||
std::string debugString(Solver::Result::Status Status) {
|
||||
switch (Status) {
|
||||
case Solver::Result::Status::Satisfiable:
|
||||
return "Satisfiable";
|
||||
case Solver::Result::Status::Unsatisfiable:
|
||||
return "Unsatisfiable";
|
||||
case Solver::Result::Status::TimedOut:
|
||||
return "TimedOut";
|
||||
}
|
||||
llvm_unreachable("Unhandled SAT check result status");
|
||||
}
|
||||
|
||||
/// Returns the name assigned to `Atom`, either user-specified or created by
|
||||
/// default rules (B0, B1, ...).
|
||||
std::string getAtomName(const AtomicBoolValue *Atom) {
|
||||
auto Entry = AtomNames.try_emplace(Atom, formatv("B{0}", Counter));
|
||||
if (Entry.second) {
|
||||
Counter++;
|
||||
}
|
||||
return Entry.first->second;
|
||||
}
|
||||
|
||||
// Keep track of number of atoms without a user-specified name, used to assign
|
||||
// non-repeating default names to such atoms.
|
||||
size_t Counter;
|
||||
|
||||
// Keep track of names assigned to atoms.
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string
|
||||
debugString(const BoolValue &B,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
|
||||
return DebugStringGenerator(std::move(AtomNames)).debugString(B);
|
||||
}
|
||||
|
||||
std::string
|
||||
debugString(const std::vector<BoolValue *> &Constraints,
|
||||
const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames) {
|
||||
return DebugStringGenerator(std::move(AtomNames))
|
||||
.debugString(Constraints, Result);
|
||||
}
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
@ -51,7 +51,7 @@ class StmtToEnvMapImpl : public StmtToEnvMap {
|
||||
assert(BlockIT != CFCtx.getStmtToBlock().end());
|
||||
const auto &State = BlockToState[BlockIT->getSecond()->getBlockID()];
|
||||
assert(State);
|
||||
return &State.getValue().Env;
|
||||
return &State.value().Env;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -212,7 +212,7 @@ static TypeErasedDataflowAnalysisState computeBlockInputState(
|
||||
if (!MaybePredState)
|
||||
continue;
|
||||
|
||||
TypeErasedDataflowAnalysisState PredState = MaybePredState.getValue();
|
||||
TypeErasedDataflowAnalysisState PredState = MaybePredState.value();
|
||||
if (ApplyBuiltinTransfer) {
|
||||
if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) {
|
||||
const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates);
|
||||
@ -370,7 +370,7 @@ runTypeErasedDataflowAnalysis(
|
||||
transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis);
|
||||
|
||||
if (OldBlockState &&
|
||||
Analysis.isEqualTypeErased(OldBlockState.getValue().Lattice,
|
||||
Analysis.isEqualTypeErased(OldBlockState.value().Lattice,
|
||||
NewBlockState.Lattice) &&
|
||||
OldBlockState->Env.equivalentTo(NewBlockState.Env, Analysis)) {
|
||||
// The state of `Block` didn't change after transfer so there's no need to
|
||||
|
@ -120,7 +120,13 @@ struct BooleanFormula {
|
||||
/// clauses in the formula start from the element at index 1.
|
||||
std::vector<ClauseID> NextWatched;
|
||||
|
||||
explicit BooleanFormula(Variable LargestVar) : LargestVar(LargestVar) {
|
||||
/// Stores the variable identifier and value location for atomic booleans in
|
||||
/// the formula.
|
||||
llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
|
||||
|
||||
explicit BooleanFormula(Variable LargestVar,
|
||||
llvm::DenseMap<Variable, AtomicBoolValue *> Atomics)
|
||||
: LargestVar(LargestVar), Atomics(std::move(Atomics)) {
|
||||
Clauses.push_back(0);
|
||||
ClauseStarts.push_back(0);
|
||||
NextWatched.push_back(0);
|
||||
@ -180,28 +186,47 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
|
||||
|
||||
// Map each sub-value in `Vals` to a unique variable.
|
||||
llvm::DenseMap<BoolValue *, Variable> SubValsToVar;
|
||||
// Store variable identifiers and value location of atomic booleans.
|
||||
llvm::DenseMap<Variable, AtomicBoolValue *> Atomics;
|
||||
Variable NextVar = 1;
|
||||
{
|
||||
std::queue<BoolValue *> UnprocessedSubVals;
|
||||
for (BoolValue *Val : Vals)
|
||||
UnprocessedSubVals.push(Val);
|
||||
while (!UnprocessedSubVals.empty()) {
|
||||
Variable Var = NextVar;
|
||||
BoolValue *Val = UnprocessedSubVals.front();
|
||||
UnprocessedSubVals.pop();
|
||||
|
||||
if (!SubValsToVar.try_emplace(Val, NextVar).second)
|
||||
if (!SubValsToVar.try_emplace(Val, Var).second)
|
||||
continue;
|
||||
++NextVar;
|
||||
|
||||
// Visit the sub-values of `Val`.
|
||||
if (auto *C = dyn_cast<ConjunctionValue>(Val)) {
|
||||
switch (Val->getKind()) {
|
||||
case Value::Kind::Conjunction: {
|
||||
auto *C = cast<ConjunctionValue>(Val);
|
||||
UnprocessedSubVals.push(&C->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&C->getRightSubValue());
|
||||
} else if (auto *D = dyn_cast<DisjunctionValue>(Val)) {
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Disjunction: {
|
||||
auto *D = cast<DisjunctionValue>(Val);
|
||||
UnprocessedSubVals.push(&D->getLeftSubValue());
|
||||
UnprocessedSubVals.push(&D->getRightSubValue());
|
||||
} else if (auto *N = dyn_cast<NegationValue>(Val)) {
|
||||
break;
|
||||
}
|
||||
case Value::Kind::Negation: {
|
||||
auto *N = cast<NegationValue>(Val);
|
||||
UnprocessedSubVals.push(&N->getSubVal());
|
||||
break;
|
||||
}
|
||||
case Value::Kind::AtomicBool: {
|
||||
Atomics[Var] = cast<AtomicBoolValue>(Val);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
llvm_unreachable("buildBooleanFormula: unhandled value kind");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -212,7 +237,7 @@ BooleanFormula buildBooleanFormula(const llvm::DenseSet<BoolValue *> &Vals) {
|
||||
return ValIt->second;
|
||||
};
|
||||
|
||||
BooleanFormula Formula(NextVar - 1);
|
||||
BooleanFormula Formula(NextVar - 1, std::move(Atomics));
|
||||
std::vector<bool> ProcessedSubVals(NextVar, false);
|
||||
|
||||
// Add a conjunct for each variable that represents a top-level conjunction
|
||||
@ -383,7 +408,7 @@ class WatchedLiteralsSolverImpl {
|
||||
// If the root level is reached, then all possible assignments lead to
|
||||
// a conflict.
|
||||
if (Level == 0)
|
||||
return WatchedLiteralsSolver::Result::Unsatisfiable;
|
||||
return Solver::Result::Unsatisfiable();
|
||||
|
||||
// Otherwise, take the other branch at the most recent level where a
|
||||
// decision was made.
|
||||
@ -440,12 +465,29 @@ class WatchedLiteralsSolverImpl {
|
||||
++I;
|
||||
}
|
||||
}
|
||||
return WatchedLiteralsSolver::Result::Satisfiable;
|
||||
return Solver::Result::Satisfiable(buildSolution());
|
||||
}
|
||||
|
||||
private:
|
||||
// Reverses forced moves until the most recent level where a decision was made
|
||||
// on the assignment of a variable.
|
||||
/// Returns a satisfying truth assignment to the atomic values in the boolean
|
||||
/// formula.
|
||||
llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment>
|
||||
buildSolution() {
|
||||
llvm::DenseMap<AtomicBoolValue *, Solver::Result::Assignment> Solution;
|
||||
for (auto &Atomic : Formula.Atomics) {
|
||||
// A variable may have a definite true/false assignment, or it may be
|
||||
// unassigned indicating its truth value does not affect the result of
|
||||
// the formula. Unassigned variables are assigned to true as a default.
|
||||
Solution[Atomic.second] =
|
||||
VarAssignments[Atomic.first] == Assignment::AssignedFalse
|
||||
? Solver::Result::Assignment::AssignedFalse
|
||||
: Solver::Result::Assignment::AssignedTrue;
|
||||
}
|
||||
return Solution;
|
||||
}
|
||||
|
||||
/// Reverses forced moves until the most recent level where a decision was
|
||||
/// made on the assignment of a variable.
|
||||
void reverseForcedMoves() {
|
||||
for (; LevelStates[Level] == State::Forced; --Level) {
|
||||
const Variable Var = LevelVars[Level];
|
||||
@ -459,7 +501,7 @@ class WatchedLiteralsSolverImpl {
|
||||
}
|
||||
}
|
||||
|
||||
// Updates watched literals that are affected by a variable assignment.
|
||||
/// Updates watched literals that are affected by a variable assignment.
|
||||
void updateWatchedLiterals() {
|
||||
const Variable Var = LevelVars[Level];
|
||||
|
||||
@ -592,7 +634,7 @@ class WatchedLiteralsSolverImpl {
|
||||
};
|
||||
|
||||
Solver::Result WatchedLiteralsSolver::solve(llvm::DenseSet<BoolValue *> Vals) {
|
||||
return Vals.empty() ? WatchedLiteralsSolver::Result::Satisfiable
|
||||
return Vals.empty() ? Solver::Result::Satisfiable({{}})
|
||||
: WatchedLiteralsSolverImpl(Vals).solve();
|
||||
}
|
||||
|
||||
|
@ -320,7 +320,7 @@ static Optional<bool> comparePath(const PathPieces &X, const PathPieces &Y) {
|
||||
for ( ; X_I != X_end && Y_I != Y_end; ++X_I, ++Y_I) {
|
||||
Optional<bool> b = comparePiece(**X_I, **Y_I);
|
||||
if (b)
|
||||
return b.getValue();
|
||||
return b.value();
|
||||
}
|
||||
|
||||
return None;
|
||||
@ -397,7 +397,7 @@ static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) {
|
||||
}
|
||||
Optional<bool> b = comparePath(X.path, Y.path);
|
||||
assert(b);
|
||||
return b.getValue();
|
||||
return b.value();
|
||||
}
|
||||
|
||||
void PathDiagnosticConsumer::FlushDiagnostics(
|
||||
|
@ -149,7 +149,7 @@ class CFGBlockValues {
|
||||
const VarDecl *vd) {
|
||||
const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
|
||||
assert(idx);
|
||||
return getValueVector(block)[idx.getValue()];
|
||||
return getValueVector(block)[idx.value()];
|
||||
}
|
||||
};
|
||||
|
||||
@ -210,7 +210,7 @@ void CFGBlockValues::resetScratch() {
|
||||
ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
|
||||
const Optional<unsigned> &idx = declToIndex.getValueIndex(vd);
|
||||
assert(idx);
|
||||
return scratch[idx.getValue()];
|
||||
return scratch[idx.value()];
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------====//
|
||||
|
@ -61,8 +61,8 @@ LangStandard::Kind clang::getDefaultLanguageStandard(clang::Language Lang,
|
||||
if (CLANG_DEFAULT_STD_C != LangStandard::lang_unspecified)
|
||||
return CLANG_DEFAULT_STD_C;
|
||||
|
||||
// The PS4 and PS5 use C99 as the default C standard.
|
||||
if (T.isPS())
|
||||
// The PS4 uses C99 as the default C standard.
|
||||
if (T.isPS4())
|
||||
return LangStandard::lang_gnu99;
|
||||
return LangStandard::lang_gnu17;
|
||||
case Language::ObjC:
|
||||
|
35
contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp
Normal file
35
contrib/llvm-project/clang/lib/Basic/MakeSupport.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
//===-- MakeSuport.cpp --------------------------------------------------*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/MakeSupport.h"
|
||||
|
||||
void clang::quoteMakeTarget(StringRef Target, SmallVectorImpl<char> &Res) {
|
||||
for (unsigned i = 0, e = Target.size(); i != e; ++i) {
|
||||
switch (Target[i]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
// Escape the preceding backslashes
|
||||
for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
|
||||
Res.push_back('\\');
|
||||
|
||||
// Escape the space/tab
|
||||
Res.push_back('\\');
|
||||
break;
|
||||
case '$':
|
||||
Res.push_back('$');
|
||||
break;
|
||||
case '#':
|
||||
Res.push_back('\\');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Res.push_back(Target[i]);
|
||||
}
|
||||
}
|
@ -503,7 +503,7 @@ bool TargetInfo::initFeatureMap(
|
||||
TargetInfo::CallingConvKind
|
||||
TargetInfo::getCallingConvKind(bool ClangABICompat4) const {
|
||||
if (getCXXABI() != TargetCXXABI::Microsoft &&
|
||||
(ClangABICompat4 || getTriple().getOS() == llvm::Triple::PS4))
|
||||
(ClangABICompat4 || getTriple().isPS4()))
|
||||
return CCK_ClangABI4OrPS4;
|
||||
return CCK_Default;
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
|
||||
.Case("64bit", Is64Bit)
|
||||
.Default(None);
|
||||
if (Result)
|
||||
return Result.getValue();
|
||||
return Result.value();
|
||||
|
||||
if (ISAInfo->isSupportedExtensionFeature(Feature))
|
||||
return ISAInfo->hasExtension(Feature);
|
||||
|
@ -123,6 +123,14 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo {
|
||||
|
||||
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
|
||||
|
||||
bool isValidTuneCPUName(StringRef Name) const override {
|
||||
return isValidCPUName(Name);
|
||||
}
|
||||
|
||||
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override {
|
||||
fillValidCPUList(Values);
|
||||
}
|
||||
|
||||
bool setCPU(const std::string &Name) override {
|
||||
CPU = Name;
|
||||
ISARevision = getISARevision(CPU);
|
||||
|
@ -297,6 +297,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
HasCLDEMOTE = true;
|
||||
} else if (Feature == "+rdpid") {
|
||||
HasRDPID = true;
|
||||
} else if (Feature == "+rdpru") {
|
||||
HasRDPRU = true;
|
||||
} else if (Feature == "+kl") {
|
||||
HasKL = true;
|
||||
} else if (Feature == "+widekl") {
|
||||
@ -743,6 +745,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
Builder.defineMacro("__WIDEKL__");
|
||||
if (HasRDPID)
|
||||
Builder.defineMacro("__RDPID__");
|
||||
if (HasRDPRU)
|
||||
Builder.defineMacro("__RDPRU__");
|
||||
if (HasCLDEMOTE)
|
||||
Builder.defineMacro("__CLDEMOTE__");
|
||||
if (HasWAITPKG)
|
||||
@ -926,6 +930,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
|
||||
.Case("prfchw", true)
|
||||
.Case("ptwrite", true)
|
||||
.Case("rdpid", true)
|
||||
.Case("rdpru", true)
|
||||
.Case("rdrnd", true)
|
||||
.Case("rdseed", true)
|
||||
.Case("rtm", true)
|
||||
@ -1021,6 +1026,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
|
||||
.Case("prfchw", HasPRFCHW)
|
||||
.Case("ptwrite", HasPTWRITE)
|
||||
.Case("rdpid", HasRDPID)
|
||||
.Case("rdpru", HasRDPRU)
|
||||
.Case("rdrnd", HasRDRND)
|
||||
.Case("rdseed", HasRDSEED)
|
||||
.Case("retpoline-external-thunk", HasRetpolineExternalThunk)
|
||||
|
@ -125,6 +125,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
|
||||
bool HasMOVBE = false;
|
||||
bool HasPREFETCHWT1 = false;
|
||||
bool HasRDPID = false;
|
||||
bool HasRDPRU = false;
|
||||
bool HasRetpolineExternalThunk = false;
|
||||
bool HasLAHFSAHF = false;
|
||||
bool HasWBNOINVD = false;
|
||||
@ -424,8 +425,8 @@ class LLVM_LIBRARY_VISIBILITY X86_32TargetInfo : public X86TargetInfo {
|
||||
|
||||
// Use fpret for all types.
|
||||
RealTypeUsesObjCFPRetMask =
|
||||
(int)(FloatModeKind::Float | FloatModeKind::Double |
|
||||
FloatModeKind::LongDouble);
|
||||
(unsigned)(FloatModeKind::Float | FloatModeKind::Double |
|
||||
FloatModeKind::LongDouble);
|
||||
|
||||
// x86-32 has atomics up to 8 bytes
|
||||
MaxAtomicPromoteWidth = 64;
|
||||
@ -704,7 +705,7 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo {
|
||||
"64-i64:64-f80:128-n8:16:32:64-S128");
|
||||
|
||||
// Use fpret only for long double.
|
||||
RealTypeUsesObjCFPRetMask = (int)FloatModeKind::LongDouble;
|
||||
RealTypeUsesObjCFPRetMask = (unsigned)FloatModeKind::LongDouble;
|
||||
|
||||
// Use fp2ret for _Complex long double.
|
||||
ComplexLongDoubleUsesFP2Ret = true;
|
||||
|
@ -788,6 +788,18 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
|
||||
SI.registerCallbacks(PIC, &FAM);
|
||||
PassBuilder PB(TM.get(), PTO, PGOOpt, &PIC);
|
||||
|
||||
// Enable verify-debuginfo-preserve-each for new PM.
|
||||
DebugifyEachInstrumentation Debugify;
|
||||
DebugInfoPerPass DebugInfoBeforePass;
|
||||
if (CodeGenOpts.EnableDIPreservationVerify) {
|
||||
Debugify.setDebugifyMode(DebugifyMode::OriginalDebugInfo);
|
||||
Debugify.setDebugInfoBeforePass(DebugInfoBeforePass);
|
||||
|
||||
if (!CodeGenOpts.DIBugsReportFilePath.empty())
|
||||
Debugify.setOrigDIVerifyBugsReportFilePath(
|
||||
CodeGenOpts.DIBugsReportFilePath);
|
||||
Debugify.registerCallbacks(PIC);
|
||||
}
|
||||
// Attempt to load pass plugins and register their callbacks with PB.
|
||||
for (auto &PluginFN : CodeGenOpts.PassPlugins) {
|
||||
auto PassPlugin = PassPlugin::Load(PluginFN);
|
||||
|
@ -212,8 +212,7 @@ static std::unique_ptr<MangleContext> InitDeviceMC(CodeGenModule &CGM) {
|
||||
CGNVCUDARuntime::CGNVCUDARuntime(CodeGenModule &CGM)
|
||||
: CGCUDARuntime(CGM), Context(CGM.getLLVMContext()),
|
||||
TheModule(CGM.getModule()),
|
||||
RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode ||
|
||||
CGM.getLangOpts().OffloadingNewDriver),
|
||||
RelocatableDeviceCode(CGM.getLangOpts().GPURelocatableDeviceCode),
|
||||
DeviceMC(InitDeviceMC(CGM)) {
|
||||
CodeGen::CodeGenTypes &Types = CGM.getTypes();
|
||||
ASTContext &Ctx = CGM.getContext();
|
||||
@ -1116,7 +1115,8 @@ void CGNVCUDARuntime::createOffloadingEntries() {
|
||||
llvm::OpenMPIRBuilder OMPBuilder(CGM.getModule());
|
||||
OMPBuilder.initialize();
|
||||
|
||||
StringRef Section = "cuda_offloading_entries";
|
||||
StringRef Section = CGM.getLangOpts().HIP ? "hip_offloading_entries"
|
||||
: "cuda_offloading_entries";
|
||||
for (KernelInfo &I : EmittedKernels)
|
||||
OMPBuilder.emitOffloadingEntry(KernelHandles[I.Kernel],
|
||||
getDeviceSideName(cast<NamedDecl>(I.D)), 0,
|
||||
@ -1171,10 +1171,11 @@ llvm::Function *CGNVCUDARuntime::finalizeModule() {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
if (!(CGM.getLangOpts().OffloadingNewDriver && RelocatableDeviceCode))
|
||||
if (CGM.getLangOpts().OffloadingNewDriver && RelocatableDeviceCode)
|
||||
createOffloadingEntries();
|
||||
else
|
||||
return makeModuleCtorFunction();
|
||||
|
||||
createOffloadingEntries();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1931,6 +1931,9 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name,
|
||||
FuncAttrs.addAttribute(llvm::Attribute::Convergent);
|
||||
}
|
||||
|
||||
// TODO: NoUnwind attribute should be added for other GPU modes OpenCL, HIP,
|
||||
// SYCL, OpenMP offload. AFAIK, none of them support exceptions in device
|
||||
// code.
|
||||
if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
|
||||
// Exceptions aren't supported in CUDA device code.
|
||||
FuncAttrs.addAttribute(llvm::Attribute::NoUnwind);
|
||||
|
@ -1783,14 +1783,14 @@ namespace {
|
||||
StartIndex = FieldIndex;
|
||||
} else if (StartIndex) {
|
||||
EHStack.pushCleanup<SanitizeDtorFieldRange>(
|
||||
NormalAndEHCleanup, DD, StartIndex.getValue(), FieldIndex);
|
||||
NormalAndEHCleanup, DD, StartIndex.value(), FieldIndex);
|
||||
StartIndex = None;
|
||||
}
|
||||
}
|
||||
void End() {
|
||||
if (StartIndex)
|
||||
EHStack.pushCleanup<SanitizeDtorFieldRange>(NormalAndEHCleanup, DD,
|
||||
StartIndex.getValue(), -1);
|
||||
StartIndex.value(), -1);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -6717,11 +6717,9 @@ llvm::Value *CGOpenMPRuntime::emitNumTeamsForTargetDirective(
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (DefaultNT == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return Bld.getInt32(DefaultNT);
|
||||
return llvm::ConstantInt::get(CGF.Int32Ty, DefaultNT);
|
||||
}
|
||||
|
||||
static llvm::Value *getNumThreads(CodeGenFunction &CGF, const CapturedStmt *CS,
|
||||
@ -10189,9 +10187,8 @@ llvm::Function *CGOpenMPRuntime::getOrCreateUserDefinedMapperFunc(
|
||||
return UDMMap.lookup(D);
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::emitTargetNumIterationsCall(
|
||||
llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall(
|
||||
CodeGenFunction &CGF, const OMPExecutableDirective &D,
|
||||
llvm::Value *DeviceID,
|
||||
llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
|
||||
const OMPLoopDirective &D)>
|
||||
SizeEmitter) {
|
||||
@ -10201,20 +10198,12 @@ void CGOpenMPRuntime::emitTargetNumIterationsCall(
|
||||
if (!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind))
|
||||
TD = getNestedDistributeDirective(CGM.getContext(), D);
|
||||
if (!TD)
|
||||
return;
|
||||
return llvm::ConstantInt::get(CGF.Int64Ty, 0);
|
||||
|
||||
const auto *LD = cast<OMPLoopDirective>(TD);
|
||||
auto &&CodeGen = [LD, DeviceID, SizeEmitter, &D, this](CodeGenFunction &CGF,
|
||||
PrePostActionTy &) {
|
||||
if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD)) {
|
||||
llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
|
||||
llvm::Value *Args[] = {RTLoc, DeviceID, NumIterations};
|
||||
CGF.EmitRuntimeCall(
|
||||
OMPBuilder.getOrCreateRuntimeFunction(
|
||||
CGM.getModule(), OMPRTL___kmpc_push_target_tripcount_mapper),
|
||||
Args);
|
||||
}
|
||||
};
|
||||
emitInlinedDirective(CGF, OMPD_unknown, CodeGen);
|
||||
if (llvm::Value *NumIterations = SizeEmitter(CGF, *LD))
|
||||
return NumIterations;
|
||||
return llvm::ConstantInt::get(CGF.Int64Ty, 0);
|
||||
}
|
||||
|
||||
void CGOpenMPRuntime::emitTargetCall(
|
||||
@ -10308,26 +10297,34 @@ void CGOpenMPRuntime::emitTargetCall(
|
||||
// Source location for the ident struct
|
||||
llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc());
|
||||
|
||||
// Emit tripcount for the target loop-based directive.
|
||||
emitTargetNumIterationsCall(CGF, D, DeviceID, SizeEmitter);
|
||||
// Get tripcount for the target loop-based directive.
|
||||
llvm::Value *NumIterations =
|
||||
emitTargetNumIterationsCall(CGF, D, SizeEmitter);
|
||||
|
||||
// Arguments for the target kernel.
|
||||
SmallVector<llvm::Value *> KernelArgs{
|
||||
CGF.Builder.getInt32(/* Version */ 1),
|
||||
PointerNum,
|
||||
InputInfo.BasePointersArray.getPointer(),
|
||||
InputInfo.PointersArray.getPointer(),
|
||||
InputInfo.SizesArray.getPointer(),
|
||||
MapTypesArray,
|
||||
MapNamesArray,
|
||||
InputInfo.MappersArray.getPointer(),
|
||||
NumIterations};
|
||||
|
||||
// Arguments passed to the 'nowait' variant.
|
||||
SmallVector<llvm::Value *> NoWaitKernelArgs{
|
||||
CGF.Builder.getInt32(0),
|
||||
llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
|
||||
CGF.Builder.getInt32(0),
|
||||
llvm::ConstantPointerNull::get(CGM.VoidPtrTy),
|
||||
};
|
||||
|
||||
bool HasNoWait = D.hasClausesOfKind<OMPNowaitClause>();
|
||||
|
||||
bool HasNowait = D.hasClausesOfKind<OMPNowaitClause>();
|
||||
// The target region is an outlined function launched by the runtime
|
||||
// via calls __tgt_target() or __tgt_target_teams().
|
||||
//
|
||||
// __tgt_target() launches a target region with one team and one thread,
|
||||
// executing a serial region. This master thread may in turn launch
|
||||
// more threads within its team upon encountering a parallel region,
|
||||
// however, no additional teams can be launched on the device.
|
||||
//
|
||||
// __tgt_target_teams() launches a target region with one or more teams,
|
||||
// each with one or more threads. This call is required for target
|
||||
// constructs such as:
|
||||
// 'target teams'
|
||||
// 'target' / 'teams'
|
||||
// 'target teams distribute parallel for'
|
||||
// 'target parallel'
|
||||
// and so on.
|
||||
// via calls to __tgt_target_kernel().
|
||||
//
|
||||
// Note that on the host and CPU targets, the runtime implementation of
|
||||
// these calls simply call the outlined function without forking threads.
|
||||
@ -10338,70 +10335,15 @@ void CGOpenMPRuntime::emitTargetCall(
|
||||
// In contrast, on the NVPTX target, the implementation of
|
||||
// __tgt_target_teams() launches a GPU kernel with the requested number
|
||||
// of teams and threads so no additional calls to the runtime are required.
|
||||
if (NumTeams) {
|
||||
// If we have NumTeams defined this means that we have an enclosed teams
|
||||
// region. Therefore we also expect to have NumThreads defined. These two
|
||||
// values should be defined in the presence of a teams directive,
|
||||
// regardless of having any clauses associated. If the user is using teams
|
||||
// but no clauses, these two values will be the default that should be
|
||||
// passed to the runtime library - a 32-bit integer with the value zero.
|
||||
assert(NumThreads && "Thread limit expression should be available along "
|
||||
"with number of teams.");
|
||||
SmallVector<llvm::Value *> OffloadingArgs = {
|
||||
RTLoc,
|
||||
DeviceID,
|
||||
OutlinedFnID,
|
||||
PointerNum,
|
||||
InputInfo.BasePointersArray.getPointer(),
|
||||
InputInfo.PointersArray.getPointer(),
|
||||
InputInfo.SizesArray.getPointer(),
|
||||
MapTypesArray,
|
||||
MapNamesArray,
|
||||
InputInfo.MappersArray.getPointer(),
|
||||
NumTeams,
|
||||
NumThreads};
|
||||
if (HasNowait) {
|
||||
// Add int32_t depNum = 0, void *depList = nullptr, int32_t
|
||||
// noAliasDepNum = 0, void *noAliasDepList = nullptr.
|
||||
OffloadingArgs.push_back(CGF.Builder.getInt32(0));
|
||||
OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
|
||||
OffloadingArgs.push_back(CGF.Builder.getInt32(0));
|
||||
OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
|
||||
}
|
||||
Return = CGF.EmitRuntimeCall(
|
||||
OMPBuilder.getOrCreateRuntimeFunction(
|
||||
CGM.getModule(), HasNowait
|
||||
? OMPRTL___tgt_target_teams_nowait_mapper
|
||||
: OMPRTL___tgt_target_teams_mapper),
|
||||
OffloadingArgs);
|
||||
} else {
|
||||
SmallVector<llvm::Value *> OffloadingArgs = {
|
||||
RTLoc,
|
||||
DeviceID,
|
||||
OutlinedFnID,
|
||||
PointerNum,
|
||||
InputInfo.BasePointersArray.getPointer(),
|
||||
InputInfo.PointersArray.getPointer(),
|
||||
InputInfo.SizesArray.getPointer(),
|
||||
MapTypesArray,
|
||||
MapNamesArray,
|
||||
InputInfo.MappersArray.getPointer()};
|
||||
if (HasNowait) {
|
||||
// Add int32_t depNum = 0, void *depList = nullptr, int32_t
|
||||
// noAliasDepNum = 0, void *noAliasDepList = nullptr.
|
||||
OffloadingArgs.push_back(CGF.Builder.getInt32(0));
|
||||
OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
|
||||
OffloadingArgs.push_back(CGF.Builder.getInt32(0));
|
||||
OffloadingArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy));
|
||||
}
|
||||
Return = CGF.EmitRuntimeCall(
|
||||
OMPBuilder.getOrCreateRuntimeFunction(
|
||||
CGM.getModule(), HasNowait ? OMPRTL___tgt_target_nowait_mapper
|
||||
: OMPRTL___tgt_target_mapper),
|
||||
OffloadingArgs);
|
||||
}
|
||||
|
||||
// Check the error code and execute the host version if required.
|
||||
CGF.Builder.restoreIP(
|
||||
HasNoWait ? OMPBuilder.emitTargetKernel(
|
||||
CGF.Builder, Return, RTLoc, DeviceID, NumTeams,
|
||||
NumThreads, OutlinedFnID, KernelArgs, NoWaitKernelArgs)
|
||||
: OMPBuilder.emitTargetKernel(CGF.Builder, Return, RTLoc,
|
||||
DeviceID, NumTeams, NumThreads,
|
||||
OutlinedFnID, KernelArgs));
|
||||
|
||||
llvm::BasicBlock *OffloadFailedBlock =
|
||||
CGF.createBasicBlock("omp_offload.failed");
|
||||
llvm::BasicBlock *OffloadContBlock =
|
||||
|
@ -884,13 +884,11 @@ class CGOpenMPRuntime {
|
||||
llvm::Function *TaskFunction, QualType SharedsTy,
|
||||
Address Shareds, const OMPTaskDataTy &Data);
|
||||
|
||||
/// Emit code that pushes the trip count of loops associated with constructs
|
||||
/// 'target teams distribute' and 'teams distribute parallel for'.
|
||||
/// \param SizeEmitter Emits the int64 value for the number of iterations of
|
||||
/// the associated loop.
|
||||
void emitTargetNumIterationsCall(
|
||||
/// Return the trip count of loops associated with constructs / 'target teams
|
||||
/// distribute' and 'teams distribute parallel for'. \param SizeEmitter Emits
|
||||
/// the int64 value for the number of iterations of the associated loop.
|
||||
llvm::Value *emitTargetNumIterationsCall(
|
||||
CodeGenFunction &CGF, const OMPExecutableDirective &D,
|
||||
llvm::Value *DeviceID,
|
||||
llvm::function_ref<llvm::Value *(CodeGenFunction &CGF,
|
||||
const OMPLoopDirective &D)>
|
||||
SizeEmitter);
|
||||
|
@ -2591,11 +2591,12 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S,
|
||||
}
|
||||
}
|
||||
|
||||
static bool isSupportedByOpenMPIRBuilder(const OMPExecutableDirective &S) {
|
||||
static bool isSupportedByOpenMPIRBuilder(const OMPSimdDirective &S) {
|
||||
// Check for unsupported clauses
|
||||
if (!S.clauses().empty()) {
|
||||
// Currently no clause is supported
|
||||
return false;
|
||||
for (OMPClause *C : S.clauses()) {
|
||||
// Currently only simdlen clause is supported
|
||||
if (!isa<OMPSimdlenClause>(C))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we have a statement with the ordered directive.
|
||||
@ -2630,7 +2631,6 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
|
||||
// Use the OpenMPIRBuilder if enabled.
|
||||
if (UseOMPIRBuilder) {
|
||||
// Emit the associated statement and get its loop representation.
|
||||
llvm::DebugLoc DL = SourceLocToDebugLoc(S.getBeginLoc());
|
||||
const Stmt *Inner = S.getRawStmt();
|
||||
llvm::CanonicalLoopInfo *CLI =
|
||||
EmitOMPCollapsedCanonicalLoopNest(Inner, 1);
|
||||
@ -2638,7 +2638,15 @@ void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) {
|
||||
llvm::OpenMPIRBuilder &OMPBuilder =
|
||||
CGM.getOpenMPRuntime().getOMPBuilder();
|
||||
// Add SIMD specific metadata
|
||||
OMPBuilder.applySimd(DL, CLI);
|
||||
llvm::ConstantInt *Simdlen = nullptr;
|
||||
if (const auto *C = S.getSingleClause<OMPSimdlenClause>()) {
|
||||
RValue Len =
|
||||
this->EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(),
|
||||
/*ignoreResult=*/true);
|
||||
auto *Val = cast<llvm::ConstantInt>(Len.getScalarVal());
|
||||
Simdlen = Val;
|
||||
}
|
||||
OMPBuilder.applySimd(CLI, Simdlen);
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -5998,18 +6006,26 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
|
||||
RMWOp = llvm::AtomicRMWInst::Xor;
|
||||
break;
|
||||
case BO_LT:
|
||||
RMWOp = X.getType()->hasSignedIntegerRepresentation()
|
||||
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
|
||||
: llvm::AtomicRMWInst::Max)
|
||||
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
|
||||
: llvm::AtomicRMWInst::UMax);
|
||||
if (IsInteger)
|
||||
RMWOp = X.getType()->hasSignedIntegerRepresentation()
|
||||
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min
|
||||
: llvm::AtomicRMWInst::Max)
|
||||
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin
|
||||
: llvm::AtomicRMWInst::UMax);
|
||||
else
|
||||
RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMin
|
||||
: llvm::AtomicRMWInst::FMax;
|
||||
break;
|
||||
case BO_GT:
|
||||
RMWOp = X.getType()->hasSignedIntegerRepresentation()
|
||||
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
|
||||
: llvm::AtomicRMWInst::Min)
|
||||
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
|
||||
: llvm::AtomicRMWInst::UMin);
|
||||
if (IsInteger)
|
||||
RMWOp = X.getType()->hasSignedIntegerRepresentation()
|
||||
? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max
|
||||
: llvm::AtomicRMWInst::Min)
|
||||
: (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax
|
||||
: llvm::AtomicRMWInst::UMin);
|
||||
else
|
||||
RMWOp = IsXLHSInRHSPart ? llvm::AtomicRMWInst::FMax
|
||||
: llvm::AtomicRMWInst::FMin;
|
||||
break;
|
||||
case BO_Assign:
|
||||
RMWOp = llvm::AtomicRMWInst::Xchg;
|
||||
|
@ -898,6 +898,20 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
||||
if (D && D->hasAttr<NoProfileFunctionAttr>())
|
||||
Fn->addFnAttr(llvm::Attribute::NoProfile);
|
||||
|
||||
if (D) {
|
||||
// Function attributes take precedence over command line flags.
|
||||
if (auto *A = D->getAttr<FunctionReturnThunksAttr>()) {
|
||||
switch (A->getThunkType()) {
|
||||
case FunctionReturnThunksAttr::Kind::Keep:
|
||||
break;
|
||||
case FunctionReturnThunksAttr::Kind::Extern:
|
||||
Fn->addFnAttr(llvm::Attribute::FnRetThunkExtern);
|
||||
break;
|
||||
}
|
||||
} else if (CGM.getCodeGenOpts().FunctionReturnThunks)
|
||||
Fn->addFnAttr(llvm::Attribute::FnRetThunkExtern);
|
||||
}
|
||||
|
||||
if (FD && (getLangOpts().OpenCL ||
|
||||
(getLangOpts().HIP && getLangOpts().CUDAIsDevice))) {
|
||||
// Add metadata for a kernel function.
|
||||
|
@ -445,6 +445,7 @@ void CodeGenModule::checkAliases() {
|
||||
|
||||
void CodeGenModule::clear() {
|
||||
DeferredDeclsToEmit.clear();
|
||||
EmittedDeferredDecls.clear();
|
||||
if (OpenMPRuntime)
|
||||
OpenMPRuntime->clear();
|
||||
}
|
||||
@ -510,6 +511,9 @@ static void setVisibilityFromDLLStorageClass(const clang::LangOptions &LO,
|
||||
|
||||
void CodeGenModule::Release() {
|
||||
EmitDeferred();
|
||||
DeferredDecls.insert(EmittedDeferredDecls.begin(),
|
||||
EmittedDeferredDecls.end());
|
||||
EmittedDeferredDecls.clear();
|
||||
EmitVTablesOpportunistically();
|
||||
applyGlobalValReplacements();
|
||||
applyReplacements();
|
||||
@ -900,6 +904,9 @@ void CodeGenModule::Release() {
|
||||
if (!getCodeGenOpts().StackProtectorGuardReg.empty())
|
||||
getModule().setStackProtectorGuardReg(
|
||||
getCodeGenOpts().StackProtectorGuardReg);
|
||||
if (!getCodeGenOpts().StackProtectorGuardSymbol.empty())
|
||||
getModule().setStackProtectorGuardSymbol(
|
||||
getCodeGenOpts().StackProtectorGuardSymbol);
|
||||
if (getCodeGenOpts().StackProtectorGuardOffset != INT_MAX)
|
||||
getModule().setStackProtectorGuardOffset(
|
||||
getCodeGenOpts().StackProtectorGuardOffset);
|
||||
@ -4286,6 +4293,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty,
|
||||
getCUDARuntime().handleVarRegistration(D, *GV);
|
||||
}
|
||||
|
||||
if (D)
|
||||
SanitizerMD->reportGlobal(GV, *D);
|
||||
|
||||
LangAS ExpectedAS =
|
||||
D ? D->getType().getAddressSpace()
|
||||
: (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default);
|
||||
|
@ -344,6 +344,20 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
std::vector<GlobalDecl> DeferredDeclsToEmit;
|
||||
void addDeferredDeclToEmit(GlobalDecl GD) {
|
||||
DeferredDeclsToEmit.emplace_back(GD);
|
||||
addEmittedDeferredDecl(GD);
|
||||
}
|
||||
|
||||
/// Decls that were DeferredDecls and have now been emitted.
|
||||
llvm::DenseMap<llvm::StringRef, GlobalDecl> EmittedDeferredDecls;
|
||||
|
||||
void addEmittedDeferredDecl(GlobalDecl GD) {
|
||||
if (!llvm::isa<FunctionDecl>(GD.getDecl()))
|
||||
return;
|
||||
llvm::GlobalVariable::LinkageTypes L = getFunctionLinkage(GD);
|
||||
if (llvm::GlobalValue::isLinkOnceLinkage(L) ||
|
||||
llvm::GlobalValue::isWeakLinkage(L)) {
|
||||
EmittedDeferredDecls[getMangledName(GD)] = GD;
|
||||
}
|
||||
}
|
||||
|
||||
/// List of alias we have emitted. Used to make sure that what they point to
|
||||
@ -1516,6 +1530,11 @@ class CodeGenModule : public CodeGenTypeCache {
|
||||
NewBuilder->WeakRefReferences = std::move(WeakRefReferences);
|
||||
|
||||
NewBuilder->TBAA = std::move(TBAA);
|
||||
|
||||
assert(NewBuilder->EmittedDeferredDecls.empty() &&
|
||||
"Still have (unmerged) EmittedDeferredDecls deferred decls");
|
||||
|
||||
NewBuilder->EmittedDeferredDecls = std::move(EmittedDeferredDecls);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -335,7 +335,42 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
|
||||
if (auto *TTy = dyn_cast<RecordType>(Ty)) {
|
||||
const RecordDecl *RD = TTy->getDecl()->getDefinition();
|
||||
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
|
||||
SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields;
|
||||
using TBAAStructField = llvm::MDBuilder::TBAAStructField;
|
||||
SmallVector<TBAAStructField, 4> Fields;
|
||||
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
// Handle C++ base classes. Non-virtual bases can treated a a kind of
|
||||
// field. Virtual bases are more complex and omitted, but avoid an
|
||||
// incomplete view for NewStructPathTBAA.
|
||||
if (CodeGenOpts.NewStructPathTBAA && CXXRD->getNumVBases() != 0)
|
||||
return BaseTypeMetadataCache[Ty] = nullptr;
|
||||
for (const CXXBaseSpecifier &B : CXXRD->bases()) {
|
||||
if (B.isVirtual())
|
||||
continue;
|
||||
QualType BaseQTy = B.getType();
|
||||
const CXXRecordDecl *BaseRD = BaseQTy->getAsCXXRecordDecl();
|
||||
if (BaseRD->isEmpty())
|
||||
continue;
|
||||
llvm::MDNode *TypeNode = isValidBaseType(BaseQTy)
|
||||
? getBaseTypeInfo(BaseQTy)
|
||||
: getTypeInfo(BaseQTy);
|
||||
if (!TypeNode)
|
||||
return BaseTypeMetadataCache[Ty] = nullptr;
|
||||
uint64_t Offset = Layout.getBaseClassOffset(BaseRD).getQuantity();
|
||||
uint64_t Size =
|
||||
Context.getASTRecordLayout(BaseRD).getDataSize().getQuantity();
|
||||
Fields.push_back(
|
||||
llvm::MDBuilder::TBAAStructField(Offset, Size, TypeNode));
|
||||
}
|
||||
// The order in which base class subobjects are allocated is unspecified,
|
||||
// so may differ from declaration order. In particular, Itanium ABI will
|
||||
// allocate a primary base first.
|
||||
// Since we exclude empty subobjects, the objects are not overlapping and
|
||||
// their offsets are unique.
|
||||
llvm::sort(Fields,
|
||||
[](const TBAAStructField &A, const TBAAStructField &B) {
|
||||
return A.Offset < B.Offset;
|
||||
});
|
||||
}
|
||||
for (FieldDecl *Field : RD->fields()) {
|
||||
if (Field->isZeroSize(Context) || Field->isUnnamedBitfield())
|
||||
continue;
|
||||
|
@ -60,17 +60,17 @@ void SanitizerMetadata::reportGlobal(llvm::GlobalVariable *GV,
|
||||
Meta.NoHWAddress |= CGM.isInNoSanitizeList(
|
||||
FsanitizeArgument.Mask & SanitizerKind::HWAddress, GV, Loc, Ty);
|
||||
|
||||
Meta.NoMemtag |= NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
|
||||
Meta.NoMemtag |= CGM.isInNoSanitizeList(
|
||||
Meta.Memtag |=
|
||||
static_cast<bool>(FsanitizeArgument.Mask & SanitizerKind::MemtagGlobals);
|
||||
Meta.Memtag &= !NoSanitizeAttrSet.hasOneOf(SanitizerKind::MemTag);
|
||||
Meta.Memtag &= !CGM.isInNoSanitizeList(
|
||||
FsanitizeArgument.Mask & SanitizerKind::MemTag, GV, Loc, Ty);
|
||||
|
||||
if (FsanitizeArgument.has(SanitizerKind::Address)) {
|
||||
// TODO(hctim): Make this conditional when we migrate off llvm.asan.globals.
|
||||
IsDynInit &= !CGM.isInNoSanitizeList(SanitizerKind::Address |
|
||||
SanitizerKind::KernelAddress,
|
||||
GV, Loc, Ty, "init");
|
||||
Meta.IsDynInit = IsDynInit;
|
||||
}
|
||||
Meta.IsDynInit = IsDynInit && !Meta.NoAddress &&
|
||||
FsanitizeArgument.has(SanitizerKind::Address) &&
|
||||
!CGM.isInNoSanitizeList(SanitizerKind::Address |
|
||||
SanitizerKind::KernelAddress,
|
||||
GV, Loc, Ty, "init");
|
||||
|
||||
GV->setSanitizerMetadata(Meta);
|
||||
}
|
||||
|
@ -2930,7 +2930,7 @@ class OffloadingActionBuilder final {
|
||||
return false;
|
||||
|
||||
Relocatable = Args.hasFlag(options::OPT_fgpu_rdc,
|
||||
options::OPT_fno_gpu_rdc, /*Default=*/false);
|
||||
options::OPT_fno_gpu_rdc, /*Default=*/false);
|
||||
|
||||
const ToolChain *HostTC = C.getSingleOffloadToolChain<Action::OFK_Host>();
|
||||
assert(HostTC && "No toolchain for host compilation.");
|
||||
@ -3326,7 +3326,7 @@ class OffloadingActionBuilder final {
|
||||
AssociatedOffloadKind);
|
||||
|
||||
if (CompileDeviceOnly && CurPhase == FinalPhase && BundleOutput &&
|
||||
BundleOutput.getValue()) {
|
||||
BundleOutput.value()) {
|
||||
for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) {
|
||||
OffloadAction::DeviceDependences DDep;
|
||||
DDep.add(*CudaDeviceActions[I], *ToolChains.front(), GpuArchList[I],
|
||||
@ -4355,7 +4355,17 @@ Driver::getOffloadArchs(Compilation &C, const llvm::opt::DerivedArgList &Args,
|
||||
return KnownArchs.lookup(TC);
|
||||
|
||||
llvm::DenseSet<StringRef> Archs;
|
||||
for (auto &Arg : Args) {
|
||||
for (auto *Arg : Args) {
|
||||
// Extract any '--[no-]offload-arch' arguments intended for this toolchain.
|
||||
std::unique_ptr<llvm::opt::Arg> ExtractedArg = nullptr;
|
||||
if (Arg->getOption().matches(options::OPT_Xopenmp_target_EQ) &&
|
||||
ToolChain::getOpenMPTriple(Arg->getValue(0)) == TC->getTriple()) {
|
||||
Arg->claim();
|
||||
unsigned Index = Args.getBaseArgs().MakeIndex(Arg->getValue(1));
|
||||
ExtractedArg = getOpts().ParseOneArg(Args, Index);
|
||||
Arg = ExtractedArg.get();
|
||||
}
|
||||
|
||||
if (Arg->getOption().matches(options::OPT_offload_arch_EQ)) {
|
||||
for (StringRef Arch : llvm::split(Arg->getValue(), ","))
|
||||
Archs.insert(getCanonicalArchString(C, Args, Arch, TC->getTriple()));
|
||||
@ -4425,8 +4435,7 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
|
||||
// Get the product of all bound architectures and toolchains.
|
||||
SmallVector<std::pair<const ToolChain *, StringRef>> TCAndArchs;
|
||||
for (const ToolChain *TC : ToolChains)
|
||||
for (StringRef Arch : getOffloadArchs(
|
||||
C, C.getArgsForToolChain(TC, "generic", Kind), Kind, TC))
|
||||
for (StringRef Arch : getOffloadArchs(C, Args, Kind, TC))
|
||||
TCAndArchs.push_back(std::make_pair(TC, Arch));
|
||||
|
||||
for (unsigned I = 0, E = TCAndArchs.size(); I != E; ++I)
|
||||
@ -4477,11 +4486,23 @@ Action *Driver::BuildOffloadingActions(Compilation &C,
|
||||
if (offloadDeviceOnly())
|
||||
return C.MakeAction<OffloadAction>(DDeps, types::TY_Nothing);
|
||||
|
||||
Action *OffloadPackager =
|
||||
C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
|
||||
OffloadAction::DeviceDependences DDep;
|
||||
DDep.add(*OffloadPackager, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
|
||||
nullptr, Action::OFK_None);
|
||||
if (C.isOffloadingHostKind(Action::OFK_Cuda) &&
|
||||
!Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false)) {
|
||||
// If we are not in RDC-mode we just emit the final CUDA fatbinary for each
|
||||
// translation unit without requiring any linking.
|
||||
Action *FatbinAction =
|
||||
C.MakeAction<LinkJobAction>(OffloadActions, types::TY_CUDA_FATBIN);
|
||||
DDep.add(*FatbinAction, *C.getSingleOffloadToolChain<Action::OFK_Cuda>(),
|
||||
nullptr, Action::OFK_Cuda);
|
||||
} else {
|
||||
// Package all the offloading actions into a single output that can be
|
||||
// embedded in the host and linked.
|
||||
Action *PackagerAction =
|
||||
C.MakeAction<OffloadPackagerJobAction>(OffloadActions, types::TY_Image);
|
||||
DDep.add(*PackagerAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
|
||||
nullptr, Action::OFK_None);
|
||||
}
|
||||
OffloadAction::HostDependence HDep(
|
||||
*HostAction, *C.getSingleOffloadToolChain<Action::OFK_Host>(),
|
||||
/*BoundArch=*/nullptr, isa<CompileJobAction>(HostAction) ? DDep : DDeps);
|
||||
|
@ -437,7 +437,6 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
: getToolChain().GetProgramPath(getShortName());
|
||||
|
||||
ArgStringList CmdArgs;
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
||||
|
||||
CmdArgs.push_back("-o");
|
||||
CmdArgs.push_back(Output.getFilename());
|
||||
@ -476,8 +475,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
if (SectionAddressData) {
|
||||
std::string DataSectionArg = std::string("-Tdata=0x") +
|
||||
llvm::utohexstr(SectionAddressData.getValue());
|
||||
std::string DataSectionArg =
|
||||
std::string("-Tdata=0x") + llvm::utohexstr(SectionAddressData.value());
|
||||
CmdArgs.push_back(Args.MakeArgString(DataSectionArg));
|
||||
} else {
|
||||
// We do not have an entry for this CPU in the address mapping table yet.
|
||||
@ -503,6 +502,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
// Add the link library specific to the MCU.
|
||||
CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU));
|
||||
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
||||
CmdArgs.push_back("--end-group");
|
||||
|
||||
// Add user specified linker script.
|
||||
@ -514,6 +514,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
// than the bare minimum supports.
|
||||
if (Linker.find("avr-ld") != std::string::npos)
|
||||
CmdArgs.push_back(Args.MakeArgString(std::string("-m") + *FamilyName));
|
||||
} else {
|
||||
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
|
||||
}
|
||||
|
||||
C.addCommand(std::make_unique<Command>(
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "clang/Basic/CharInfo.h"
|
||||
#include "clang/Basic/CodeGenOptions.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/MakeSupport.h"
|
||||
#include "clang/Basic/ObjCRuntime.h"
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Config/config.h"
|
||||
@ -51,6 +52,7 @@
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/TargetParser.h"
|
||||
#include "llvm/Support/YAMLParser.h"
|
||||
#include <cctype>
|
||||
|
||||
using namespace clang::driver;
|
||||
using namespace clang::driver::tools;
|
||||
@ -97,34 +99,6 @@ static void EscapeSpacesAndBackslashes(const char *Arg,
|
||||
}
|
||||
}
|
||||
|
||||
// Quote target names for inclusion in GNU Make dependency files.
|
||||
// Only the characters '$', '#', ' ', '\t' are quoted.
|
||||
static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) {
|
||||
for (unsigned i = 0, e = Target.size(); i != e; ++i) {
|
||||
switch (Target[i]) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
// Escape the preceding backslashes
|
||||
for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j)
|
||||
Res.push_back('\\');
|
||||
|
||||
// Escape the space/tab
|
||||
Res.push_back('\\');
|
||||
break;
|
||||
case '$':
|
||||
Res.push_back('$');
|
||||
break;
|
||||
case '#':
|
||||
Res.push_back('\\');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Res.push_back(Target[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply \a Work on the current tool chain \a RegularToolChain and any other
|
||||
/// offloading tool chain that is associated with the current action \a JA.
|
||||
static void
|
||||
@ -567,7 +541,7 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args,
|
||||
break;
|
||||
}
|
||||
|
||||
if (Triple.isOSNetBSD()) {
|
||||
if (Triple.isOSFuchsia() || Triple.isOSNetBSD()) {
|
||||
return !areOptimizationsEnabled(Args);
|
||||
}
|
||||
|
||||
@ -1144,7 +1118,7 @@ static void RenderDebugInfoCompressionArgs(const ArgList &Args,
|
||||
if (Value == "none") {
|
||||
CmdArgs.push_back("--compress-debug-sections=none");
|
||||
} else if (Value == "zlib") {
|
||||
if (llvm::zlib::isAvailable()) {
|
||||
if (llvm::compression::zlib::isAvailable()) {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
|
||||
} else {
|
||||
@ -1249,7 +1223,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
|
||||
} else {
|
||||
CmdArgs.push_back("-MT");
|
||||
SmallString<128> Quoted;
|
||||
QuoteTarget(A->getValue(), Quoted);
|
||||
quoteMakeTarget(A->getValue(), Quoted);
|
||||
CmdArgs.push_back(Args.MakeArgString(Quoted));
|
||||
}
|
||||
}
|
||||
@ -1274,7 +1248,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
|
||||
|
||||
CmdArgs.push_back("-MT");
|
||||
SmallString<128> Quoted;
|
||||
QuoteTarget(DepTarget, Quoted);
|
||||
quoteMakeTarget(DepTarget, Quoted);
|
||||
CmdArgs.push_back(Args.MakeArgString(Quoted));
|
||||
}
|
||||
|
||||
@ -2228,8 +2202,23 @@ void Clang::AddSparcTargetArgs(const ArgList &Args,
|
||||
|
||||
void Clang::AddSystemZTargetArgs(const ArgList &Args,
|
||||
ArgStringList &CmdArgs) const {
|
||||
bool HasBackchain = Args.hasFlag(options::OPT_mbackchain,
|
||||
options::OPT_mno_backchain, false);
|
||||
if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) {
|
||||
StringRef Name = A->getValue();
|
||||
|
||||
std::string TuneCPU;
|
||||
if (Name == "native")
|
||||
TuneCPU = std::string(llvm::sys::getHostCPUName());
|
||||
else
|
||||
TuneCPU = std::string(Name);
|
||||
|
||||
if (!TuneCPU.empty()) {
|
||||
CmdArgs.push_back("-tune-cpu");
|
||||
CmdArgs.push_back(Args.MakeArgString(TuneCPU));
|
||||
}
|
||||
}
|
||||
|
||||
bool HasBackchain =
|
||||
Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false);
|
||||
bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack,
|
||||
options::OPT_mno_packed_stack, false);
|
||||
systemz::FloatABI FloatABI =
|
||||
@ -2341,7 +2330,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args,
|
||||
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
|
||||
CmdArgs.push_back("-mllvm");
|
||||
CmdArgs.push_back(Args.MakeArgString("-hexagon-small-data-threshold=" +
|
||||
Twine(G.getValue())));
|
||||
Twine(G.value())));
|
||||
}
|
||||
|
||||
if (!Args.hasArg(options::OPT_fno_short_enums))
|
||||
@ -3231,6 +3220,16 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs,
|
||||
Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer);
|
||||
}
|
||||
|
||||
static bool isValidSymbolName(StringRef S) {
|
||||
if (S.empty())
|
||||
return false;
|
||||
|
||||
if (std::isdigit(S[0]))
|
||||
return false;
|
||||
|
||||
return llvm::all_of(S, [](char C) { return std::isalnum(C) || C == '_'; });
|
||||
}
|
||||
|
||||
static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
|
||||
const ArgList &Args, ArgStringList &CmdArgs,
|
||||
bool KernelOrKext) {
|
||||
@ -3362,6 +3361,16 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC,
|
||||
}
|
||||
A->render(Args, CmdArgs);
|
||||
}
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_symbol_EQ)) {
|
||||
StringRef Value = A->getValue();
|
||||
if (!isValidSymbolName(Value)) {
|
||||
D.Diag(diag::err_drv_argument_only_allowed_with)
|
||||
<< A->getOption().getName() << "legal symbol name";
|
||||
return;
|
||||
}
|
||||
A->render(Args, CmdArgs);
|
||||
}
|
||||
}
|
||||
|
||||
static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args,
|
||||
@ -3750,38 +3759,49 @@ static void RenderModulesOptions(Compilation &C, const Driver &D,
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after);
|
||||
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
|
||||
if (HaveClangModules) {
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp);
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
|
||||
if (Args.hasArg(options::OPT_fbuild_session_timestamp))
|
||||
D.Diag(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getAsString(Args) << "-fbuild-session-timestamp";
|
||||
if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) {
|
||||
if (Args.hasArg(options::OPT_fbuild_session_timestamp))
|
||||
D.Diag(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getAsString(Args) << "-fbuild-session-timestamp";
|
||||
|
||||
llvm::sys::fs::file_status Status;
|
||||
if (llvm::sys::fs::status(A->getValue(), Status))
|
||||
D.Diag(diag::err_drv_no_such_file) << A->getValue();
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"-fbuild-session-timestamp=" +
|
||||
Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
|
||||
Status.getLastModificationTime().time_since_epoch())
|
||||
.count())));
|
||||
}
|
||||
llvm::sys::fs::file_status Status;
|
||||
if (llvm::sys::fs::status(A->getValue(), Status))
|
||||
D.Diag(diag::err_drv_no_such_file) << A->getValue();
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"-fbuild-session-timestamp=" +
|
||||
Twine((uint64_t)std::chrono::duration_cast<std::chrono::seconds>(
|
||||
Status.getLastModificationTime().time_since_epoch())
|
||||
.count())));
|
||||
}
|
||||
|
||||
if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) {
|
||||
if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
|
||||
options::OPT_fbuild_session_file))
|
||||
D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
|
||||
if (Args.getLastArg(
|
||||
options::OPT_fmodules_validate_once_per_build_session)) {
|
||||
if (!Args.getLastArg(options::OPT_fbuild_session_timestamp,
|
||||
options::OPT_fbuild_session_file))
|
||||
D.Diag(diag::err_drv_modules_validate_once_requires_timestamp);
|
||||
|
||||
Args.AddLastArg(CmdArgs,
|
||||
options::OPT_fmodules_validate_once_per_build_session);
|
||||
}
|
||||
|
||||
if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
|
||||
options::OPT_fno_modules_validate_system_headers,
|
||||
ImplicitModules))
|
||||
CmdArgs.push_back("-fmodules-validate-system-headers");
|
||||
|
||||
Args.AddLastArg(CmdArgs,
|
||||
options::OPT_fmodules_validate_once_per_build_session);
|
||||
options::OPT_fmodules_disable_diagnostic_validation);
|
||||
} else {
|
||||
Args.ClaimAllArgs(options::OPT_fbuild_session_timestamp);
|
||||
Args.ClaimAllArgs(options::OPT_fbuild_session_file);
|
||||
Args.ClaimAllArgs(options::OPT_fmodules_validate_once_per_build_session);
|
||||
Args.ClaimAllArgs(options::OPT_fmodules_validate_system_headers);
|
||||
Args.ClaimAllArgs(options::OPT_fno_modules_validate_system_headers);
|
||||
Args.ClaimAllArgs(options::OPT_fmodules_disable_diagnostic_validation);
|
||||
}
|
||||
|
||||
if (Args.hasFlag(options::OPT_fmodules_validate_system_headers,
|
||||
options::OPT_fno_modules_validate_system_headers,
|
||||
ImplicitModules))
|
||||
CmdArgs.push_back("-fmodules-validate-system-headers");
|
||||
|
||||
Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation);
|
||||
}
|
||||
|
||||
static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T,
|
||||
@ -4422,12 +4442,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
Args.hasFlag(options::OPT_offload_new_driver,
|
||||
options::OPT_no_offload_new_driver, false));
|
||||
|
||||
bool IsRDCMode =
|
||||
Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false);
|
||||
bool IsUsingLTO = D.isUsingLTO(IsDeviceOffloadAction);
|
||||
auto LTOMode = D.getLTOMode(IsDeviceOffloadAction);
|
||||
|
||||
// A header module compilation doesn't have a main input file, so invent a
|
||||
// fake one as a placeholder.
|
||||
const char *ModuleName = [&]{
|
||||
const char *ModuleName = [&] {
|
||||
auto *ModuleNameArg = Args.getLastArg(options::OPT_fmodule_name_EQ);
|
||||
return ModuleNameArg ? ModuleNameArg->getValue() : "";
|
||||
}();
|
||||
@ -6285,10 +6307,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
if (IsCuda || IsHIP) {
|
||||
if (!Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false) &&
|
||||
Args.hasArg(options::OPT_offload_new_driver))
|
||||
D.Diag(diag::err_drv_no_rdc_new_driver);
|
||||
if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
|
||||
if (IsRDCMode)
|
||||
CmdArgs.push_back("-fgpu-rdc");
|
||||
if (Args.hasFlag(options::OPT_fgpu_defer_diag,
|
||||
options::OPT_fno_gpu_defer_diag, false))
|
||||
@ -6313,6 +6332,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (IsUsingLTO)
|
||||
Args.AddLastArg(CmdArgs, options::OPT_mibt_seal);
|
||||
|
||||
if (Arg *A = Args.getLastArg(options::OPT_mfunction_return_EQ))
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-mfunction-return=") + A->getValue()));
|
||||
|
||||
// Forward -f options with positive and negative forms; we translate these by
|
||||
// hand. Do not propagate PGO options to the GPU-side compilations as the
|
||||
// profile info is for the host-side compilation only.
|
||||
@ -6956,13 +6979,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
}
|
||||
|
||||
// Host-side cuda compilation receives all device-side outputs in a single
|
||||
// fatbin as Inputs[1]. Include the binary with -fcuda-include-gpubinary.
|
||||
// Host-side offloading compilation receives all device-side outputs. Include
|
||||
// them in the host compilation depending on the target. If the host inputs
|
||||
// are not empty we use the new-driver scheme, otherwise use the old scheme.
|
||||
if ((IsCuda || IsHIP) && CudaDeviceInput) {
|
||||
CmdArgs.push_back("-fcuda-include-gpubinary");
|
||||
CmdArgs.push_back(CudaDeviceInput->getFilename());
|
||||
} else if (!HostOffloadingInputs.empty()) {
|
||||
if (IsCuda && !IsRDCMode) {
|
||||
assert(HostOffloadingInputs.size() == 1 && "Only one input expected");
|
||||
CmdArgs.push_back("-fcuda-include-gpubinary");
|
||||
CmdArgs.push_back(CudaDeviceInput->getFilename());
|
||||
if (Args.hasFlag(options::OPT_fgpu_rdc, options::OPT_fno_gpu_rdc, false))
|
||||
CmdArgs.push_back("-fgpu-rdc");
|
||||
CmdArgs.push_back(HostOffloadingInputs.front().getFilename());
|
||||
} else {
|
||||
for (const InputInfo Input : HostOffloadingInputs)
|
||||
CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" +
|
||||
TC.getInputFilename(Input)));
|
||||
}
|
||||
}
|
||||
|
||||
if (IsCuda) {
|
||||
@ -7011,12 +7043,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
}
|
||||
|
||||
// Host-side offloading recieves the device object files and embeds it in a
|
||||
// named section including the associated target triple and architecture.
|
||||
for (const InputInfo Input : HostOffloadingInputs)
|
||||
CmdArgs.push_back(Args.MakeArgString("-fembed-offload-object=" +
|
||||
TC.getInputFilename(Input)));
|
||||
|
||||
if (Triple.isAMDGPU()) {
|
||||
handleAMDGPUCodeObjectVersionOptions(D, Args, CmdArgs);
|
||||
|
||||
@ -8314,7 +8340,8 @@ void OffloadPackager::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
ArgStringList Features;
|
||||
SmallVector<StringRef> FeatureArgs;
|
||||
getTargetFeatures(TC->getDriver(), TC->getTriple(), Args, Features, false);
|
||||
getTargetFeatures(TC->getDriver(), TC->getTriple(), TCArgs, Features,
|
||||
false);
|
||||
llvm::copy_if(Features, std::back_inserter(FeatureArgs),
|
||||
[](StringRef Arg) { return !Arg.startswith("-target"); });
|
||||
|
||||
@ -8382,7 +8409,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
for (StringRef LibName : BCLibs)
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"-target-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) +
|
||||
"--bitcode-library=" + Action::GetOffloadKindName(Action::OFK_OpenMP) +
|
||||
"-" + TC->getTripleString() + "-" + Arch + "=" + LibName));
|
||||
}
|
||||
|
||||
@ -8402,63 +8429,64 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
} else if (A->getOption().matches(options::OPT_O0))
|
||||
OOpt = "0";
|
||||
if (!OOpt.empty())
|
||||
CmdArgs.push_back(Args.MakeArgString(Twine("-opt-level=O") + OOpt));
|
||||
CmdArgs.push_back(Args.MakeArgString(Twine("--opt-level=O") + OOpt));
|
||||
}
|
||||
}
|
||||
|
||||
CmdArgs.push_back("-host-triple");
|
||||
CmdArgs.push_back(Args.MakeArgString(TheTriple.getTriple()));
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString("--host-triple=" + TheTriple.getTriple()));
|
||||
if (Args.hasArg(options::OPT_v))
|
||||
CmdArgs.push_back("-v");
|
||||
CmdArgs.push_back("--verbose");
|
||||
|
||||
// Add debug information if present.
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) {
|
||||
const Option &Opt = A->getOption();
|
||||
if (Opt.matches(options::OPT_gN_Group)) {
|
||||
if (Opt.matches(options::OPT_gline_directives_only) ||
|
||||
Opt.matches(options::OPT_gline_tables_only))
|
||||
CmdArgs.push_back("-gline-directives-only");
|
||||
} else
|
||||
CmdArgs.push_back("-g");
|
||||
if (!A->getOption().matches(options::OPT_g0))
|
||||
CmdArgs.push_back("--device-debug");
|
||||
}
|
||||
|
||||
for (const auto &A : Args.getAllArgValues(options::OPT_Xcuda_ptxas))
|
||||
CmdArgs.push_back(Args.MakeArgString("-ptxas-args=" + A));
|
||||
CmdArgs.push_back(Args.MakeArgString("--ptxas-args=" + A));
|
||||
|
||||
// Forward remarks passes to the LLVM backend in the wrapper.
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_EQ))
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-pass-remarks=") + A->getValue()));
|
||||
Args.MakeArgString(Twine("--pass-remarks=") + A->getValue()));
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_missed_EQ))
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-pass-remarks-missed=") + A->getValue()));
|
||||
Args.MakeArgString(Twine("--pass-remarks-missed=") + A->getValue()));
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_Rpass_analysis_EQ))
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-pass-remarks-analysis=") + A->getValue()));
|
||||
Args.MakeArgString(Twine("--pass-remarks-analysis=") + A->getValue()));
|
||||
if (Args.getLastArg(options::OPT_save_temps_EQ))
|
||||
CmdArgs.push_back("-save-temps");
|
||||
CmdArgs.push_back("--save-temps");
|
||||
|
||||
// Construct the link job so we can wrap around it.
|
||||
Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput);
|
||||
const auto &LinkCommand = C.getJobs().getJobs().back();
|
||||
|
||||
// Forward -Xoffload-linker<-triple> arguments to the device link job.
|
||||
for (auto *Arg : Args.filtered(options::OPT_Xoffload_linker)) {
|
||||
StringRef Val = Arg->getValue(0);
|
||||
for (Arg *A : Args.filtered(options::OPT_Xoffload_linker)) {
|
||||
StringRef Val = A->getValue(0);
|
||||
if (Val.empty())
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(Twine("-device-linker=") + Arg->getValue(1)));
|
||||
Args.MakeArgString(Twine("--device-linker=") + A->getValue(1)));
|
||||
else
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"-device-linker=" +
|
||||
"--device-linker=" +
|
||||
ToolChain::getOpenMPTriple(Val.drop_front()).getTriple() + "=" +
|
||||
Arg->getValue(1)));
|
||||
A->getValue(1)));
|
||||
}
|
||||
Args.ClaimAllArgs(options::OPT_Xoffload_linker);
|
||||
|
||||
// Forward `-mllvm` arguments to the LLVM invocations if present.
|
||||
for (Arg *A : Args.filtered(options::OPT_mllvm)) {
|
||||
CmdArgs.push_back("-mllvm");
|
||||
CmdArgs.push_back(A->getValue());
|
||||
A->claim();
|
||||
}
|
||||
|
||||
// Add the linker arguments to be forwarded by the wrapper.
|
||||
CmdArgs.push_back("-linker-path");
|
||||
CmdArgs.push_back(LinkCommand->getExecutable());
|
||||
CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") +
|
||||
LinkCommand->getExecutable()));
|
||||
CmdArgs.push_back("--");
|
||||
for (const char *LinkArg : LinkCommand->getArguments())
|
||||
CmdArgs.push_back(LinkArg);
|
||||
|
@ -727,7 +727,8 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC,
|
||||
if (IsOffloadingHost)
|
||||
CmdArgs.push_back("-lomptarget");
|
||||
|
||||
if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true))
|
||||
if (IsOffloadingHost && TC.getDriver().isUsingLTO(/* IsOffload */ true) &&
|
||||
!Args.hasArg(options::OPT_nogpulib))
|
||||
CmdArgs.push_back("-lomptarget.devicertl");
|
||||
|
||||
addArchSpecificRPath(TC, Args, CmdArgs);
|
||||
|
@ -1551,10 +1551,10 @@ struct DarwinPlatform {
|
||||
options::ID Opt;
|
||||
switch (Platform) {
|
||||
case DarwinPlatformKind::MacOS:
|
||||
Opt = options::OPT_mmacosx_version_min_EQ;
|
||||
Opt = options::OPT_mmacos_version_min_EQ;
|
||||
break;
|
||||
case DarwinPlatformKind::IPhoneOS:
|
||||
Opt = options::OPT_miphoneos_version_min_EQ;
|
||||
Opt = options::OPT_mios_version_min_EQ;
|
||||
break;
|
||||
case DarwinPlatformKind::TvOS:
|
||||
Opt = options::OPT_mtvos_version_min_EQ;
|
||||
@ -1727,8 +1727,8 @@ struct DarwinPlatform {
|
||||
Optional<DarwinPlatform>
|
||||
getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
|
||||
const Driver &TheDriver) {
|
||||
Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ);
|
||||
Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ,
|
||||
Arg *macOSVersion = Args.getLastArg(options::OPT_mmacos_version_min_EQ);
|
||||
Arg *iOSVersion = Args.getLastArg(options::OPT_mios_version_min_EQ,
|
||||
options::OPT_mios_simulator_version_min_EQ);
|
||||
Arg *TvOSVersion =
|
||||
Args.getLastArg(options::OPT_mtvos_version_min_EQ,
|
||||
@ -1736,15 +1736,15 @@ getDeploymentTargetFromOSVersionArg(DerivedArgList &Args,
|
||||
Arg *WatchOSVersion =
|
||||
Args.getLastArg(options::OPT_mwatchos_version_min_EQ,
|
||||
options::OPT_mwatchos_simulator_version_min_EQ);
|
||||
if (OSXVersion) {
|
||||
if (macOSVersion) {
|
||||
if (iOSVersion || TvOSVersion || WatchOSVersion) {
|
||||
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
|
||||
<< OSXVersion->getAsString(Args)
|
||||
<< macOSVersion->getAsString(Args)
|
||||
<< (iOSVersion ? iOSVersion
|
||||
: TvOSVersion ? TvOSVersion : WatchOSVersion)
|
||||
->getAsString(Args);
|
||||
}
|
||||
return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion);
|
||||
return DarwinPlatform::createOSVersionArg(Darwin::MacOS, macOSVersion);
|
||||
} else if (iOSVersion) {
|
||||
if (TvOSVersion || WatchOSVersion) {
|
||||
TheDriver.Diag(diag::err_drv_argument_not_allowed_with)
|
||||
|
@ -2087,7 +2087,7 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
|
||||
|
||||
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
|
||||
if (BiarchSibling) {
|
||||
M = BiarchSibling.getValue();
|
||||
M = BiarchSibling.value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -340,8 +340,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back("-pie");
|
||||
|
||||
if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) {
|
||||
CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.getValue())));
|
||||
UseG0 = G.getValue() == 0;
|
||||
CmdArgs.push_back(Args.MakeArgString("-G" + Twine(G.value())));
|
||||
UseG0 = G.value() == 0;
|
||||
}
|
||||
|
||||
CmdArgs.push_back("-o");
|
||||
|
@ -339,8 +339,9 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
|
||||
static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
|
||||
std::string &Ver) {
|
||||
auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
|
||||
std::string &Ver,
|
||||
toolchains::Generic_GCC::GCCVersion &Version) {
|
||||
Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0");
|
||||
std::error_code EC;
|
||||
for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
|
||||
LI = LI.increment(EC)) {
|
||||
@ -371,7 +372,7 @@ void toolchains::MinGW::findGccLibDir() {
|
||||
for (StringRef CandidateSysroot : SubdirNames) {
|
||||
llvm::SmallString<1024> LibDir(Base);
|
||||
llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot);
|
||||
if (findGccVersion(LibDir, GccLibDir, Ver)) {
|
||||
if (findGccVersion(LibDir, GccLibDir, Ver, GccVer)) {
|
||||
SubdirName = std::string(CandidateSysroot);
|
||||
return;
|
||||
}
|
||||
@ -438,6 +439,11 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple,
|
||||
getFilePaths().push_back(GccLibDir);
|
||||
getFilePaths().push_back(
|
||||
(Base + SubdirName + llvm::sys::path::get_separator() + "lib").str());
|
||||
|
||||
// Gentoo
|
||||
getFilePaths().push_back(
|
||||
(Base + SubdirName + llvm::sys::path::get_separator() + "mingw/lib").str());
|
||||
|
||||
getFilePaths().push_back(Base + "lib");
|
||||
// openSUSE
|
||||
getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib");
|
||||
@ -593,6 +599,11 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
addSystemInclude(DriverArgs, CC1Args,
|
||||
Base + SubdirName + llvm::sys::path::get_separator() +
|
||||
"include");
|
||||
|
||||
// Gentoo
|
||||
addSystemInclude(DriverArgs, CC1Args,
|
||||
Base + SubdirName + llvm::sys::path::get_separator() + "usr/include");
|
||||
|
||||
addSystemInclude(DriverArgs, CC1Args, Base + "include");
|
||||
}
|
||||
|
||||
@ -620,7 +631,7 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
|
||||
}
|
||||
|
||||
case ToolChain::CST_Libstdcxx:
|
||||
llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
|
||||
llvm::SmallVector<llvm::SmallString<1024>, 7> CppIncludeBases;
|
||||
CppIncludeBases.emplace_back(Base);
|
||||
llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++");
|
||||
CppIncludeBases.emplace_back(Base);
|
||||
@ -630,6 +641,15 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs(
|
||||
llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
|
||||
CppIncludeBases.emplace_back(GccLibDir);
|
||||
llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
|
||||
CppIncludeBases.emplace_back(GccLibDir);
|
||||
llvm::sys::path::append(CppIncludeBases[4], "include",
|
||||
"g++-v" + GccVer.Text);
|
||||
CppIncludeBases.emplace_back(GccLibDir);
|
||||
llvm::sys::path::append(CppIncludeBases[5], "include",
|
||||
"g++-v" + GccVer.MajorStr + "." + GccVer.MinorStr);
|
||||
CppIncludeBases.emplace_back(GccLibDir);
|
||||
llvm::sys::path::append(CppIncludeBases[6], "include",
|
||||
"g++-v" + GccVer.MajorStr);
|
||||
for (auto &CppIncludeBase : CppIncludeBases) {
|
||||
addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
|
||||
CppIncludeBase += Slash;
|
||||
|
@ -103,6 +103,7 @@ class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain {
|
||||
|
||||
std::string Base;
|
||||
std::string GccLibDir;
|
||||
clang::driver::toolchains::Generic_GCC::GCCVersion GccVer;
|
||||
std::string Ver;
|
||||
std::string SubdirName;
|
||||
mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor;
|
||||
|
@ -201,8 +201,11 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nodefaultlibs)) {
|
||||
if (ToolChain.ShouldLinkCXXStdlib(Args))
|
||||
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
if (D.CCCIsCXX()) {
|
||||
if (ToolChain.ShouldLinkCXXStdlib(Args))
|
||||
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
||||
CmdArgs.push_back("-lm");
|
||||
}
|
||||
CmdArgs.push_back("--start-group");
|
||||
CmdArgs.push_back("-lc");
|
||||
CmdArgs.push_back("-lgloss");
|
||||
|
@ -31,14 +31,14 @@ namespace {
|
||||
/// at position \p Key.
|
||||
void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
|
||||
if (Obj)
|
||||
Paren[Key] = std::move(Obj.getValue());
|
||||
Paren[Key] = std::move(Obj.value());
|
||||
}
|
||||
|
||||
/// Helper function to inject a JSON array \p Array into object \p Paren at
|
||||
/// position \p Key.
|
||||
void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
|
||||
if (Array)
|
||||
Paren[Key] = std::move(Array.getValue());
|
||||
Paren[Key] = std::move(Array.value());
|
||||
}
|
||||
|
||||
/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
|
||||
|
@ -37,7 +37,7 @@ static bool shouldIndentWrappedSelectorName(const FormatStyle &Style,
|
||||
// Returns the length of everything up to the first possible line break after
|
||||
// the ), ], } or > matching \c Tok.
|
||||
static unsigned getLengthToMatchingParen(const FormatToken &Tok,
|
||||
const std::vector<ParenState> &Stack) {
|
||||
const SmallVector<ParenState> &Stack) {
|
||||
// Normally whether or not a break before T is possible is calculated and
|
||||
// stored in T.CanBreakBefore. Braces, array initializers and text proto
|
||||
// messages like `key: < ... >` are an exception: a break is possible
|
||||
@ -404,6 +404,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
|
||||
(State.Column + State.Line->Last->TotalLength - Previous.TotalLength >
|
||||
getColumnLimit(State) ||
|
||||
CurrentState.BreakBeforeParameter) &&
|
||||
(!Current.isTrailingComment() || Current.NewlinesBefore > 0) &&
|
||||
(Style.AllowShortFunctionsOnASingleLine != FormatStyle::SFS_All ||
|
||||
Style.BreakConstructorInitializers != FormatStyle::BCIS_BeforeColon ||
|
||||
Style.ColumnLimit != 0)) {
|
||||
@ -793,6 +794,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
|
||||
(Previous.is(tok::colon) && Previous.is(TT_ObjCMethodExpr)))) {
|
||||
CurrentState.LastSpace = State.Column;
|
||||
} else if (Previous.is(TT_CtorInitializerColon) &&
|
||||
(!Current.isTrailingComment() || Current.NewlinesBefore > 0) &&
|
||||
Style.BreakConstructorInitializers ==
|
||||
FormatStyle::BCIS_AfterColon) {
|
||||
CurrentState.Indent = State.Column;
|
||||
@ -1032,7 +1034,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
|
||||
// be considered bin packing unless the relevant AllowAll option is false or
|
||||
// this is a dict/object literal.
|
||||
bool PreviousIsBreakingCtorInitializerColon =
|
||||
Previous.is(TT_CtorInitializerColon) &&
|
||||
PreviousNonComment && PreviousNonComment->is(TT_CtorInitializerColon) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
|
||||
if (!(Previous.isOneOf(tok::l_paren, tok::l_brace, TT_BinaryOperator) ||
|
||||
PreviousIsBreakingCtorInitializerColon) ||
|
||||
|
@ -434,7 +434,7 @@ struct LineState {
|
||||
|
||||
/// A stack keeping track of properties applying to parenthesis
|
||||
/// levels.
|
||||
std::vector<ParenState> Stack;
|
||||
SmallVector<ParenState> Stack;
|
||||
|
||||
/// Ignore the stack of \c ParenStates for state comparison.
|
||||
///
|
||||
|
@ -2386,7 +2386,7 @@ class Cleaner : public TokenAnalyzer {
|
||||
|
||||
tooling::Replacements generateFixes() {
|
||||
tooling::Replacements Fixes;
|
||||
std::vector<FormatToken *> Tokens;
|
||||
SmallVector<FormatToken *> Tokens;
|
||||
std::copy(DeletedTokens.begin(), DeletedTokens.end(),
|
||||
std::back_inserter(Tokens));
|
||||
|
||||
@ -2580,7 +2580,7 @@ struct JavaImportDirective {
|
||||
StringRef Identifier;
|
||||
StringRef Text;
|
||||
unsigned Offset;
|
||||
std::vector<StringRef> AssociatedCommentLines;
|
||||
SmallVector<StringRef> AssociatedCommentLines;
|
||||
bool IsStatic;
|
||||
};
|
||||
|
||||
@ -2983,7 +2983,7 @@ tooling::Replacements sortJavaImports(const FormatStyle &Style, StringRef Code,
|
||||
llvm::Regex ImportRegex(JavaImportRegexPattern);
|
||||
SmallVector<StringRef, 4> Matches;
|
||||
SmallVector<JavaImportDirective, 16> ImportsInBlock;
|
||||
std::vector<StringRef> AssociatedCommentLines;
|
||||
SmallVector<StringRef> AssociatedCommentLines;
|
||||
|
||||
bool FormattingOff = false;
|
||||
|
||||
@ -3433,17 +3433,19 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
|
||||
}
|
||||
|
||||
const char *StyleOptionHelpDescription =
|
||||
"Coding style, currently supports:\n"
|
||||
" LLVM, GNU, Google, Chromium, Microsoft, Mozilla, WebKit.\n"
|
||||
"Use -style=file to load style configuration from\n"
|
||||
".clang-format file located in one of the parent\n"
|
||||
"directories of the source file (or current\n"
|
||||
"directory for stdin).\n"
|
||||
"Use -style=file:<format_file_path> to explicitly specify\n"
|
||||
"the configuration file.\n"
|
||||
"Use -style=\"{key: value, ...}\" to set specific\n"
|
||||
"parameters, e.g.:\n"
|
||||
" -style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
|
||||
"Set coding style. <string> can be:\n"
|
||||
"1. A preset: LLVM, GNU, Google, Chromium, Microsoft,\n"
|
||||
" Mozilla, WebKit.\n"
|
||||
"2. 'file' to load style configuration from a\n"
|
||||
" .clang-format file in one of the parent directories\n"
|
||||
" of the source file (for stdin, see --assume-filename).\n"
|
||||
" If no .clang-format file is found, falls back to\n"
|
||||
" --fallback-style.\n"
|
||||
" --style=file is the default.\n"
|
||||
"3. 'file:<format_file_path>' to explicitly specify\n"
|
||||
" the configuration file.\n"
|
||||
"4. \"{key: value, ...}\" to set specific parameters, e.g.:\n"
|
||||
" --style=\"{BasedOnStyle: llvm, IndentWidth: 8}\"";
|
||||
|
||||
static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) {
|
||||
if (FileName.endswith(".java"))
|
||||
@ -3498,6 +3500,7 @@ FormatStyle::LanguageKind guessLanguage(StringRef FileName, StringRef Code) {
|
||||
return GuessedLanguage;
|
||||
}
|
||||
|
||||
// Update StyleOptionHelpDescription above when changing this.
|
||||
const char *DefaultFormatStyle = "file";
|
||||
|
||||
const char *DefaultFallbackStyle = "LLVM";
|
||||
|
@ -264,7 +264,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
|
||||
// We can never place more than ColumnLimit / 3 items in a row (because of the
|
||||
// spaces and the comma).
|
||||
unsigned MaxItems = Style.ColumnLimit / 3;
|
||||
std::vector<unsigned> MinSizeInColumn;
|
||||
SmallVector<unsigned> MinSizeInColumn;
|
||||
MinSizeInColumn.reserve(MaxItems);
|
||||
for (unsigned Columns = 1; Columns <= MaxItems; ++Columns) {
|
||||
ColumnFormat Format;
|
||||
|
@ -497,6 +497,15 @@ struct FormatToken {
|
||||
// in a configured macro expansion.
|
||||
llvm::Optional<MacroExpansion> MacroCtx;
|
||||
|
||||
/// When macro expansion introduces nodes with children, those are marked as
|
||||
/// \c MacroParent.
|
||||
/// FIXME: The formatting code currently hard-codes the assumption that
|
||||
/// child nodes are introduced by blocks following an opening brace.
|
||||
/// This is deeply baked into the code and disentangling this will require
|
||||
/// signficant refactorings. \c MacroParent allows us to special-case the
|
||||
/// cases in which we treat parents as block-openers for now.
|
||||
bool MacroParent = false;
|
||||
|
||||
bool is(tok::TokenKind Kind) const { return Tok.is(Kind); }
|
||||
bool is(TokenType TT) const { return getType() == TT; }
|
||||
bool is(const IdentifierInfo *II) const {
|
||||
|
573
contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp
Normal file
573
contrib/llvm-project/clang/lib/Format/MacroCallReconstructor.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
//===--- MacroCallReconstructor.cpp - Format C++ code -----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file contains the implementation of MacroCallReconstructor, which fits
|
||||
/// an reconstructed macro call to a parsed set of UnwrappedLines.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Macros.h"
|
||||
|
||||
#include "UnwrappedLineParser.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <cassert>
|
||||
|
||||
#define DEBUG_TYPE "format-reconstruct"
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
// Call \p Call for each token in the unwrapped line given, passing
|
||||
// the token, its parent and whether it is the first token in the line.
|
||||
template <typename T>
|
||||
void forEachToken(const UnwrappedLine &Line, const T &Call,
|
||||
FormatToken *Parent = nullptr) {
|
||||
bool First = true;
|
||||
for (const auto &N : Line.Tokens) {
|
||||
Call(N.Tok, Parent, First);
|
||||
First = false;
|
||||
for (const auto &Child : N.Children) {
|
||||
forEachToken(Child, Call, N.Tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MacroCallReconstructor::MacroCallReconstructor(
|
||||
unsigned Level,
|
||||
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
|
||||
&ActiveExpansions)
|
||||
: Level(Level), IdToReconstructed(ActiveExpansions) {
|
||||
Result.Tokens.push_back(std::make_unique<LineNode>());
|
||||
ActiveReconstructedLines.push_back(&Result);
|
||||
}
|
||||
|
||||
void MacroCallReconstructor::addLine(const UnwrappedLine &Line) {
|
||||
assert(State != Finalized);
|
||||
LLVM_DEBUG(llvm::dbgs() << "MCR: new line...\n");
|
||||
forEachToken(Line, [&](FormatToken *Token, FormatToken *Parent, bool First) {
|
||||
add(Token, Parent, First);
|
||||
});
|
||||
assert(InProgress || finished());
|
||||
}
|
||||
|
||||
UnwrappedLine MacroCallReconstructor::takeResult() && {
|
||||
finalize();
|
||||
assert(Result.Tokens.size() == 1 && Result.Tokens.front()->Children.size() == 1);
|
||||
UnwrappedLine Final =
|
||||
createUnwrappedLine(*Result.Tokens.front()->Children.front(), Level);
|
||||
assert(!Final.Tokens.empty());
|
||||
return Final;
|
||||
}
|
||||
|
||||
// Reconstruct the position of the next \p Token, given its parent \p
|
||||
// ExpandedParent in the incoming unwrapped line. \p First specifies whether it
|
||||
// is the first token in a given unwrapped line.
|
||||
void MacroCallReconstructor::add(FormatToken *Token,
|
||||
FormatToken *ExpandedParent, bool First) {
|
||||
LLVM_DEBUG(
|
||||
llvm::dbgs() << "MCR: Token: " << Token->TokenText << ", Parent: "
|
||||
<< (ExpandedParent ? ExpandedParent->TokenText : "<null>")
|
||||
<< ", First: " << First << "\n");
|
||||
// In order to be able to find the correct parent in the reconstructed token
|
||||
// stream, we need to continue the last open reconstruction until we find the
|
||||
// given token if it is part of the reconstructed token stream.
|
||||
//
|
||||
// Note that hidden tokens can be part of the reconstructed stream in nested
|
||||
// macro calls.
|
||||
// For example, given
|
||||
// #define C(x, y) x y
|
||||
// #define B(x) {x}
|
||||
// And the call:
|
||||
// C(a, B(b))
|
||||
// The outer macro call will be C(a, {b}), and the hidden token '}' can be
|
||||
// found in the reconstructed token stream of that expansion level.
|
||||
// In the expanded token stream
|
||||
// a {b}
|
||||
// 'b' is a child of '{'. We need to continue the open expansion of the ','
|
||||
// in the call of 'C' in order to correctly set the ',' as the parent of '{',
|
||||
// so we later set the spelled token 'b' as a child of the ','.
|
||||
if (!ActiveExpansions.empty() && Token->MacroCtx &&
|
||||
(Token->MacroCtx->Role != MR_Hidden ||
|
||||
ActiveExpansions.size() != Token->MacroCtx->ExpandedFrom.size())) {
|
||||
if (/*PassedMacroComma = */ reconstructActiveCallUntil(Token))
|
||||
First = true;
|
||||
}
|
||||
|
||||
prepareParent(ExpandedParent, First);
|
||||
|
||||
if (Token->MacroCtx) {
|
||||
// If this token was generated by a macro call, add the reconstructed
|
||||
// equivalent of the token.
|
||||
reconstruct(Token);
|
||||
} else {
|
||||
// Otherwise, we add it to the current line.
|
||||
appendToken(Token);
|
||||
}
|
||||
}
|
||||
|
||||
// Adjusts the stack of active reconstructed lines so we're ready to push
|
||||
// tokens. The tokens to be pushed are children of ExpandedParent in the
|
||||
// expanded code.
|
||||
//
|
||||
// This may entail:
|
||||
// - creating a new line, if the parent is on the active line
|
||||
// - popping active lines, if the parent is further up the stack
|
||||
//
|
||||
// Postcondition:
|
||||
// ActiveReconstructedLines.back() is the line that has \p ExpandedParent or its
|
||||
// reconstructed replacement token as a parent (when possible) - that is, the
|
||||
// last token in \c ActiveReconstructedLines[ActiveReconstructedLines.size()-2]
|
||||
// is the parent of ActiveReconstructedLines.back() in the reconstructed
|
||||
// unwrapped line.
|
||||
void MacroCallReconstructor::prepareParent(FormatToken *ExpandedParent,
|
||||
bool NewLine) {
|
||||
LLVM_DEBUG({
|
||||
llvm::dbgs() << "ParentMap:\n";
|
||||
debugParentMap();
|
||||
});
|
||||
// We want to find the parent in the new unwrapped line, where the expanded
|
||||
// parent might have been replaced during reconstruction.
|
||||
FormatToken *Parent = getParentInResult(ExpandedParent);
|
||||
LLVM_DEBUG(llvm::dbgs() << "MCR: New parent: "
|
||||
<< (Parent ? Parent->TokenText : "<null>") << "\n");
|
||||
|
||||
FormatToken *OpenMacroParent = nullptr;
|
||||
if (!MacroCallStructure.empty()) {
|
||||
// Inside a macro expansion, it is possible to lose track of the correct
|
||||
// parent - either because it is already popped, for example because it was
|
||||
// in a different macro argument (e.g. M({, })), or when we work on invalid
|
||||
// code.
|
||||
// Thus, we use the innermost macro call's parent as the parent at which
|
||||
// we stop; this allows us to stay within the macro expansion and keeps
|
||||
// any problems confined to the extent of the macro call.
|
||||
OpenMacroParent =
|
||||
getParentInResult(MacroCallStructure.back().MacroCallLParen);
|
||||
LLVM_DEBUG(llvm::dbgs()
|
||||
<< "MacroCallLParen: "
|
||||
<< MacroCallStructure.back().MacroCallLParen->TokenText
|
||||
<< ", OpenMacroParent: "
|
||||
<< (OpenMacroParent ? OpenMacroParent->TokenText : "<null>")
|
||||
<< "\n");
|
||||
}
|
||||
if (NewLine ||
|
||||
(!ActiveReconstructedLines.back()->Tokens.empty() &&
|
||||
Parent == ActiveReconstructedLines.back()->Tokens.back()->Tok)) {
|
||||
// If we are at the first token in a new line, we want to also
|
||||
// create a new line in the resulting reconstructed unwrapped line.
|
||||
while (ActiveReconstructedLines.back()->Tokens.empty() ||
|
||||
(Parent != ActiveReconstructedLines.back()->Tokens.back()->Tok &&
|
||||
ActiveReconstructedLines.back()->Tokens.back()->Tok !=
|
||||
OpenMacroParent)) {
|
||||
ActiveReconstructedLines.pop_back();
|
||||
assert(!ActiveReconstructedLines.empty());
|
||||
}
|
||||
assert(!ActiveReconstructedLines.empty());
|
||||
ActiveReconstructedLines.back()->Tokens.back()->Children.push_back(
|
||||
std::make_unique<ReconstructedLine>());
|
||||
ActiveReconstructedLines.push_back(
|
||||
&*ActiveReconstructedLines.back()->Tokens.back()->Children.back());
|
||||
} else if (parentLine().Tokens.back()->Tok != Parent) {
|
||||
// If we're not the first token in a new line, pop lines until we find
|
||||
// the child of \c Parent in the stack.
|
||||
while (Parent != parentLine().Tokens.back()->Tok &&
|
||||
parentLine().Tokens.back()->Tok &&
|
||||
parentLine().Tokens.back()->Tok != OpenMacroParent) {
|
||||
ActiveReconstructedLines.pop_back();
|
||||
assert(!ActiveReconstructedLines.empty());
|
||||
}
|
||||
}
|
||||
assert(!ActiveReconstructedLines.empty());
|
||||
}
|
||||
|
||||
// For a given \p Parent in the incoming expanded token stream, find the
|
||||
// corresponding parent in the output.
|
||||
FormatToken *MacroCallReconstructor::getParentInResult(FormatToken *Parent) {
|
||||
FormatToken *Mapped = SpelledParentToReconstructedParent.lookup(Parent);
|
||||
if (!Mapped)
|
||||
return Parent;
|
||||
for (; Mapped; Mapped = SpelledParentToReconstructedParent.lookup(Parent)) {
|
||||
Parent = Mapped;
|
||||
}
|
||||
// If we use a different token than the parent in the expanded token stream
|
||||
// as parent, mark it as a special parent, so the formatting code knows it
|
||||
// needs to have its children formatted.
|
||||
Parent->MacroParent = true;
|
||||
return Parent;
|
||||
}
|
||||
|
||||
// Reconstruct a \p Token that was expanded from a macro call.
|
||||
void MacroCallReconstructor::reconstruct(FormatToken *Token) {
|
||||
assert(Token->MacroCtx);
|
||||
// A single token can be the only result of a macro call:
|
||||
// Given: #define ID(x, y) ;
|
||||
// And the call: ID(<some>, <tokens>)
|
||||
// ';' in the expanded stream will reconstruct all of ID(<some>, <tokens>).
|
||||
if (Token->MacroCtx->StartOfExpansion) {
|
||||
startReconstruction(Token);
|
||||
// If the order of tokens in the expanded token stream is not the
|
||||
// same as the order of tokens in the reconstructed stream, we need
|
||||
// to reconstruct tokens that arrive later in the stream.
|
||||
if (Token->MacroCtx->Role != MR_Hidden) {
|
||||
reconstructActiveCallUntil(Token);
|
||||
}
|
||||
}
|
||||
assert(!ActiveExpansions.empty());
|
||||
if (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE) {
|
||||
assert(ActiveExpansions.size() == Token->MacroCtx->ExpandedFrom.size());
|
||||
if (Token->MacroCtx->Role != MR_Hidden) {
|
||||
// The current token in the reconstructed token stream must be the token
|
||||
// we're looking for - we either arrive here after startReconstruction,
|
||||
// which initiates the stream to the first token, or after
|
||||
// continueReconstructionUntil skipped until the expected token in the
|
||||
// reconstructed stream at the start of add(...).
|
||||
assert(ActiveExpansions.back().SpelledI->Tok == Token);
|
||||
processNextReconstructed();
|
||||
} else if (!currentLine()->Tokens.empty()) {
|
||||
// Map all hidden tokens to the last visible token in the output.
|
||||
// If the hidden token is a parent, we'll use the last visible
|
||||
// token as the parent of the hidden token's children.
|
||||
SpelledParentToReconstructedParent[Token] =
|
||||
currentLine()->Tokens.back()->Tok;
|
||||
} else {
|
||||
for (auto I = ActiveReconstructedLines.rbegin(),
|
||||
E = ActiveReconstructedLines.rend();
|
||||
I != E; ++I) {
|
||||
if (!(*I)->Tokens.empty()) {
|
||||
SpelledParentToReconstructedParent[Token] = (*I)->Tokens.back()->Tok;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Token->MacroCtx->EndOfExpansion)
|
||||
endReconstruction(Token);
|
||||
}
|
||||
|
||||
// Given a \p Token that starts an expansion, reconstruct the beginning of the
|
||||
// macro call.
|
||||
// For example, given: #define ID(x) x
|
||||
// And the call: ID(int a)
|
||||
// Reconstructs: ID(
|
||||
void MacroCallReconstructor::startReconstruction(FormatToken *Token) {
|
||||
assert(Token->MacroCtx);
|
||||
assert(!Token->MacroCtx->ExpandedFrom.empty());
|
||||
assert(ActiveExpansions.size() <= Token->MacroCtx->ExpandedFrom.size());
|
||||
#ifndef NDEBUG
|
||||
// Check that the token's reconstruction stack matches our current
|
||||
// reconstruction stack.
|
||||
for (size_t I = 0; I < ActiveExpansions.size(); ++I) {
|
||||
assert(ActiveExpansions[I].ID ==
|
||||
Token->MacroCtx
|
||||
->ExpandedFrom[Token->MacroCtx->ExpandedFrom.size() - 1 - I]);
|
||||
}
|
||||
#endif
|
||||
// Start reconstruction for all calls for which this token is the first token
|
||||
// generated by the call.
|
||||
// Note that the token's expanded from stack is inside-to-outside, and the
|
||||
// expansions for which this token is not the first are the outermost ones.
|
||||
ArrayRef<FormatToken *> StartedMacros =
|
||||
makeArrayRef(Token->MacroCtx->ExpandedFrom)
|
||||
.drop_back(ActiveExpansions.size());
|
||||
assert(StartedMacros.size() == Token->MacroCtx->StartOfExpansion);
|
||||
// We reconstruct macro calls outside-to-inside.
|
||||
for (FormatToken *ID : llvm::reverse(StartedMacros)) {
|
||||
// We found a macro call to be reconstructed; the next time our
|
||||
// reconstruction stack is empty we know we finished an reconstruction.
|
||||
#ifndef NDEBUG
|
||||
State = InProgress;
|
||||
#endif
|
||||
// Put the reconstructed macro call's token into our reconstruction stack.
|
||||
auto IU = IdToReconstructed.find(ID);
|
||||
assert(IU != IdToReconstructed.end());
|
||||
ActiveExpansions.push_back(
|
||||
{ID, IU->second->Tokens.begin(), IU->second->Tokens.end()});
|
||||
// Process the macro call's identifier.
|
||||
processNextReconstructed();
|
||||
if (ActiveExpansions.back().SpelledI == ActiveExpansions.back().SpelledE)
|
||||
continue;
|
||||
if (ActiveExpansions.back().SpelledI->Tok->is(tok::l_paren)) {
|
||||
// Process the optional opening parenthesis.
|
||||
processNextReconstructed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all tokens in the reconstruction stream to the output until we find the
|
||||
// given \p Token.
|
||||
bool MacroCallReconstructor::reconstructActiveCallUntil(FormatToken *Token) {
|
||||
assert(!ActiveExpansions.empty());
|
||||
bool PassedMacroComma = false;
|
||||
// FIXME: If Token was already expanded earlier, due to
|
||||
// a change in order, we will not find it, but need to
|
||||
// skip it.
|
||||
while (ActiveExpansions.back().SpelledI != ActiveExpansions.back().SpelledE &&
|
||||
ActiveExpansions.back().SpelledI->Tok != Token) {
|
||||
PassedMacroComma = processNextReconstructed() || PassedMacroComma;
|
||||
}
|
||||
return PassedMacroComma;
|
||||
}
|
||||
|
||||
// End all reconstructions for which \p Token is the final token.
|
||||
void MacroCallReconstructor::endReconstruction(FormatToken *Token) {
|
||||
assert(Token->MacroCtx &&
|
||||
(ActiveExpansions.size() >= Token->MacroCtx->EndOfExpansion));
|
||||
for (size_t I = 0; I < Token->MacroCtx->EndOfExpansion; ++I) {
|
||||
#ifndef NDEBUG
|
||||
// Check all remaining tokens but the final closing parenthesis and optional
|
||||
// trailing comment were already reconstructed at an inner expansion level.
|
||||
for (auto T = ActiveExpansions.back().SpelledI;
|
||||
T != ActiveExpansions.back().SpelledE; ++T) {
|
||||
FormatToken *Token = T->Tok;
|
||||
bool ClosingParen = (std::next(T) == ActiveExpansions.back().SpelledE ||
|
||||
std::next(T)->Tok->isTrailingComment()) &&
|
||||
!Token->MacroCtx && Token->is(tok::r_paren);
|
||||
bool TrailingComment = Token->isTrailingComment();
|
||||
bool PreviousLevel =
|
||||
Token->MacroCtx &&
|
||||
(ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size());
|
||||
if (!ClosingParen && !TrailingComment && !PreviousLevel) {
|
||||
llvm::dbgs() << "At token: " << Token->TokenText << "\n";
|
||||
}
|
||||
// In addition to the following cases, we can also run into this
|
||||
// when a macro call had more arguments than expected; in that case,
|
||||
// the comma and the remaining tokens in the macro call will potentially
|
||||
// end up in the line when we finish the expansion.
|
||||
// FIXME: Add the information which arguments are unused, and assert
|
||||
// one of the cases below plus reconstructed macro argument tokens.
|
||||
// assert(ClosingParen || TrailingComment || PreviousLevel);
|
||||
}
|
||||
#endif
|
||||
// Handle the remaining open tokens:
|
||||
// - expand the closing parenthesis, if it exists, including an optional
|
||||
// trailing comment
|
||||
// - handle tokens that were already reconstructed at an inner expansion
|
||||
// level
|
||||
// - handle tokens when a macro call had more than the expected number of
|
||||
// arguments, i.e. when #define M(x) is called as M(a, b, c) we'll end
|
||||
// up with the sequence ", b, c)" being open at the end of the
|
||||
// reconstruction; we want to gracefully handle that case
|
||||
//
|
||||
// FIXME: See the above debug-check for what we will need to do to be
|
||||
// able to assert this.
|
||||
for (auto T = ActiveExpansions.back().SpelledI;
|
||||
T != ActiveExpansions.back().SpelledE; ++T) {
|
||||
processNextReconstructed();
|
||||
}
|
||||
ActiveExpansions.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroCallReconstructor::debugParentMap() const {
|
||||
llvm::DenseSet<FormatToken *> Values;
|
||||
for (const auto &P : SpelledParentToReconstructedParent)
|
||||
Values.insert(P.second);
|
||||
|
||||
for (const auto &P : SpelledParentToReconstructedParent) {
|
||||
if (Values.contains(P.first))
|
||||
continue;
|
||||
llvm::dbgs() << (P.first ? P.first->TokenText : "<null>");
|
||||
for (auto I = SpelledParentToReconstructedParent.find(P.first),
|
||||
E = SpelledParentToReconstructedParent.end();
|
||||
I != E; I = SpelledParentToReconstructedParent.find(I->second)) {
|
||||
llvm::dbgs() << " -> " << (I->second ? I->second->TokenText : "<null>");
|
||||
}
|
||||
llvm::dbgs() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// If visible, add the next token of the reconstructed token sequence to the
|
||||
// output. Returns whether reconstruction passed a comma that is part of a
|
||||
// macro call.
|
||||
bool MacroCallReconstructor::processNextReconstructed() {
|
||||
FormatToken *Token = ActiveExpansions.back().SpelledI->Tok;
|
||||
++ActiveExpansions.back().SpelledI;
|
||||
if (Token->MacroCtx) {
|
||||
// Skip tokens that are not part of the macro call.
|
||||
if (Token->MacroCtx->Role == MR_Hidden) {
|
||||
return false;
|
||||
}
|
||||
// Skip tokens we already expanded during an inner reconstruction.
|
||||
// For example, given: #define ID(x) {x}
|
||||
// And the call: ID(ID(f))
|
||||
// We get two reconstructions:
|
||||
// ID(f) -> {f}
|
||||
// ID({f}) -> {{f}}
|
||||
// We reconstruct f during the first reconstruction, and skip it during the
|
||||
// second reconstruction.
|
||||
if (ActiveExpansions.size() < Token->MacroCtx->ExpandedFrom.size()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Tokens that do not have a macro context are tokens in that are part of the
|
||||
// macro call that have not taken part in expansion.
|
||||
if (!Token->MacroCtx) {
|
||||
// Put the parentheses and commas of a macro call into the same line;
|
||||
// if the arguments produce new unwrapped lines, they will become children
|
||||
// of the corresponding opening parenthesis or comma tokens in the
|
||||
// reconstructed call.
|
||||
if (Token->is(tok::l_paren)) {
|
||||
MacroCallStructure.push_back(MacroCallState(
|
||||
currentLine(), parentLine().Tokens.back()->Tok, Token));
|
||||
// All tokens that are children of the previous line's last token in the
|
||||
// reconstructed token stream will now be children of the l_paren token.
|
||||
// For example, for the line containing the macro calls:
|
||||
// auto x = ID({ID(2)});
|
||||
// We will build up a map <null> -> ( -> ( with the first and second
|
||||
// l_paren of the macro call respectively. New lines that come in with a
|
||||
// <null> parent will then become children of the l_paren token of the
|
||||
// currently innermost macro call.
|
||||
SpelledParentToReconstructedParent[MacroCallStructure.back()
|
||||
.ParentLastToken] = Token;
|
||||
appendToken(Token);
|
||||
prepareParent(Token, /*NewLine=*/true);
|
||||
Token->MacroParent = true;
|
||||
return false;
|
||||
}
|
||||
if (!MacroCallStructure.empty()) {
|
||||
if (Token->is(tok::comma)) {
|
||||
// Make new lines inside the next argument children of the comma token.
|
||||
SpelledParentToReconstructedParent
|
||||
[MacroCallStructure.back().Line->Tokens.back()->Tok] = Token;
|
||||
Token->MacroParent = true;
|
||||
appendToken(Token, MacroCallStructure.back().Line);
|
||||
prepareParent(Token, /*NewLine=*/true);
|
||||
return true;
|
||||
}
|
||||
if (Token->is(tok::r_paren)) {
|
||||
appendToken(Token, MacroCallStructure.back().Line);
|
||||
SpelledParentToReconstructedParent.erase(
|
||||
MacroCallStructure.back().ParentLastToken);
|
||||
MacroCallStructure.pop_back();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note that any tokens that are tagged with MR_None have been passed as
|
||||
// arguments to the macro that have not been expanded, for example:
|
||||
// Given: #define ID(X) x
|
||||
// When calling: ID(a, b)
|
||||
// 'b' will be part of the reconstructed token stream, but tagged MR_None.
|
||||
// Given that erroring out in this case would be disruptive, we continue
|
||||
// pushing the (unformatted) token.
|
||||
// FIXME: This can lead to unfortunate formatting decisions - give the user
|
||||
// a hint that their macro definition is broken.
|
||||
appendToken(Token);
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroCallReconstructor::finalize() {
|
||||
#ifndef NDEBUG
|
||||
assert(State != Finalized && finished());
|
||||
State = Finalized;
|
||||
#endif
|
||||
|
||||
// We created corresponding unwrapped lines for each incoming line as children
|
||||
// the the toplevel null token.
|
||||
assert(Result.Tokens.size() == 1 && !Result.Tokens.front()->Children.empty());
|
||||
LLVM_DEBUG({
|
||||
llvm::dbgs() << "Finalizing reconstructed lines:\n";
|
||||
debug(Result, 0);
|
||||
});
|
||||
|
||||
// The first line becomes the top level line in the resulting unwrapped line.
|
||||
LineNode &Top = *Result.Tokens.front();
|
||||
auto *I = Top.Children.begin();
|
||||
// Every subsequent line will become a child of the last token in the previous
|
||||
// line, which is the token prior to the first token in the line.
|
||||
LineNode *Last = (*I)->Tokens.back().get();
|
||||
++I;
|
||||
for (auto *E = Top.Children.end(); I != E; ++I) {
|
||||
assert(Last->Children.empty());
|
||||
Last->Children.push_back(std::move(*I));
|
||||
|
||||
// Mark the previous line's last token as generated by a macro expansion
|
||||
// so the formatting algorithm can take that into account.
|
||||
Last->Tok->MacroParent = true;
|
||||
|
||||
Last = Last->Children.back()->Tokens.back().get();
|
||||
}
|
||||
Top.Children.resize(1);
|
||||
}
|
||||
|
||||
void MacroCallReconstructor::appendToken(FormatToken *Token,
|
||||
ReconstructedLine *L) {
|
||||
L = L ? L : currentLine();
|
||||
LLVM_DEBUG(llvm::dbgs() << "-> " << Token->TokenText << "\n");
|
||||
L->Tokens.push_back(std::make_unique<LineNode>(Token));
|
||||
}
|
||||
|
||||
UnwrappedLine
|
||||
MacroCallReconstructor::createUnwrappedLine(const ReconstructedLine &Line,
|
||||
int Level) {
|
||||
UnwrappedLine Result;
|
||||
Result.Level = Level;
|
||||
for (const auto &N : Line.Tokens) {
|
||||
Result.Tokens.push_back(N->Tok);
|
||||
UnwrappedLineNode &Current = Result.Tokens.back();
|
||||
for (const auto &Child : N->Children) {
|
||||
if (Child->Tokens.empty())
|
||||
continue;
|
||||
Current.Children.push_back(createUnwrappedLine(*Child, Level + 1));
|
||||
}
|
||||
if (Current.Children.size() == 1 &&
|
||||
Current.Tok->isOneOf(tok::l_paren, tok::comma)) {
|
||||
Result.Tokens.splice(Result.Tokens.end(),
|
||||
Current.Children.front().Tokens);
|
||||
Current.Children.clear();
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
void MacroCallReconstructor::debug(const ReconstructedLine &Line, int Level) {
|
||||
for (int i = 0; i < Level; ++i)
|
||||
llvm::dbgs() << " ";
|
||||
for (const auto &N : Line.Tokens) {
|
||||
if (!N)
|
||||
continue;
|
||||
if (N->Tok)
|
||||
llvm::dbgs() << N->Tok->TokenText << " ";
|
||||
for (const auto &Child : N->Children) {
|
||||
llvm::dbgs() << "\n";
|
||||
debug(*Child, Level + 1);
|
||||
for (int i = 0; i < Level; ++i)
|
||||
llvm::dbgs() << " ";
|
||||
}
|
||||
}
|
||||
llvm::dbgs() << "\n";
|
||||
}
|
||||
|
||||
MacroCallReconstructor::ReconstructedLine &
|
||||
MacroCallReconstructor::parentLine() {
|
||||
return **std::prev(std::prev(ActiveReconstructedLines.end()));
|
||||
}
|
||||
|
||||
MacroCallReconstructor::ReconstructedLine *
|
||||
MacroCallReconstructor::currentLine() {
|
||||
return ActiveReconstructedLines.back();
|
||||
}
|
||||
|
||||
MacroCallReconstructor::MacroCallState::MacroCallState(
|
||||
MacroCallReconstructor::ReconstructedLine *Line,
|
||||
FormatToken *ParentLastToken, FormatToken *MacroCallLParen)
|
||||
: Line(Line), ParentLastToken(ParentLastToken),
|
||||
MacroCallLParen(MacroCallLParen) {
|
||||
LLVM_DEBUG(
|
||||
llvm::dbgs() << "ParentLastToken: "
|
||||
<< (ParentLastToken ? ParentLastToken->TokenText : "<null>")
|
||||
<< "\n");
|
||||
|
||||
assert(MacroCallLParen->is(tok::l_paren));
|
||||
}
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
@ -1,4 +1,4 @@
|
||||
//===--- MacroExpander.h - Format C++ code ----------------------*- C++ -*-===//
|
||||
//===--- Macros.h - Format C++ code -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@ -22,40 +22,38 @@
|
||||
/// spelled token streams into expanded token streams when it encounters a
|
||||
/// macro call. The UnwrappedLineParser continues to parse UnwrappedLines
|
||||
/// from the expanded token stream.
|
||||
/// After the expanded unwrapped lines are parsed, the MacroUnexpander matches
|
||||
/// the spelled token stream into unwrapped lines that best resemble the
|
||||
/// structure of the expanded unwrapped lines.
|
||||
/// After the expanded unwrapped lines are parsed, the MacroCallReconstructor
|
||||
/// matches the spelled token stream into unwrapped lines that best resemble the
|
||||
/// structure of the expanded unwrapped lines. These reconstructed unwrapped
|
||||
/// lines are aliasing the tokens in the expanded token stream, so that token
|
||||
/// annotations will be reused when formatting the spelled macro calls.
|
||||
///
|
||||
/// When formatting, clang-format formats the expanded unwrapped lines first,
|
||||
/// determining the token types. Next, it formats the spelled unwrapped lines,
|
||||
/// keeping the token types fixed, while allowing other formatting decisions
|
||||
/// to change.
|
||||
/// When formatting, clang-format annotates and formats the expanded unwrapped
|
||||
/// lines first, determining the token types. Next, it formats the spelled
|
||||
/// unwrapped lines, keeping the token types fixed, while allowing other
|
||||
/// formatting decisions to change.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_LIB_FORMAT_MACROS_H
|
||||
#define CLANG_LIB_FORMAT_MACROS_H
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Encoding.h"
|
||||
#include "FormatToken.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
} // namespace llvm
|
||||
|
||||
namespace clang {
|
||||
class IdentifierTable;
|
||||
class SourceManager;
|
||||
|
||||
namespace format {
|
||||
struct FormatStyle;
|
||||
|
||||
struct UnwrappedLine;
|
||||
struct UnwrappedLineNode;
|
||||
|
||||
/// Takes a set of macro definitions as strings and allows expanding calls to
|
||||
/// those macros.
|
||||
@ -130,10 +128,253 @@ class MacroExpander {
|
||||
const FormatStyle &Style;
|
||||
llvm::SpecificBumpPtrAllocator<FormatToken> &Allocator;
|
||||
IdentifierTable &IdentTable;
|
||||
std::vector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
|
||||
SmallVector<std::unique_ptr<llvm::MemoryBuffer>> Buffers;
|
||||
llvm::StringMap<Definition> Definitions;
|
||||
};
|
||||
|
||||
/// Converts a sequence of UnwrappedLines containing expanded macros into a
|
||||
/// single UnwrappedLine containing the macro calls. This UnwrappedLine may be
|
||||
/// broken into child lines, in a way that best conveys the structure of the
|
||||
/// expanded code.
|
||||
///
|
||||
/// In the simplest case, a spelled UnwrappedLine contains one macro, and after
|
||||
/// expanding it we have one expanded UnwrappedLine. In general, macro
|
||||
/// expansions can span UnwrappedLines, and multiple macros can contribute
|
||||
/// tokens to the same line. We keep consuming expanded lines until:
|
||||
/// * all expansions that started have finished (we're not chopping any macros
|
||||
/// in half)
|
||||
/// * *and* we've reached the end of a *spelled* unwrapped line.
|
||||
///
|
||||
/// A single UnwrappedLine represents this chunk of code.
|
||||
///
|
||||
/// After this point, the state of the spelled/expanded stream is "in sync"
|
||||
/// (both at the start of an UnwrappedLine, with no macros open), so the
|
||||
/// Unexpander can be thrown away and parsing can continue.
|
||||
///
|
||||
/// Given a mapping from the macro name identifier token in the macro call
|
||||
/// to the tokens of the macro call, for example:
|
||||
/// CLASSA -> CLASSA({public: void x();})
|
||||
///
|
||||
/// When getting the formatted lines of the expansion via the \c addLine method
|
||||
/// (each '->' specifies a call to \c addLine ):
|
||||
/// -> class A {
|
||||
/// -> public:
|
||||
/// -> void x();
|
||||
/// -> };
|
||||
///
|
||||
/// Creates the tree of unwrapped lines containing the macro call tokens so that
|
||||
/// the macro call tokens fit the semantic structure of the expanded formatted
|
||||
/// lines:
|
||||
/// -> CLASSA({
|
||||
/// -> public:
|
||||
/// -> void x();
|
||||
/// -> })
|
||||
class MacroCallReconstructor {
|
||||
public:
|
||||
/// Create an Reconstructor whose resulting \p UnwrappedLine will start at
|
||||
/// \p Level, using the map from name identifier token to the corresponding
|
||||
/// tokens of the spelled macro call.
|
||||
MacroCallReconstructor(
|
||||
unsigned Level,
|
||||
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
|
||||
&ActiveExpansions);
|
||||
|
||||
/// For the given \p Line, match all occurences of tokens expanded from a
|
||||
/// macro to unwrapped lines in the spelled macro call so that the resulting
|
||||
/// tree of unwrapped lines best resembles the structure of unwrapped lines
|
||||
/// passed in via \c addLine.
|
||||
void addLine(const UnwrappedLine &Line);
|
||||
|
||||
/// Check whether at the current state there is no open macro expansion
|
||||
/// that needs to be processed to finish an macro call.
|
||||
/// Only when \c finished() is true, \c takeResult() can be called to retrieve
|
||||
/// the resulting \c UnwrappedLine.
|
||||
/// If there are multiple subsequent macro calls within an unwrapped line in
|
||||
/// the spelled token stream, the calling code may also continue to call
|
||||
/// \c addLine() when \c finished() is true.
|
||||
bool finished() const { return ActiveExpansions.empty(); }
|
||||
|
||||
/// Retrieve the formatted \c UnwrappedLine containing the orginal
|
||||
/// macro calls, formatted according to the expanded token stream received
|
||||
/// via \c addLine().
|
||||
/// Generally, this line tries to have the same structure as the expanded,
|
||||
/// formatted unwrapped lines handed in via \c addLine(), with the exception
|
||||
/// that for multiple top-level lines, each subsequent line will be the
|
||||
/// child of the last token in its predecessor. This representation is chosen
|
||||
/// because it is a precondition to the formatter that we get what looks like
|
||||
/// a single statement in a single \c UnwrappedLine (i.e. matching parens).
|
||||
///
|
||||
/// If a token in a macro argument is a child of a token in the expansion,
|
||||
/// the parent will be the corresponding token in the macro call.
|
||||
/// For example:
|
||||
/// #define C(a, b) class C { a b
|
||||
/// C(int x;, int y;)
|
||||
/// would expand to
|
||||
/// class C { int x; int y;
|
||||
/// where in a formatted line "int x;" and "int y;" would both be new separate
|
||||
/// lines.
|
||||
///
|
||||
/// In the result, "int x;" will be a child of the opening parenthesis in "C("
|
||||
/// and "int y;" will be a child of the "," token:
|
||||
/// C (
|
||||
/// \- int x;
|
||||
/// ,
|
||||
/// \- int y;
|
||||
/// )
|
||||
UnwrappedLine takeResult() &&;
|
||||
|
||||
private:
|
||||
void add(FormatToken *Token, FormatToken *ExpandedParent, bool First);
|
||||
void prepareParent(FormatToken *ExpandedParent, bool First);
|
||||
FormatToken *getParentInResult(FormatToken *Parent);
|
||||
void reconstruct(FormatToken *Token);
|
||||
void startReconstruction(FormatToken *Token);
|
||||
bool reconstructActiveCallUntil(FormatToken *Token);
|
||||
void endReconstruction(FormatToken *Token);
|
||||
bool processNextReconstructed();
|
||||
void finalize();
|
||||
|
||||
struct ReconstructedLine;
|
||||
|
||||
void appendToken(FormatToken *Token, ReconstructedLine *L = nullptr);
|
||||
UnwrappedLine createUnwrappedLine(const ReconstructedLine &Line, int Level);
|
||||
void debug(const ReconstructedLine &Line, int Level);
|
||||
ReconstructedLine &parentLine();
|
||||
ReconstructedLine *currentLine();
|
||||
void debugParentMap() const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
enum ReconstructorState {
|
||||
Start, // No macro expansion was found in the input yet.
|
||||
InProgress, // During a macro reconstruction.
|
||||
Finalized, // Past macro reconstruction, the result is finalized.
|
||||
};
|
||||
ReconstructorState State = Start;
|
||||
#endif
|
||||
|
||||
// Node in which we build up the resulting unwrapped line; this type is
|
||||
// analogous to UnwrappedLineNode.
|
||||
struct LineNode {
|
||||
LineNode() = default;
|
||||
LineNode(FormatToken *Tok) : Tok(Tok) {}
|
||||
FormatToken *Tok = nullptr;
|
||||
llvm::SmallVector<std::unique_ptr<ReconstructedLine>> Children;
|
||||
};
|
||||
|
||||
// Line in which we build up the resulting unwrapped line.
|
||||
// FIXME: Investigate changing UnwrappedLine to a pointer type and using it
|
||||
// instead of rolling our own type.
|
||||
struct ReconstructedLine {
|
||||
llvm::SmallVector<std::unique_ptr<LineNode>> Tokens;
|
||||
};
|
||||
|
||||
// The line in which we collect the resulting reconstructed output.
|
||||
// To reduce special cases in the algorithm, the first level of the line
|
||||
// contains a single null token that has the reconstructed incoming
|
||||
// lines as children.
|
||||
// In the end, we stich the lines together so that each subsequent line
|
||||
// is a child of the last token of the previous line. This is necessary
|
||||
// in order to format the overall expression as a single logical line -
|
||||
// if we created separate lines, we'd format them with their own top-level
|
||||
// indent depending on the semantic structure, which is not desired.
|
||||
ReconstructedLine Result;
|
||||
|
||||
// Stack of currently "open" lines, where each line's predecessor's last
|
||||
// token is the parent token for that line.
|
||||
llvm::SmallVector<ReconstructedLine *> ActiveReconstructedLines;
|
||||
|
||||
// Maps from the expanded token to the token that takes its place in the
|
||||
// reconstructed token stream in terms of parent-child relationships.
|
||||
// Note that it might take multiple steps to arrive at the correct
|
||||
// parent in the output.
|
||||
// Given: #define C(a, b) []() { a; b; }
|
||||
// And a call: C(f(), g())
|
||||
// The structure in the incoming formatted unwrapped line will be:
|
||||
// []() {
|
||||
// |- f();
|
||||
// \- g();
|
||||
// }
|
||||
// with f and g being children of the opening brace.
|
||||
// In the reconstructed call:
|
||||
// C(f(), g())
|
||||
// \- f()
|
||||
// \- g()
|
||||
// We want f to be a child of the opening parenthesis and g to be a child
|
||||
// of the comma token in the macro call.
|
||||
// Thus, we map
|
||||
// { -> (
|
||||
// and add
|
||||
// ( -> ,
|
||||
// once we're past the comma in the reconstruction.
|
||||
llvm::DenseMap<FormatToken *, FormatToken *>
|
||||
SpelledParentToReconstructedParent;
|
||||
|
||||
// Keeps track of a single expansion while we're reconstructing tokens it
|
||||
// generated.
|
||||
struct Expansion {
|
||||
// The identifier token of the macro call.
|
||||
FormatToken *ID;
|
||||
// Our current position in the reconstruction.
|
||||
std::list<UnwrappedLineNode>::iterator SpelledI;
|
||||
// The end of the reconstructed token sequence.
|
||||
std::list<UnwrappedLineNode>::iterator SpelledE;
|
||||
};
|
||||
|
||||
// Stack of macro calls for which we're in the middle of an expansion.
|
||||
llvm::SmallVector<Expansion> ActiveExpansions;
|
||||
|
||||
struct MacroCallState {
|
||||
MacroCallState(ReconstructedLine *Line, FormatToken *ParentLastToken,
|
||||
FormatToken *MacroCallLParen);
|
||||
|
||||
ReconstructedLine *Line;
|
||||
|
||||
// The last token in the parent line or expansion, or nullptr if the macro
|
||||
// expansion is on a top-level line.
|
||||
//
|
||||
// For example, in the macro call:
|
||||
// auto f = []() { ID(1); };
|
||||
// The MacroCallState for ID will have '{' as ParentLastToken.
|
||||
//
|
||||
// In the macro call:
|
||||
// ID(ID(void f()));
|
||||
// The MacroCallState of the outer ID will have nullptr as ParentLastToken,
|
||||
// while the MacroCallState for the inner ID will have the '(' of the outer
|
||||
// ID as ParentLastToken.
|
||||
//
|
||||
// In the macro call:
|
||||
// ID2(a, ID(b));
|
||||
// The MacroCallState of ID will have ',' as ParentLastToken.
|
||||
FormatToken *ParentLastToken;
|
||||
|
||||
// The l_paren of this MacroCallState's macro call.
|
||||
FormatToken *MacroCallLParen;
|
||||
};
|
||||
|
||||
// Keeps track of the lines into which the opening brace/parenthesis &
|
||||
// argument separating commas for each level in the macro call go in order to
|
||||
// put the corresponding closing brace/parenthesis into the same line in the
|
||||
// output and keep track of which parents in the expanded token stream map to
|
||||
// which tokens in the reconstructed stream.
|
||||
// When an opening brace/parenthesis has children, we want the structure of
|
||||
// the output line to be:
|
||||
// |- MACRO
|
||||
// |- (
|
||||
// | \- <argument>
|
||||
// |- ,
|
||||
// | \- <argument>
|
||||
// \- )
|
||||
llvm::SmallVector<MacroCallState> MacroCallStructure;
|
||||
|
||||
// Level the generated UnwrappedLine will be at.
|
||||
const unsigned Level;
|
||||
|
||||
// Maps from identifier of the macro call to an unwrapped line containing
|
||||
// all tokens of the macro call.
|
||||
const llvm::DenseMap<FormatToken *, std::unique_ptr<UnwrappedLine>>
|
||||
&IdToReconstructed;
|
||||
};
|
||||
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
||||
|
@ -4734,7 +4734,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
|
||||
// the first list element. Otherwise, it should be placed outside of the
|
||||
// list.
|
||||
return Left.is(BK_BracedInit) ||
|
||||
(Left.is(TT_CtorInitializerColon) &&
|
||||
(Left.is(TT_CtorInitializerColon) && Right.NewlinesBefore > 0 &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon);
|
||||
}
|
||||
if (Left.is(tok::question) && Right.is(tok::colon))
|
||||
@ -4894,8 +4894,10 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
|
||||
if (Right.is(tok::identifier) && Right.Next && Right.Next->is(TT_DictLiteral))
|
||||
return true;
|
||||
|
||||
if (Left.is(TT_CtorInitializerColon))
|
||||
return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon;
|
||||
if (Left.is(TT_CtorInitializerColon)) {
|
||||
return Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon &&
|
||||
(!Right.isTrailingComment() || Right.NewlinesBefore > 0);
|
||||
}
|
||||
if (Right.is(TT_CtorInitializerColon))
|
||||
return Style.BreakConstructorInitializers != FormatStyle::BCIS_AfterColon;
|
||||
if (Left.is(TT_CtorInitializerComma) &&
|
||||
|
@ -59,14 +59,12 @@ class LevelIndentTracker {
|
||||
Offset = getIndentOffset(*Line.First);
|
||||
// Update the indent level cache size so that we can rely on it
|
||||
// having the right size in adjustToUnmodifiedline.
|
||||
while (IndentForLevel.size() <= Line.Level)
|
||||
IndentForLevel.push_back(-1);
|
||||
skipLine(Line, /*UnknownIndent=*/true);
|
||||
if (Line.InPPDirective) {
|
||||
unsigned IndentWidth =
|
||||
(Style.PPIndentWidth >= 0) ? Style.PPIndentWidth : Style.IndentWidth;
|
||||
Indent = Line.Level * IndentWidth + AdditionalIndent;
|
||||
} else {
|
||||
IndentForLevel.resize(Line.Level + 1);
|
||||
Indent = getIndent(Line.Level);
|
||||
}
|
||||
if (static_cast<int>(Indent) + Offset >= 0)
|
||||
@ -77,9 +75,9 @@ class LevelIndentTracker {
|
||||
|
||||
/// Update the indent state given that \p Line indent should be
|
||||
/// skipped.
|
||||
void skipLine(const AnnotatedLine &Line) {
|
||||
while (IndentForLevel.size() <= Line.Level)
|
||||
IndentForLevel.push_back(Indent);
|
||||
void skipLine(const AnnotatedLine &Line, bool UnknownIndent = false) {
|
||||
if (Line.Level >= IndentForLevel.size())
|
||||
IndentForLevel.resize(Line.Level + 1, UnknownIndent ? -1 : Indent);
|
||||
}
|
||||
|
||||
/// Update the level indent to adapt to the given \p Line.
|
||||
@ -91,6 +89,7 @@ class LevelIndentTracker {
|
||||
unsigned LevelIndent = Line.First->OriginalColumn;
|
||||
if (static_cast<int>(LevelIndent) - Offset >= 0)
|
||||
LevelIndent -= Offset;
|
||||
assert(Line.Level < IndentForLevel.size());
|
||||
if ((!Line.First->is(tok::comment) || IndentForLevel[Line.Level] == -1) &&
|
||||
!Line.InPPDirective) {
|
||||
IndentForLevel[Line.Level] = LevelIndent;
|
||||
@ -159,7 +158,7 @@ class LevelIndentTracker {
|
||||
const unsigned AdditionalIndent;
|
||||
|
||||
/// The indent in characters for each level.
|
||||
std::vector<int> IndentForLevel;
|
||||
SmallVector<int> IndentForLevel;
|
||||
|
||||
/// Offset of the current line relative to the indent level.
|
||||
///
|
||||
@ -1133,7 +1132,7 @@ class OptimizingLineFormatter : public LineFormatter {
|
||||
typedef std::pair<OrderedPenalty, StateNode *> QueueItem;
|
||||
|
||||
/// The BFS queue type.
|
||||
typedef std::priority_queue<QueueItem, std::vector<QueueItem>,
|
||||
typedef std::priority_queue<QueueItem, SmallVector<QueueItem>,
|
||||
std::greater<QueueItem>>
|
||||
QueueType;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "UnwrappedLineParser.h"
|
||||
#include "FormatToken.h"
|
||||
#include "TokenAnnotator.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -1910,15 +1911,12 @@ void UnwrappedLineParser::parseStructuralElement(
|
||||
break;
|
||||
|
||||
auto OneTokenSoFar = [&]() {
|
||||
const UnwrappedLineNode *Tok = &Line->Tokens.front(),
|
||||
*End = Tok + Line->Tokens.size();
|
||||
while (Tok != End && Tok->Tok->is(tok::comment))
|
||||
++Tok;
|
||||
// In Verilog, macro invocations start with a backtick which the code
|
||||
// treats as a hash. Skip it.
|
||||
if (Style.isVerilog() && Tok != End && Tok->Tok->is(tok::hash))
|
||||
++Tok;
|
||||
return End - Tok == 1;
|
||||
auto I = Line->Tokens.begin(), E = Line->Tokens.end();
|
||||
while (I != E && I->Tok->is(tok::comment))
|
||||
++I;
|
||||
while (I != E && Style.isVerilog() && I->Tok->is(tok::hash))
|
||||
++I;
|
||||
return I != E && (++I == E);
|
||||
};
|
||||
if (OneTokenSoFar()) {
|
||||
if (FormatTok->is(tok::colon) && !Line->MustBeDeclaration) {
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/Format/Format.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
#include <list>
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
@ -38,7 +39,7 @@ struct UnwrappedLine {
|
||||
UnwrappedLine();
|
||||
|
||||
/// The \c Tokens comprising this \c UnwrappedLine.
|
||||
std::vector<UnwrappedLineNode> Tokens;
|
||||
std::list<UnwrappedLineNode> Tokens;
|
||||
|
||||
/// The indent level of the \c UnwrappedLine.
|
||||
unsigned Level;
|
||||
|
@ -115,9 +115,9 @@ bool CompilerInstance::createTarget() {
|
||||
auto TO = std::make_shared<TargetOptions>();
|
||||
TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple);
|
||||
if (getFrontendOpts().AuxTargetCPU)
|
||||
TO->CPU = getFrontendOpts().AuxTargetCPU.getValue();
|
||||
TO->CPU = getFrontendOpts().AuxTargetCPU.value();
|
||||
if (getFrontendOpts().AuxTargetFeatures)
|
||||
TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.getValue();
|
||||
TO->FeaturesAsWritten = getFrontendOpts().AuxTargetFeatures.value();
|
||||
TO->HostTriple = getTarget().getTriple().str();
|
||||
setAuxTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), TO));
|
||||
}
|
||||
@ -757,6 +757,8 @@ void CompilerInstance::createSema(TranslationUnitKind TUKind,
|
||||
// Output Files
|
||||
|
||||
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
|
||||
// The ASTConsumer can own streams that write to the output files.
|
||||
assert(!hasASTConsumer() && "ASTConsumer should be reset");
|
||||
// Ignore errors that occur when trying to discard the temp file.
|
||||
for (OutputFile &OF : OutputFiles) {
|
||||
if (EraseFiles) {
|
||||
@ -1235,8 +1237,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
|
||||
|
||||
// Execute the action to actually build the module in-place. Use a separate
|
||||
// thread so that we get a stack large enough.
|
||||
llvm::CrashRecoveryContext CRC;
|
||||
CRC.RunSafelyOnThread(
|
||||
bool Crashed = !llvm::CrashRecoveryContext().RunSafelyOnThread(
|
||||
[&]() {
|
||||
GenerateModuleFromModuleMapAction Action;
|
||||
Instance.ExecuteAction(Action);
|
||||
@ -1249,9 +1250,15 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
|
||||
diag::remark_module_build_done)
|
||||
<< ModuleName;
|
||||
|
||||
// Delete any remaining temporary files related to Instance, in case the
|
||||
// module generation thread crashed.
|
||||
Instance.clearOutputFiles(/*EraseFiles=*/true);
|
||||
if (Crashed) {
|
||||
// Clear the ASTConsumer if it hasn't been already, in case it owns streams
|
||||
// that must be closed before clearing output files.
|
||||
Instance.setSema(nullptr);
|
||||
Instance.setASTConsumer(nullptr);
|
||||
|
||||
// Delete any remaining temporary files related to Instance.
|
||||
Instance.clearOutputFiles(/*EraseFiles=*/true);
|
||||
}
|
||||
|
||||
// If \p AllowPCMWithCompilerErrors is set return 'success' even if errors
|
||||
// occurred.
|
||||
|
@ -1485,6 +1485,9 @@ void CompilerInvocation::GenerateCodeGenArgs(
|
||||
if (Opts.IBTSeal)
|
||||
GenerateArg(Args, OPT_mibt_seal, SA);
|
||||
|
||||
if (Opts.FunctionReturnThunks)
|
||||
GenerateArg(Args, OPT_mfunction_return_EQ, "thunk-extern", SA);
|
||||
|
||||
for (const auto &F : Opts.LinkBitcodeFiles) {
|
||||
bool Builtint = F.LinkFlags == llvm::Linker::Flags::LinkOnlyNeeded &&
|
||||
F.PropagateAttrs && F.Internalize;
|
||||
@ -1825,6 +1828,27 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
|
||||
Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
|
||||
}
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_mfunction_return_EQ)) {
|
||||
auto Val = llvm::StringSwitch<llvm::FunctionReturnThunksKind>(A->getValue())
|
||||
.Case("keep", llvm::FunctionReturnThunksKind::Keep)
|
||||
.Case("thunk-extern", llvm::FunctionReturnThunksKind::Extern)
|
||||
.Default(llvm::FunctionReturnThunksKind::Invalid);
|
||||
// SystemZ might want to add support for "expolines."
|
||||
if (!T.isX86())
|
||||
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getSpelling() << T.getTriple();
|
||||
else if (Val == llvm::FunctionReturnThunksKind::Invalid)
|
||||
Diags.Report(diag::err_drv_invalid_value)
|
||||
<< A->getAsString(Args) << A->getValue();
|
||||
else if (Val == llvm::FunctionReturnThunksKind::Extern &&
|
||||
Args.getLastArgValue(OPT_mcmodel_EQ).equals("large"))
|
||||
Diags.Report(diag::err_drv_argument_not_allowed_with)
|
||||
<< A->getAsString(Args)
|
||||
<< Args.getLastArg(OPT_mcmodel_EQ)->getAsString(Args);
|
||||
else
|
||||
Opts.FunctionReturnThunks = static_cast<unsigned>(Val);
|
||||
}
|
||||
|
||||
if (Opts.PrepareForLTO && Args.hasArg(OPT_mibt_seal))
|
||||
Opts.IBTSeal = 1;
|
||||
|
||||
@ -1952,7 +1976,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
|
||||
} else {
|
||||
Opts.DiagnosticsHotnessThreshold = *ResultOrErr;
|
||||
if ((!Opts.DiagnosticsHotnessThreshold ||
|
||||
Opts.DiagnosticsHotnessThreshold.getValue() > 0) &&
|
||||
Opts.DiagnosticsHotnessThreshold.value() > 0) &&
|
||||
!UsingProfile)
|
||||
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
|
||||
<< "-fdiagnostics-hotness-threshold=";
|
||||
@ -1969,7 +1993,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
|
||||
} else {
|
||||
Opts.DiagnosticsMisExpectTolerance = *ResultOrErr;
|
||||
if ((!Opts.DiagnosticsMisExpectTolerance ||
|
||||
Opts.DiagnosticsMisExpectTolerance.getValue() > 0) &&
|
||||
Opts.DiagnosticsMisExpectTolerance.value() > 0) &&
|
||||
!UsingProfile)
|
||||
Diags.Report(diag::warn_drv_diagnostics_misexpect_requires_pgo)
|
||||
<< "-fdiagnostics-misexpect-tolerance=";
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Parse/ParseAST.h"
|
||||
#include "clang/Sema/HLSLExternalSemaSource.h"
|
||||
#include "clang/Serialization/ASTDeserializationListener.h"
|
||||
#include "clang/Serialization/ASTReader.h"
|
||||
#include "clang/Serialization/GlobalModuleIndex.h"
|
||||
@ -580,6 +581,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
||||
auto FailureCleanup = llvm::make_scope_exit([&]() {
|
||||
if (HasBegunSourceFile)
|
||||
CI.getDiagnosticClient().EndSourceFile();
|
||||
CI.setASTConsumer(nullptr);
|
||||
CI.clearOutputFiles(/*EraseFiles=*/true);
|
||||
CI.getLangOpts().setCompilingModule(LangOptions::CMK_None);
|
||||
setCurrentInput(FrontendInputFile());
|
||||
@ -1014,6 +1016,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
|
||||
CI.getASTContext().setExternalSource(Override);
|
||||
}
|
||||
|
||||
// Setup HLSL External Sema Source
|
||||
if (CI.getLangOpts().HLSL && CI.hasASTContext()) {
|
||||
IntrusiveRefCntPtr<ExternalASTSource> HLSLSema(
|
||||
new HLSLExternalSemaSource());
|
||||
CI.getASTContext().setExternalSource(HLSLSema);
|
||||
}
|
||||
|
||||
FailureCleanup.release();
|
||||
return true;
|
||||
}
|
||||
|
@ -854,8 +854,9 @@ void DumpModuleInfoAction::ExecuteAction() {
|
||||
std::error_code EC;
|
||||
OutFile.reset(new llvm::raw_fd_ostream(OutputFileName.str(), EC,
|
||||
llvm::sys::fs::OF_TextWithCRLF));
|
||||
OutputStream = OutFile.get();
|
||||
}
|
||||
llvm::raw_ostream &Out = OutFile.get()? *OutFile.get() : llvm::outs();
|
||||
llvm::raw_ostream &Out = OutputStream ? *OutputStream : llvm::outs();
|
||||
|
||||
Out << "Information for module file '" << getCurrentFile() << "':\n";
|
||||
auto &FileMgr = getCompilerInstance().getFileManager();
|
||||
|
@ -832,11 +832,11 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
|
||||
|
||||
unsigned minor = 0;
|
||||
if (tuple.getMinor())
|
||||
minor = tuple.getMinor().getValue();
|
||||
minor = tuple.getMinor().value();
|
||||
|
||||
unsigned subminor = 0;
|
||||
if (tuple.getSubminor())
|
||||
subminor = tuple.getSubminor().getValue();
|
||||
subminor = tuple.getSubminor().value();
|
||||
|
||||
Builder.defineMacro("__OBJFW_RUNTIME_ABI__",
|
||||
Twine(tuple.getMajor() * 10000 + minor * 100 +
|
||||
|
@ -27,38 +27,38 @@ typedef long int64_t;
|
||||
// built-in vector data types:
|
||||
|
||||
#ifdef __HLSL_ENABLE_16_BIT
|
||||
typedef int16_t int16_t2 __attribute__((ext_vector_type(2)));
|
||||
typedef int16_t int16_t3 __attribute__((ext_vector_type(3)));
|
||||
typedef int16_t int16_t4 __attribute__((ext_vector_type(4)));
|
||||
typedef uint16_t uint16_t2 __attribute__((ext_vector_type(2)));
|
||||
typedef uint16_t uint16_t3 __attribute__((ext_vector_type(3)));
|
||||
typedef uint16_t uint16_t4 __attribute__((ext_vector_type(4)));
|
||||
typedef vector<int16_t, 2> int16_t2;
|
||||
typedef vector<int16_t, 3> int16_t3;
|
||||
typedef vector<int16_t, 4> int16_t4;
|
||||
typedef vector<uint16_t, 2> uint16_t2;
|
||||
typedef vector<uint16_t, 3> uint16_t3;
|
||||
typedef vector<uint16_t, 4> uint16_t4;
|
||||
#endif
|
||||
|
||||
typedef int int2 __attribute__((ext_vector_type(2)));
|
||||
typedef int int3 __attribute__((ext_vector_type(3)));
|
||||
typedef int int4 __attribute__((ext_vector_type(4)));
|
||||
typedef uint uint2 __attribute__((ext_vector_type(2)));
|
||||
typedef uint uint3 __attribute__((ext_vector_type(3)));
|
||||
typedef uint uint4 __attribute__((ext_vector_type(4)));
|
||||
typedef int64_t int64_t2 __attribute__((ext_vector_type(2)));
|
||||
typedef int64_t int64_t3 __attribute__((ext_vector_type(3)));
|
||||
typedef int64_t int64_t4 __attribute__((ext_vector_type(4)));
|
||||
typedef uint64_t uint64_t2 __attribute__((ext_vector_type(2)));
|
||||
typedef uint64_t uint64_t3 __attribute__((ext_vector_type(3)));
|
||||
typedef uint64_t uint64_t4 __attribute__((ext_vector_type(4)));
|
||||
typedef vector<int, 2> int2;
|
||||
typedef vector<int, 3> int3;
|
||||
typedef vector<int, 4> int4;
|
||||
typedef vector<uint, 2> uint2;
|
||||
typedef vector<uint, 3> uint3;
|
||||
typedef vector<uint, 4> uint4;
|
||||
typedef vector<int64_t, 2> int64_t2;
|
||||
typedef vector<int64_t, 3> int64_t3;
|
||||
typedef vector<int64_t, 4> int64_t4;
|
||||
typedef vector<uint64_t, 2> uint64_t2;
|
||||
typedef vector<uint64_t, 3> uint64_t3;
|
||||
typedef vector<uint64_t, 4> uint64_t4;
|
||||
|
||||
#ifdef __HLSL_ENABLE_16_BIT
|
||||
typedef half half2 __attribute__((ext_vector_type(2)));
|
||||
typedef half half3 __attribute__((ext_vector_type(3)));
|
||||
typedef half half4 __attribute__((ext_vector_type(4)));
|
||||
typedef vector<half, 2> half2;
|
||||
typedef vector<half, 3> half3;
|
||||
typedef vector<half, 4> half4;
|
||||
#endif
|
||||
|
||||
typedef float float2 __attribute__((ext_vector_type(2)));
|
||||
typedef float float3 __attribute__((ext_vector_type(3)));
|
||||
typedef float float4 __attribute__((ext_vector_type(4)));
|
||||
typedef double double2 __attribute__((ext_vector_type(2)));
|
||||
typedef double double3 __attribute__((ext_vector_type(3)));
|
||||
typedef double double4 __attribute__((ext_vector_type(4)));
|
||||
typedef vector<float, 2> float2;
|
||||
typedef vector<float, 3> float3;
|
||||
typedef vector<float, 4> float4;
|
||||
typedef vector<double, 2> double2;
|
||||
typedef vector<double, 3> double3;
|
||||
typedef vector<double, 4> double4;
|
||||
|
||||
#endif //_HLSL_HLSL_BASIC_TYPES_H_
|
||||
|
@ -10467,12 +10467,6 @@ float __ovld __cnfn fast_distance(float, float);
|
||||
float __ovld __cnfn fast_distance(float2, float2);
|
||||
float __ovld __cnfn fast_distance(float3, float3);
|
||||
float __ovld __cnfn fast_distance(float4, float4);
|
||||
#ifdef cl_khr_fp16
|
||||
half __ovld __cnfn fast_distance(half, half);
|
||||
half __ovld __cnfn fast_distance(half2, half2);
|
||||
half __ovld __cnfn fast_distance(half3, half3);
|
||||
half __ovld __cnfn fast_distance(half4, half4);
|
||||
#endif //cl_khr_fp16
|
||||
|
||||
/**
|
||||
* Returns the length of vector p computed as:
|
||||
@ -10482,12 +10476,6 @@ float __ovld __cnfn fast_length(float);
|
||||
float __ovld __cnfn fast_length(float2);
|
||||
float __ovld __cnfn fast_length(float3);
|
||||
float __ovld __cnfn fast_length(float4);
|
||||
#ifdef cl_khr_fp16
|
||||
half __ovld __cnfn fast_length(half);
|
||||
half __ovld __cnfn fast_length(half2);
|
||||
half __ovld __cnfn fast_length(half3);
|
||||
half __ovld __cnfn fast_length(half4);
|
||||
#endif //cl_khr_fp16
|
||||
|
||||
/**
|
||||
* Returns a vector in the same direction as p but with a
|
||||
@ -10514,12 +10502,6 @@ float __ovld __cnfn fast_normalize(float);
|
||||
float2 __ovld __cnfn fast_normalize(float2);
|
||||
float3 __ovld __cnfn fast_normalize(float3);
|
||||
float4 __ovld __cnfn fast_normalize(float4);
|
||||
#ifdef cl_khr_fp16
|
||||
half __ovld __cnfn fast_normalize(half);
|
||||
half2 __ovld __cnfn fast_normalize(half2);
|
||||
half3 __ovld __cnfn fast_normalize(half3);
|
||||
half4 __ovld __cnfn fast_normalize(half4);
|
||||
#endif //cl_khr_fp16
|
||||
|
||||
// OpenCL v1.1 s6.11.6, v1.2 s6.12.6, v2.0 s6.13.6 - Relational Functions
|
||||
|
||||
|
57
contrib/llvm-project/clang/lib/Headers/rdpruintrin.h
Normal file
57
contrib/llvm-project/clang/lib/Headers/rdpruintrin.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*===---- rdpruintrin.h - RDPRU intrinsics ---------------------------------===
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*===-----------------------------------------------------------------------===
|
||||
*/
|
||||
|
||||
#if !defined __X86INTRIN_H
|
||||
#error "Never use <rdpruintrin.h> directly; include <x86intrin.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef __RDPRUINTRIN_H
|
||||
#define __RDPRUINTRIN_H
|
||||
|
||||
/* Define the default attributes for the functions in this file. */
|
||||
#define __DEFAULT_FN_ATTRS \
|
||||
__attribute__((__always_inline__, __nodebug__, __target__("rdpru")))
|
||||
|
||||
|
||||
/// Reads the content of a processor register.
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic corresponds to the <c> RDPRU </c> instruction.
|
||||
///
|
||||
/// \param reg_id
|
||||
/// A processor register identifier.
|
||||
static __inline__ unsigned long long __DEFAULT_FN_ATTRS
|
||||
__rdpru (int reg_id)
|
||||
{
|
||||
return __builtin_ia32_rdpru(reg_id);
|
||||
}
|
||||
|
||||
#define __RDPRU_MPERF 0
|
||||
#define __RDPRU_APERF 1
|
||||
|
||||
/// Reads the content of processor register MPERF.
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic generates instruction <c> RDPRU </c> to read the value of
|
||||
/// register MPERF.
|
||||
#define __mperf() __builtin_ia32_rdpru(__RDPRU_MPERF)
|
||||
|
||||
/// Reads the content of processor register APERF.
|
||||
///
|
||||
/// \headerfile <x86intrin.h>
|
||||
///
|
||||
/// This intrinsic generates instruction <c> RDPRU </c> to read the value of
|
||||
/// register APERF.
|
||||
#define __aperf() __builtin_ia32_rdpru(__RDPRU_APERF)
|
||||
|
||||
#undef __DEFAULT_FN_ATTRS
|
||||
|
||||
#endif /* __RDPRUINTRIN_H */
|
@ -158,10 +158,6 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
|
||||
|
||||
#define ATOMIC_FLAG_INIT { 0 }
|
||||
#if __cplusplus >= 202002L && !defined(_CLANG_DISABLE_CRT_DEPRECATION_WARNINGS)
|
||||
/* ATOMIC_FLAG_INIT was deprecated in C++20 but is not deprecated in C. */
|
||||
#pragma clang deprecated(ATOMIC_FLAG_INIT)
|
||||
#endif
|
||||
|
||||
/* These should be provided by the libc implementation. */
|
||||
#ifdef __cplusplus
|
||||
|
@ -59,5 +59,9 @@
|
||||
#include <clzerointrin.h>
|
||||
#endif
|
||||
|
||||
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
|
||||
defined(__RDPRU__)
|
||||
#include <rdpruintrin.h>
|
||||
#endif
|
||||
|
||||
#endif /* __X86INTRIN_H */
|
||||
|
@ -550,7 +550,7 @@ Scanner::tryLexIdentifierOrSkipLine(const char *&First, const char *const End) {
|
||||
StringRef Scanner::lexIdentifier(const char *&First, const char *const End) {
|
||||
Optional<StringRef> Id = tryLexIdentifierOrSkipLine(First, End);
|
||||
assert(Id && "expected identifier token");
|
||||
return Id.getValue();
|
||||
return Id.value();
|
||||
}
|
||||
|
||||
bool Scanner::isNextIdentifierOrSkipLine(StringRef Id, const char *&First,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user