Merge llvm-project main llvmorg-18-init-15692-g007ed0dccd6a

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvm-project main llvmorg-18-init-15692-g007ed0dccd6a.

PR:		276104
MFC after:	1 month

(cherry picked from commit cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
This commit is contained in:
Dimitry Andric 2023-12-25 18:35:41 +01:00
parent 1bc094c4a0
commit e710425beb
1000 changed files with 79194 additions and 91214 deletions

View file

@ -358,7 +358,8 @@ public:
///
/// \param IsKnownNewer \c true if this declaration is known to be newer
/// than \p OldD (for instance, if this declaration is newly-created).
bool declarationReplaces(NamedDecl *OldD, bool IsKnownNewer = true) const;
bool declarationReplaces(const NamedDecl *OldD,
bool IsKnownNewer = true) const;
/// Determine whether this declaration has linkage.
bool hasLinkage() const;
@ -4332,30 +4333,6 @@ public:
return field_begin() == field_end();
}
FieldDecl *getLastField() {
FieldDecl *FD = nullptr;
for (FieldDecl *Field : fields())
FD = Field;
return FD;
}
const FieldDecl *getLastField() const {
return const_cast<RecordDecl *>(this)->getLastField();
}
template <typename Functor>
const FieldDecl *findFieldIf(Functor &Pred) const {
for (const Decl *D : decls()) {
if (const auto *FD = dyn_cast<FieldDecl>(D); FD && Pred(FD))
return FD;
if (const auto *RD = dyn_cast<RecordDecl>(D))
if (const FieldDecl *FD = RD->findFieldIf(Pred))
return FD;
}
return nullptr;
}
/// Note that the definition of this type is now complete.
virtual void completeDefinition();

View file

@ -19,7 +19,6 @@
#include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "llvm/ADT/ArrayRef.h"
@ -489,15 +488,6 @@ public:
// Return true if this is a FileContext Decl.
bool isFileContextDecl() const;
/// Whether it resembles a flexible array member. This is a static member
/// because we want to be able to call it with a nullptr. That allows us to
/// perform non-Decl specific checks based on the object's type and strict
/// flex array level.
static bool isFlexibleArrayMemberLike(
ASTContext &Context, const Decl *D, QualType Ty,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution);
ASTContext &getASTContext() const LLVM_READONLY;
/// Helper to get the language options from the ASTContext.

View file

@ -2036,12 +2036,7 @@ bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \
if (TemplateParameterList *TPL = D->getTemplateParameters()) { \
for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); \
I != E; ++I) { \
TRY_TO(TraverseDecl(*I)); \
} \
} \
TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); \
/* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
D->getTemplateArgsAsWritten()->getTemplateArgs(), \

View file

@ -289,6 +289,22 @@ public:
/// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
StorageLocation *getStorageLocation(const Expr &E) const;
/// Returns the result of casting `getStorageLocation(...)` to a subclass of
/// `StorageLocation` (using `cast_or_null<T>`).
/// This assert-fails if the result of `getStorageLocation(...)` is not of
/// type `T *`; if the storage location is not guaranteed to have type `T *`,
/// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead.
template <typename T>
std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const ValueDecl &D) const {
return cast_or_null<T>(getStorageLocation(D));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
get(const Expr &E) const {
return cast_or_null<T>(getStorageLocation(E));
}
/// Returns the storage location assigned to the `this` pointee in the
/// environment or null if the `this` pointee has no assigned storage location
/// in the environment.
@ -325,7 +341,8 @@ public:
///
/// Requirements:
/// `E` must be a prvalue of record type.
RecordStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const;
/// Returns the return value of the current function. This can be null if:
/// - The function has a void return type
@ -434,24 +451,14 @@ public:
/// Assigns `Val` as the value of the prvalue `E` in the environment.
///
/// If `E` is not yet associated with a storage location, associates it with
/// a newly created storage location. In any case, associates the storage
/// location of `E` with `Val`.
///
/// Once the migration to strict handling of value categories is complete
/// (see https://discourse.llvm.org/t/70086), this function will be renamed to
/// `setValue()`. At this point, prvalue expressions will be associated
/// directly with `Value`s, and the legacy behavior of associating prvalue
/// expressions with storage locations (as described above) will be
/// eliminated.
///
/// Requirements:
///
/// `E` must be a prvalue
/// If `Val` is a `RecordValue`, its `RecordStorageLocation` must be the
/// same as that of any `RecordValue` that has already been associated with
/// `E`. This is to guarantee that the result object initialized by a prvalue
/// `RecordValue` has a durable storage location.
/// - `E` must be a prvalue
/// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be
/// `getResultObjectLocation(E)`. An exception to this is if `E` is an
/// expression that originally creates a `RecordValue` (such as a
/// `CXXConstructExpr` or `CallExpr`), as these establish the location of
/// the result object in the first place.
void setValue(const Expr &E, Value &Val);
/// Returns the value assigned to `Loc` in the environment or null if `Loc`
@ -466,6 +473,26 @@ public:
/// storage location in the environment, otherwise returns null.
Value *getValue(const Expr &E) const;
/// Returns the result of casting `getValue(...)` to a subclass of `Value`
/// (using `cast_or_null<T>`).
/// This assert-fails if the result of `getValue(...)` is not of type `T *`;
/// if the value is not guaranteed to have type `T *`, consider using
/// `dyn_cast_or_null<T>(getValue(...))` instead.
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const StorageLocation &Loc) const {
return cast_or_null<T>(getValue(Loc));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *>
get(const ValueDecl &D) const {
return cast_or_null<T>(getValue(D));
}
template <typename T>
std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const {
return cast_or_null<T>(getValue(E));
}
// FIXME: should we deprecate the following & call arena().create() directly?
/// Creates a `T` (some subclass of `Value`), forwarding `args` to the
@ -608,14 +635,6 @@ private:
// The copy-constructor is for use in fork() only.
Environment(const Environment &) = default;
/// Internal version of `setStorageLocation()` that doesn't check if the
/// expression is a prvalue.
void setStorageLocationInternal(const Expr &E, StorageLocation &Loc);
/// Internal version of `getStorageLocation()` that doesn't check if the
/// expression is a prvalue.
StorageLocation *getStorageLocationInternal(const Expr &E) const;
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
/// return null.
///
@ -708,20 +727,9 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);
/// Associates a new `RecordValue` with `Loc` and returns the new value.
/// It is not defined whether the field values remain the same or not.
///
/// This function is primarily intended for use by checks that set custom
/// properties on `RecordValue`s to model the state of these values. Such checks
/// should avoid modifying the properties of an existing `RecordValue` because
/// these changes would be visible to other `Environment`s that share the same
/// `RecordValue`. Instead, call `refreshRecordValue()`, then set the properties
/// on the new `RecordValue` that it returns. Typical usage:
///
/// refreshRecordValue(Loc, Env).setProperty("my_prop", MyPropValue);
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
/// Associates a new `RecordValue` with `Expr` and returns the new value.
/// See also documentation for the overload above.
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
} // namespace dataflow

View file

@ -22,19 +22,13 @@ namespace dataflow {
/// Copies a record (struct, class, or union) from `Src` to `Dst`.
///
/// This performs a deep copy, i.e. it copies every field (including synthetic
/// fields) and recurses on fields of record type. It also copies properties
/// from the `RecordValue` associated with `Src` to the `RecordValue` associated
/// with `Dst` (if these `RecordValue`s exist).
/// fields) and recurses on fields of record type.
///
/// If there is a `RecordValue` associated with `Dst` in the environment, this
/// function creates a new `RecordValue` and associates it with `Dst`; clients
/// need to be aware of this and must not assume that the `RecordValue`
/// associated with `Dst` remains the same after the call.
///
/// We create a new `RecordValue` rather than modifying properties on the old
/// `RecordValue` because the old `RecordValue` may be shared with other
/// `Environment`s, and we don't want changes to properties to be visible there.
///
/// Requirements:
///
/// `Src` and `Dst` must have the same canonical unqualified type.
@ -49,9 +43,7 @@ void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,
///
/// This performs a deep comparison, i.e. it compares every field (including
/// synthetic fields) and recurses on fields of record type. Fields of reference
/// type compare equal if they refer to the same storage location. If
/// `RecordValue`s are associated with `Loc1` and Loc2`, it also compares the
/// properties on those `RecordValue`s.
/// type compare equal if they refer to the same storage location.
///
/// Note on how to interpret the result:
/// - If this returns true, the records are guaranteed to be equal at runtime.

View file

@ -63,7 +63,11 @@ public:
/// Assigns `Val` as the value of the synthetic property with the given
/// `Name`.
///
/// Properties may not be set on `RecordValue`s; use synthetic fields instead
/// (for details, see documentation for `RecordStorageLocation`).
void setProperty(llvm::StringRef Name, Value &Val) {
assert(getKind() != Kind::Record);
Properties.insert_or_assign(Name, &Val);
}
@ -184,33 +188,23 @@ private:
/// In C++, prvalues of class type serve only a limited purpose: They can only
/// be used to initialize a result object. It is not possible to access member
/// variables or call member functions on a prvalue of class type.
/// Correspondingly, `RecordValue` also serves only two limited purposes:
/// - It conveys a prvalue of class type from the place where the object is
/// constructed to the result object that it initializes.
/// Correspondingly, `RecordValue` also serves only a limited purpose: It
/// conveys a prvalue of class type from the place where the object is
/// constructed to the result object that it initializes.
///
/// When creating a prvalue of class type, we already need a storage location
/// for `this`, even though prvalues are otherwise not associated with storage
/// locations. `RecordValue` is therefore essentially a wrapper for a storage
/// location, which is then used to set the storage location for the result
/// object when we process the AST node for that result object.
/// When creating a prvalue of class type, we already need a storage location
/// for `this`, even though prvalues are otherwise not associated with storage
/// locations. `RecordValue` is therefore essentially a wrapper for a storage
/// location, which is then used to set the storage location for the result
/// object when we process the AST node for that result object.
///
/// For example:
/// MyStruct S = MyStruct(3);
/// For example:
/// MyStruct S = MyStruct(3);
///
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
/// `RecordValue` that wraps a `RecordStorageLocation`. This
// `RecordStorageLocation` is then used as the storage location for `S`.
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
/// `RecordValue` that wraps a `RecordStorageLocation`. This
/// `RecordStorageLocation` is then used as the storage location for `S`.
///
/// - It allows properties to be associated with an object of class type.
/// Note that when doing so, you should avoid mutating the properties of an
/// existing `RecordValue` in place, as these changes would be visible to
/// other `Environment`s that share the same `RecordValue`. Instead, associate
/// a new `RecordValue` with the `RecordStorageLocation` and set the
/// properties on this new `RecordValue`. (See also `refreshRecordValue()` in
/// DataflowEnvironment.h, which makes this easy.)
/// Note also that this implies that it is common for the same
/// `RecordStorageLocation` to be associated with different `RecordValue`s
/// in different environments.
/// Over time, we may eliminate `RecordValue` entirely. See also the discussion
/// here: https://reviews.llvm.org/D155204#inline-1503204
class RecordValue final : public Value {

View file

@ -4331,24 +4331,6 @@ def AvailableOnlyInDefaultEvalMethod : InheritableAttr {
let Documentation = [Undocumented];
}
def CountedBy : InheritableAttr {
let Spellings = [Clang<"counted_by">];
let Subjects = SubjectList<[Field]>;
let Args = [IdentifierArgument<"CountedByField">];
let Documentation = [CountedByDocs];
let LangOpts = [COnly];
// FIXME: This is ugly. Let using a DeclArgument would be nice, but a Decl
// isn't yet available due to the fact that we're still parsing the
// structure. Maybe that code could be changed sometime in the future.
code AdditionalMembers = [{
private:
SourceRange CountedByFieldLoc;
public:
SourceRange getCountedByFieldLoc() const { return CountedByFieldLoc; }
void setCountedByFieldLoc(SourceRange Loc) { CountedByFieldLoc = Loc; }
}];
}
def PreferredType: InheritableAttr {
let Spellings = [Clang<"preferred_type">];
let Subjects = SubjectList<[BitField], ErrorDiag>;

View file

@ -7500,72 +7500,6 @@ attribute, they default to the value ``65535``.
}];
}
def CountedByDocs : Documentation {
let Category = DocCatField;
let Content = [{
Clang supports the ``counted_by`` attribute on the flexible array member of a
structure in C. The argument for the attribute is the name of a field member in
the same structure holding the count of elements in the flexible array. This
information can be used to improve the results of the array bound sanitizer and
the ``__builtin_dynamic_object_size`` builtin.
For example, the following code:
.. code-block:: c
struct bar;
struct foo {
size_t count;
char other;
struct bar *array[] __attribute__((counted_by(count)));
};
specifies that the flexible array member ``array`` has the number of elements
allocated for it stored in ``count``. This establishes a relationship between
``array`` and ``count``. Specifically, ``p->array`` must have at least
``p->count`` number of elements available. It's the user's responsibility to
ensure that this relationship is maintained through changes to the structure.
In the following example, the allocated array erroneously has fewer elements
than what's specified by ``p->count``. This would result in an out-of-bounds
access not being detected.
.. code-block:: c
#define SIZE_INCR 42
struct foo *p;
void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
p->count = count + SIZE_INCR;
}
The next example updates ``p->count``, breaking the relationship requirement
that ``p->array`` must have at least ``p->count`` number of elements available:
.. code-block:: c
#define SIZE_INCR 42
struct foo *p;
void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count * sizeof(struct bar *)));
p->count = count;
}
void use_foo(int index) {
p->count += SIZE_INCR + 1; /* 'count' is now larger than the number of elements of 'array'. */
p->array[index] = 0; /* the sanitizer can't properly check if this is an out-of-bounds access. */
}
}];
}
def CoroOnlyDestroyWhenCompleteDocs : Documentation {
let Category = DocCatDecl;
let Content = [{

View file

@ -348,7 +348,8 @@ def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic",
CXXPre20CompatPedantic,
CXXPre23CompatPedantic]>;
def CXX11Narrowing : DiagGroup<"c++11-narrowing">;
def CXX11NarrowingConstReference : DiagGroup<"c++11-narrowing-const-reference">;
def CXX11Narrowing : DiagGroup<"c++11-narrowing", [CXX11NarrowingConstReference]>;
def CXX11WarnInconsistentOverrideDestructor :
DiagGroup<"inconsistent-missing-destructor-override">;
@ -1488,4 +1489,5 @@ def DXILValidation : DiagGroup<"dxil-validation">;
def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
// Warnings and fixes to support the "safe buffers" programming model.
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage">;
def UnsafeBufferUsageInContainer : DiagGroup<"unsafe-buffer-usage-in-container">;
def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInContainer]>;

View file

@ -1358,11 +1358,9 @@ def err_acc_unexpected_directive
def warn_pragma_acc_unimplemented
: Warning<"OpenACC directives not yet implemented, pragma ignored">,
InGroup<SourceUsesOpenACC>;
def warn_pragma_acc_unimplemented_clause_parsing
: Warning<"OpenACC clause parsing not yet implemented">,
InGroup<SourceUsesOpenACC>;
def err_acc_invalid_directive
: Error<"invalid OpenACC directive %select{%1|'%1 %2'}0">;
def err_acc_invalid_clause : Error<"invalid OpenACC clause %0">;
def err_acc_missing_directive : Error<"expected OpenACC directive">;
def err_acc_invalid_open_paren
: Error<"expected clause-list or newline in OpenACC directive">;

View file

@ -3155,6 +3155,9 @@ def err_attribute_arm_feature_sve_bits_unsupported : Error<
def warn_attribute_arm_sm_incompat_builtin : Warning<
"builtin call has undefined behaviour when called from a %0 function">,
InGroup<DiagGroup<"undefined-arm-streaming">>;
def warn_attribute_arm_za_builtin_no_za_state : Warning<
"builtin call is not valid when calling from a function without active ZA state">,
InGroup<DiagGroup<"undefined-arm-za">>;
def err_sve_vector_in_non_sve_target : Error<
"SVE vector type %0 cannot be used in a target without sve">;
def err_attribute_riscv_rvv_bits_unsupported : Error<
@ -6155,12 +6158,24 @@ def err_illegal_initializer_type : Error<"illegal initializer type %0">;
def ext_init_list_type_narrowing : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
// *_narrowing_const_reference diagnostics have the same messages, but are
// controlled by -Wc++11-narrowing-const-reference for narrowing involving a
// const reference.
def ext_init_list_type_narrowing_const_reference : ExtWarn<
"type %0 cannot be narrowed to %1 in initializer list">,
InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def ext_init_list_variable_narrowing : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_variable_narrowing_const_reference : ExtWarn<
"non-constant-expression cannot be narrowed from type %0 to %1 in "
"initializer list">, InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def ext_init_list_constant_narrowing : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
def ext_init_list_constant_narrowing_const_reference : ExtWarn<
"constant expression evaluates to %0 which cannot be narrowed to type %1">,
InGroup<CXX11NarrowingConstReference>, DefaultError, SFINAEFailure;
def warn_init_list_type_narrowing : Warning<
"type %0 cannot be narrowed to %1 in initializer list in C++11">,
InGroup<CXX11Narrowing>, DefaultIgnore;
@ -6426,17 +6441,6 @@ def warn_superclass_variable_sized_type_not_at_end : Warning<
"field %0 can overwrite instance variable %1 with variable sized type %2"
" in superclass %3">, InGroup<ObjCFlexibleArray>;
def err_counted_by_attr_not_on_flexible_array_member : Error<
"'counted_by' only applies to C99 flexible array members">;
def err_counted_by_attr_refers_to_flexible_array : Error<
"'counted_by' cannot refer to the flexible array %0">;
def err_counted_by_must_be_in_structure : Error<
"field %0 in 'counted_by' not inside structure">;
def err_flexible_array_counted_by_attr_field_not_integer : Error<
"field %0 in 'counted_by' must be a non-boolean integer type">;
def note_flexible_array_counted_by_attr_field : Note<
"field %0 declared here">;
let CategoryName = "ARC Semantic Issue" in {
// ARC-mode diagnostics.
@ -11368,6 +11372,8 @@ def err_openmp_vla_in_task_untied : Error<
def warn_omp_unterminated_declare_target : Warning<
"expected '#pragma omp end declare target' at end of file to match '#pragma omp %0'">,
InGroup<SourceUsesOpenMP>;
def err_ompx_bare_no_grid : Error<
"'ompx_bare' clauses requires explicit grid size via 'num_teams' and 'thread_limit' clauses">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {

View file

@ -456,6 +456,7 @@ ENUM_LANGOPT(SignReturnAddressScope, SignReturnAddressScopeKind, 2, SignReturnAd
ENUM_LANGOPT(SignReturnAddressKey, SignReturnAddressKeyKind, 1, SignReturnAddressKeyKind::AKey,
"Key used for return address signing")
LANGOPT(BranchTargetEnforcement, 1, 0, "Branch-target enforcement enabled")
LANGOPT(BranchProtectionPAuthLR, 1, 0, "Use PC as a diversifier using PAuthLR NOP instructions.")
LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled")

View file

@ -69,6 +69,30 @@ enum class OpenACCAtomicKind {
Capture,
Invalid,
};
/// Represents the kind of an OpenACC clause.
enum class OpenACCClauseKind {
// 'finalize' clause, allowed on 'exit data' directive.
Finalize,
// 'if_present' clause, allowed on 'host_data' and 'update' directives.
IfPresent,
// 'seq' clause, allowed on 'loop' and 'routine' directives.
Seq,
// 'independent' clause, allowed on 'loop' directives.
Independent,
// 'auto' clause, allowed on 'loop' directives.
Auto,
// 'worker' clause, allowed on 'loop' and 'routine' directives.
Worker,
// 'vector' clause, allowed on 'loop' and 'routine' directives. Takes no
// arguments for 'routine', so the 'loop' version is not yet implemented
// completely.
Vector,
// 'nohost' clause, allowed on 'routine' directives.
NoHost,
// Represents an invalid clause, for the purposes of parsing.
Invalid,
};
} // namespace clang
#endif // LLVM_CLANG_BASIC_OPENACCKINDS_H

View file

@ -77,8 +77,7 @@ inline raw_ostream &EmitInteger(raw_ostream &o, int64_t value) {
inline raw_ostream &EmitString(raw_ostream &o, StringRef s) {
o << "<string>";
for (StringRef::const_iterator I = s.begin(), E = s.end(); I != E; ++I) {
char c = *I;
for (char c : s) {
switch (c) {
default:
o << c;

View file

@ -1372,6 +1372,7 @@ public:
LangOptions::SignReturnAddressKeyKind SignKey =
LangOptions::SignReturnAddressKeyKind::AKey;
bool BranchTargetEnforcement = false;
bool BranchProtectionPAuthLR = false;
};
/// Determine if the Architecture in this TargetInfo supports branch

View file

@ -40,6 +40,9 @@ namespace clang {
/// string as getClangRevision.
std::string getLLVMRevision();
/// Retrieves the Clang vendor tag.
std::string getClangVendor();
/// Retrieves the full repository version that is an amalgamation of
/// the information in getClangRepositoryPath() and getClangRevision().
std::string getClangFullRepositoryVersion();

View file

@ -299,6 +299,44 @@ multiclass ZAAddSub<string n_suffix> {
defm SVADD : ZAAddSub<"add">;
defm SVSUB : ZAAddSub<"sub">;
// SME2 - MOVA
//
// Single, 2 and 4 vector-group read/write intrinsics.
//
multiclass ZAWrite_VG<string n, string t, string i, list<ImmCheck> checks> {
def NAME # _VG2_H : Inst<"svwrite_hor_" # n # "[_{d}]_vg2", "vim2", t, MergeNone, i # "_hor_vg2", [IsSharedZA, IsStreaming], checks>;
def NAME # _VG2_V : Inst<"svwrite_ver_" # n # "[_{d}]_vg2", "vim2", t, MergeNone, i # "_ver_vg2", [IsSharedZA, IsStreaming], checks>;
def NAME # _VG4_H : Inst<"svwrite_hor_" # n # "[_{d}]_vg4", "vim4", t, MergeNone, i # "_hor_vg4", [IsSharedZA, IsStreaming], checks>;
def NAME # _VG4_V : Inst<"svwrite_ver_" # n # "[_{d}]_vg4", "vim4", t, MergeNone, i # "_ver_vg4", [IsSharedZA, IsStreaming], checks>;
def NAME # _VG1x2 : Inst<"svwrite_" # n # "[_{d}]_vg1x2", "vm2", t, MergeNone, i # "_vg1x2", [IsSharedZA, IsStreaming], []>;
def NAME # _VG1x4 : Inst<"svwrite_" # n # "[_{d}]_vg1x4", "vm4", t, MergeNone, i # "_vg1x4", [IsSharedZA, IsStreaming], []>;
}
let TargetGuard = "sme2" in {
defm SVWRITE_ZA8 : ZAWrite_VG<"za8", "cUc", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_0>]>;
defm SVWRITE_ZA16 : ZAWrite_VG<"za16", "sUshb", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_1>]>;
defm SVWRITE_ZA32 : ZAWrite_VG<"za32", "iUif", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_3>]>;
defm SVWRITE_ZA64 : ZAWrite_VG<"za64", "lUld", "aarch64_sme_write", [ImmCheck<0, ImmCheck0_7>]>;
}
multiclass ZARead_VG<string n, string t, string i, list<ImmCheck> checks> {
def NAME # _VG2_H : Inst<"svread_hor_" # n # "_{d}_vg2", "2im", t, MergeNone, i # "_hor_vg2", [IsSharedZA, IsPreservesZA, IsStreaming], checks>;
def NAME # _VG2_V : Inst<"svread_ver_" # n # "_{d}_vg2", "2im", t, MergeNone, i # "_ver_vg2", [IsSharedZA, IsPreservesZA, IsStreaming], checks>;
def NAME # _VG4_H : Inst<"svread_hor_" # n # "_{d}_vg4", "4im", t, MergeNone, i # "_hor_vg4", [IsSharedZA, IsPreservesZA, IsStreaming], checks>;
def NAME # _VG4_V : Inst<"svread_ver_" # n # "_{d}_vg4", "4im", t, MergeNone, i # "_ver_vg4", [IsSharedZA, IsPreservesZA, IsStreaming], checks>;
def NAME # _VG1x2 : Inst<"svread_" # n # "_{d}_vg1x2", "2m", t, MergeNone, i # "_vg1x2", [IsSharedZA, IsPreservesZA, IsStreaming], []>;
def NAME # _VG1x4 : Inst<"svread_" # n # "_{d}_vg1x4", "4m", t, MergeNone, i # "_vg1x4", [IsSharedZA, IsPreservesZA, IsStreaming], []>;
}
let TargetGuard = "sme2" in {
defm SVREAD_ZA8 : ZARead_VG<"za8", "cUc", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_0>]>;
defm SVREAD_ZA16 : ZARead_VG<"za16", "sUshb", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_1>]>;
defm SVREAD_ZA32 : ZARead_VG<"za32", "iUif", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_3>]>;
defm SVREAD_ZA64 : ZARead_VG<"za64", "lUld", "aarch64_sme_read", [ImmCheck<0, ImmCheck0_7>]>;
}
//
// Outer product and accumulate/subtract
//
@ -313,6 +351,285 @@ let TargetGuard = "sme2" in {
def SVBMOPA : Inst<"svbmopa_za32[_{d}]_m", "viPPdd", "iUi", MergeNone, "aarch64_sme_bmopa_za32", [IsSharedZA, IsStreaming], [ImmCheck<0, ImmCheck0_3>]>;
def SVBMOPS : Inst<"svbmops_za32[_{d}]_m", "viPPdd", "iUi", MergeNone, "aarch64_sme_bmops_za32", [IsSharedZA, IsStreaming], [ImmCheck<0, ImmCheck0_3>]>;
// VERTICAL DOT-PRODUCT
def SVVDOT_LANE_ZA32_VG1x2_S : Inst<"svvdot_lane_za32[_{d}]_vg1x2", "vm2di", "s", MergeNone, "aarch64_sme_svdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVVDOT_LANE_ZA32_VG1x4_S : Inst<"svvdot_lane_za32[_{d}]_vg1x4", "vm4di", "c", MergeNone, "aarch64_sme_svdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVVDOT_LANE_ZA32_VG1x2_U : Inst<"svvdot_lane_za32[_{d}]_vg1x2", "vm2di", "Us", MergeNone, "aarch64_sme_uvdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVVDOT_LANE_ZA32_VG1x4_U : Inst<"svvdot_lane_za32[_{d}]_vg1x4", "vm4di", "Uc", MergeNone, "aarch64_sme_uvdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVVDOT_LANE_ZA32_VG1x2_F : Inst<"svvdot_lane_za32[_{d}]_vg1x2", "vm2di", "hb", MergeNone, "aarch64_sme_fvdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVSUVDOT_LANE_ZA32_VG1x4 : Inst<"svsuvdot_lane_za32[_{d}]_vg1x4", "vm4di", "c", MergeNone, "aarch64_sme_suvdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVUSVDOT_LANE_ZA32_VG1x4 : Inst<"svusvdot_lane_za32[_{d}]_vg1x4", "vm4di", "Uc", MergeNone, "aarch64_sme_usvdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
// Multi-vector signed & unsigned integer dot-product
def SVDOT_MULTI_ZA32_VG1x2_S : Inst<"svdot_za32[_{d}]_vg1x2", "vm22", "cs", MergeNone, "aarch64_sme_sdot_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA32_VG1x4_S : Inst<"svdot_za32[_{d}]_vg1x4", "vm44", "cs", MergeNone, "aarch64_sme_sdot_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA32_VG1x2_U : Inst<"svdot_za32[_{d}]_vg1x2", "vm22", "UcUs", MergeNone, "aarch64_sme_udot_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA32_VG1x4_U : Inst<"svdot_za32[_{d}]_vg1x4", "vm44", "UcUs", MergeNone, "aarch64_sme_udot_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x2_S : Inst<"svdot[_single]_za32[_{d}]_vg1x2", "vm2d", "cs", MergeNone, "aarch64_sme_sdot_single_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x4_S : Inst<"svdot[_single]_za32[_{d}]_vg1x4", "vm4d", "cs", MergeNone, "aarch64_sme_sdot_single_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x2_U : Inst<"svdot[_single]_za32[_{d}]_vg1x2", "vm2d", "UcUs", MergeNone, "aarch64_sme_udot_single_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x4_U : Inst<"svdot[_single]_za32[_{d}]_vg1x4", "vm4d", "UcUs", MergeNone, "aarch64_sme_udot_single_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_LANE_ZA32_VG1x2_S : Inst<"svdot_lane_za32[_{d}]_vg1x2", "vm2di", "cs", MergeNone, "aarch64_sme_sdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVDOT_LANE_ZA32_VG1x4_S : Inst<"svdot_lane_za32[_{d}]_vg1x4", "vm4di", "cs", MergeNone, "aarch64_sme_sdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVDOT_LANE_ZA32_VG1x2_U : Inst<"svdot_lane_za32[_{d}]_vg1x2", "vm2di", "UcUs", MergeNone, "aarch64_sme_udot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVDOT_LANE_ZA32_VG1x4_U : Inst<"svdot_lane_za32[_{d}]_vg1x4", "vm4di", "UcUs", MergeNone, "aarch64_sme_udot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVUSDOT_SINGLE_ZA32_VG1x2 : Inst<"svusdot[_single]_za32[_{d}]_vg1x2", "vm2.dx", "Uc", MergeNone, "aarch64_sme_usdot_single_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVUSDOT_SINGLE_ZA32_VG1x4 : Inst<"svusdot[_single]_za32[_{d}]_vg1x4", "vm4.dx", "Uc", MergeNone, "aarch64_sme_usdot_single_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVUSDOT_MULTI_ZA32_VG1x2 : Inst<"svusdot_za32[_{d}]_vg1x2", "vm2.d2.x", "Uc", MergeNone, "aarch64_sme_usdot_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVUSDOT_MULTI_ZA32_VG1x4 : Inst<"svusdot_za32[_{d}]_vg1x4", "vm4.d4.x", "Uc", MergeNone, "aarch64_sme_usdot_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVUSDOT_LANE_ZA32_VG1x2 : Inst<"svusdot_lane_za32[_{d}]_vg1x2", "vm2.dxi", "Uc", MergeNone, "aarch64_sme_usdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVUSDOT_LANE_ZA32_VG1x4 : Inst<"svusdot_lane_za32[_{d}]_vg1x4", "vm4.dxi", "Uc", MergeNone, "aarch64_sme_usdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVSUDOT_SINGLE_ZA32_VG1x2 : Inst<"svsudot[_single]_za32[_{d}]_vg1x2", "vm2.du", "c", MergeNone, "aarch64_sme_sudot_single_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVSUDOT_SINGLE_ZA32_VG1x4 : Inst<"svsudot[_single]_za32[_{d}]_vg1x4", "vm4.du", "c", MergeNone, "aarch64_sme_sudot_single_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
// Multi-multi sudot builtins are mapped to usdot, with zn & zm operands swapped
def SVSUDOT_MULTI_ZA32_VG1x2 : Inst<"svsudot_za32[_{d}]_vg1x2", "vm2.d2.u", "c", MergeNone, "aarch64_sme_usdot_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVSUDOT_MULTI_ZA32_VG1x4 : Inst<"svsudot_za32[_{d}]_vg1x4", "vm4.d4.u", "c", MergeNone, "aarch64_sme_usdot_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVSUDOT_LANE_ZA32_VG1x2 : Inst<"svsudot_lane_za32[_{d}]_vg1x2", "vm2.dui", "c", MergeNone, "aarch64_sme_sudot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVSUDOT_LANE_ZA32_VG1x4 : Inst<"svsudot_lane_za32[_{d}]_vg1x4", "vm4.dui", "c", MergeNone, "aarch64_sme_sudot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
// Multi-vector half-precision/BFloat16 floating-point dot-product
def SVDOT_MULTI_ZA32_VG1x2_F16 : Inst<"svdot_za32[_{d}]_vg1x2", "vm22", "bh", MergeNone, "aarch64_sme_fdot_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA32_VG1x4_F16 : Inst<"svdot_za32[_{d}]_vg1x4", "vm44", "bh", MergeNone, "aarch64_sme_fdot_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x2_F16 : Inst<"svdot[_single]_za32[_{d}]_vg1x2", "vm2d", "bh", MergeNone, "aarch64_sme_fdot_single_za32_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA32_VG1x4_F16 : Inst<"svdot[_single]_za32[_{d}]_vg1x4", "vm4d", "bh", MergeNone, "aarch64_sme_fdot_single_za32_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_LANE_ZA32_VG1x2_F16 : Inst<"svdot_lane_za32[_{d}]_vg1x2", "vm2di", "bh", MergeNone, "aarch64_sme_fdot_lane_za32_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVDOT_LANE_ZA32_VG1x4_F16 : Inst<"svdot_lane_za32[_{d}]_vg1x4", "vm4di", "bh", MergeNone, "aarch64_sme_fdot_lane_za32_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
}
let TargetGuard = "sme2,sme-i16i64" in {
def SVVDOT_LANE_ZA64_VG1x4_S : Inst<"svvdot_lane_za64[_{d}]_vg1x4", "vm4di", "s", MergeNone, "aarch64_sme_svdot_lane_za64_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVVDOT_LANE_ZA64_VG1x4_U : Inst<"svvdot_lane_za64[_{d}]_vg1x4", "vm4di", "Us", MergeNone, "aarch64_sme_uvdot_lane_za64_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVDOT_MULTI_ZA64_VG1x2_S16 : Inst<"svdot_za64[_{d}]_vg1x2", "vm22", "s", MergeNone, "aarch64_sme_sdot_za64_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA64_VG1x4_S16 : Inst<"svdot_za64[_{d}]_vg1x4", "vm44", "s", MergeNone, "aarch64_sme_sdot_za64_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA64_VG1x2_U16 : Inst<"svdot_za64[_{d}]_vg1x2", "vm22", "Us", MergeNone, "aarch64_sme_udot_za64_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_MULTI_ZA64_VG1x4_U16 : Inst<"svdot_za64[_{d}]_vg1x4", "vm44", "Us", MergeNone, "aarch64_sme_udot_za64_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA64_VG1x2_S16 : Inst<"svdot[_single]_za64[_{d}]_vg1x2", "vm2d", "s", MergeNone, "aarch64_sme_sdot_single_za64_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA64_VG1x4_S16 : Inst<"svdot[_single]_za64[_{d}]_vg1x4", "vm4d", "s", MergeNone, "aarch64_sme_sdot_single_za64_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA64_VG1x2_U16 : Inst<"svdot[_single]_za64[_{d}]_vg1x2", "vm2d", "Us", MergeNone, "aarch64_sme_udot_single_za64_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVDOT_SINGLE_ZA64_VG1x4_U16 : Inst<"svdot[_single]_za64[_{d}]_vg1x4", "vm4d", "Us", MergeNone, "aarch64_sme_udot_single_za64_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVDOT_LANE_ZA64_VG1x2_S16 : Inst<"svdot_lane_za64[_{d}]_vg1x2", "vm2di", "s", MergeNone, "aarch64_sme_sdot_lane_za64_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVDOT_LANE_ZA64_VG1x4_S16 : Inst<"svdot_lane_za64[_{d}]_vg1x4", "vm4di", "s", MergeNone, "aarch64_sme_sdot_lane_za64_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVDOT_LANE_ZA64_VG1x2_U16 : Inst<"svdot_lane_za64[_{d}]_vg1x2", "vm2di", "Us", MergeNone, "aarch64_sme_udot_lane_za64_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVDOT_LANE_ZA64_VG1x4_U16 : Inst<"svdot_lane_za64[_{d}]_vg1x4", "vm4di", "Us", MergeNone, "aarch64_sme_udot_lane_za64_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
}
// FMLA/FMLS
let TargetGuard = "sme2" in {
def SVMLA_MULTI_VG1x2_F32 : Inst<"svmla_za32[_{d}]_vg1x2", "vm22", "f", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLA_MULTI_VG1x4_F32 : Inst<"svmla_za32[_{d}]_vg1x4", "vm44", "f", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLS_MULTI_VG1x2_F32 : Inst<"svmls_za32[_{d}]_vg1x2", "vm22", "f", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLS_MULTI_VG1x4_F32 : Inst<"svmls_za32[_{d}]_vg1x4", "vm44", "f", MergeNone, "aarch64_sme_fmls_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLA_SINGLE_VG1x2_F32 : Inst<"svmla[_single]_za32[_{d}]_vg1x2", "vm2d", "f", MergeNone, "aarch64_sme_fmla_single_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLA_SINGLE_VG1x4_F32 : Inst<"svmla[_single]_za32[_{d}]_vg1x4", "vm4d", "f", MergeNone, "aarch64_sme_fmla_single_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLS_SINGLE_VG1x2_F32 : Inst<"svmls[_single]_za32[_{d}]_vg1x2", "vm2d", "f", MergeNone, "aarch64_sme_fmls_single_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLS_SINGLE_VG1x4_F32 : Inst<"svmls[_single]_za32[_{d}]_vg1x4", "vm4d", "f", MergeNone, "aarch64_sme_fmls_single_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLA_LANE_VG1x2_F32 : Inst<"svmla_lane_za32[_{d}]_vg1x2", "vm2di", "f", MergeNone, "aarch64_sme_fmla_lane_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVMLA_LANE_VG1x4_F32 : Inst<"svmla_lane_za32[_{d}]_vg1x4", "vm4di", "f", MergeNone, "aarch64_sme_fmla_lane_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVMLS_LANE_VG1x2_F32 : Inst<"svmls_lane_za32[_{d}]_vg1x2", "vm2di", "f", MergeNone, "aarch64_sme_fmls_lane_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
def SVMLS_LANE_VG1x4_F32 : Inst<"svmls_lane_za32[_{d}]_vg1x4", "vm4di", "f", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_3>]>;
}
let TargetGuard = "sme2,sme-f64f64" in {
def SVMLA_MULTI_VG1x2_F64 : Inst<"svmla_za64[_{d}]_vg1x2", "vm22", "d", MergeNone, "aarch64_sme_fmla_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLA_MULTI_VG1x4_F64 : Inst<"svmla_za64[_{d}]_vg1x4", "vm44", "d", MergeNone, "aarch64_sme_fmla_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLS_MULTI_VG1x2_F64 : Inst<"svmls_za64[_{d}]_vg1x2", "vm22", "d", MergeNone, "aarch64_sme_fmls_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLS_MULTI_VG1x4_F64 : Inst<"svmls_za64[_{d}]_vg1x4", "vm44", "d", MergeNone, "aarch64_sme_fmls_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLA_SINGLE_VG1x2_F64 : Inst<"svmla[_single]_za64[_{d}]_vg1x2", "vm2d", "d", MergeNone, "aarch64_sme_fmla_single_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLA_SINGLE_VG1x4_F64 : Inst<"svmla[_single]_za64[_{d}]_vg1x4", "vm4d", "d", MergeNone, "aarch64_sme_fmla_single_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLS_SINGLE_VG1x2_F64 : Inst<"svmls[_single]_za64[_{d}]_vg1x2", "vm2d", "d", MergeNone, "aarch64_sme_fmls_single_vg1x2", [IsStreaming, IsSharedZA], []>;
def SVMLS_SINGLE_VG1x4_F64 : Inst<"svmls[_single]_za64[_{d}]_vg1x4", "vm4d", "d", MergeNone, "aarch64_sme_fmls_single_vg1x4", [IsStreaming, IsSharedZA], []>;
def SVMLA_LANE_VG1x2_F64 : Inst<"svmla_lane_za64[_{d}]_vg1x2", "vm2di", "d", MergeNone, "aarch64_sme_fmla_lane_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVMLA_LANE_VG1x4_F64 : Inst<"svmla_lane_za64[_{d}]_vg1x4", "vm4di", "d", MergeNone, "aarch64_sme_fmla_lane_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVMLS_LANE_VG1x2_F64 : Inst<"svmls_lane_za64[_{d}]_vg1x2", "vm2di", "d", MergeNone, "aarch64_sme_fmls_lane_vg1x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
def SVMLS_LANE_VG1x4_F64 : Inst<"svmls_lane_za64[_{d}]_vg1x4", "vm4di", "d", MergeNone, "aarch64_sme_fmls_lane_vg1x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_1>]>;
}
// FMLAL/FMLSL/UMLAL/SMLAL
// SMLALL/UMLALL/USMLALL/SUMLALL
let TargetGuard = "sme2" in {
// MULTI MLAL
def SVMLAL_MULTI_VG2x2_F16 : Inst<"svmla_za32[_{d}]_vg2x2", "vm22", "bh", MergeNone, "aarch64_sme_fmlal_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG2x4_F16 : Inst<"svmla_za32[_{d}]_vg2x4", "vm44", "bh", MergeNone, "aarch64_sme_fmlal_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG2x2_S16 : Inst<"svmla_za32[_{d}]_vg2x2", "vm22", "s", MergeNone, "aarch64_sme_smlal_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG2x4_S16 : Inst<"svmla_za32[_{d}]_vg2x4", "vm44", "s", MergeNone, "aarch64_sme_smlal_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG2x2_U16 : Inst<"svmla_za32[_{d}]_vg2x2", "vm22", "Us", MergeNone, "aarch64_sme_umlal_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG2x4_U16 : Inst<"svmla_za32[_{d}]_vg2x4", "vm44", "Us", MergeNone, "aarch64_sme_umlal_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x2_S8 : Inst<"svmla_za32[_{d}]_vg4x2", "vm22", "c", MergeNone, "aarch64_sme_smla_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x2_U8 : Inst<"svmla_za32[_{d}]_vg4x2", "vm22", "Uc", MergeNone, "aarch64_sme_umla_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x4_S8 : Inst<"svmla_za32[_{d}]_vg4x4", "vm44", "c", MergeNone, "aarch64_sme_smla_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x4_U8 : Inst<"svmla_za32[_{d}]_vg4x4", "vm44", "Uc", MergeNone, "aarch64_sme_umla_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
// MULTI MLSL
def SVMLSL_MULTI_VG2x2_F16 : Inst<"svmls_za32[_{d}]_vg2x2", "vm22", "bh", MergeNone, "aarch64_sme_fmlsl_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG2x4_F16 : Inst<"svmls_za32[_{d}]_vg2x4", "vm44", "bh", MergeNone, "aarch64_sme_fmlsl_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG2x2_S16 : Inst<"svmls_za32[_{d}]_vg2x2", "vm22", "s", MergeNone, "aarch64_sme_smlsl_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG2x4_S16 : Inst<"svmls_za32[_{d}]_vg2x4", "vm44", "s", MergeNone, "aarch64_sme_smlsl_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG2x2_U16 : Inst<"svmls_za32[_{d}]_vg2x2", "vm22", "Us", MergeNone, "aarch64_sme_umlsl_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG2x4_U16 : Inst<"svmls_za32[_{d}]_vg2x4", "vm44", "Us", MergeNone, "aarch64_sme_umlsl_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x2_S8 : Inst<"svmls_za32[_{d}]_vg4x2", "vm22", "c", MergeNone, "aarch64_sme_smls_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x2_U8 : Inst<"svmls_za32[_{d}]_vg4x2", "vm22", "Uc", MergeNone, "aarch64_sme_umls_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x4_S8 : Inst<"svmls_za32[_{d}]_vg4x4", "vm44", "c", MergeNone, "aarch64_sme_smls_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x4_U8 : Inst<"svmls_za32[_{d}]_vg4x4", "vm44", "Uc", MergeNone, "aarch64_sme_umls_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
// SINGLE MLAL
def SVMLAL_SINGLE_VG2x1_F16 : Inst<"svmla_za32[_{d}]_vg2x1", "vmdd", "bh", MergeNone, "aarch64_sme_fmlal_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x2_F16 : Inst<"svmla[_single]_za32[_{d}]_vg2x2", "vm2d", "bh", MergeNone, "aarch64_sme_fmlal_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x4_F16 : Inst<"svmla[_single]_za32[_{d}]_vg2x4", "vm4d", "bh", MergeNone, "aarch64_sme_fmlal_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x1_S16 : Inst<"svmla_za32[_{d}]_vg2x1", "vmdd", "s", MergeNone, "aarch64_sme_smlal_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x2_S16 : Inst<"svmla[_single]_za32[_{d}]_vg2x2", "vm2d", "s", MergeNone, "aarch64_sme_smlal_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x4_S16 : Inst<"svmla[_single]_za32[_{d}]_vg2x4", "vm4d", "s", MergeNone, "aarch64_sme_smlal_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x1_U16 : Inst<"svmla_za32[_{d}]_vg2x1", "vmdd", "Us", MergeNone, "aarch64_sme_umlal_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x2_U16 : Inst<"svmla[_single]_za32[_{d}]_vg2x2", "vm2d", "Us", MergeNone, "aarch64_sme_umlal_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG2x4_U16 : Inst<"svmla[_single]_za32[_{d}]_vg2x4", "vm4d", "Us", MergeNone, "aarch64_sme_umlal_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x1_S8 : Inst<"svmla_za32[_{d}]_vg4x1", "vmdd", "c", MergeNone, "aarch64_sme_smla_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x1_U8 : Inst<"svmla_za32[_{d}]_vg4x1", "vmdd", "Uc", MergeNone, "aarch64_sme_umla_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x2_S8 : Inst<"svmla[_single]_za32[_{d}]_vg4x2", "vm2d", "c", MergeNone, "aarch64_sme_smla_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x2_U8 : Inst<"svmla[_single]_za32[_{d}]_vg4x2", "vm2d", "Uc", MergeNone, "aarch64_sme_umla_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x4_S8 : Inst<"svmla[_single]_za32[_{d}]_vg4x4", "vm4d", "c", MergeNone, "aarch64_sme_smla_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x4_U8 : Inst<"svmla[_single]_za32[_{d}]_vg4x4", "vm4d", "Uc", MergeNone, "aarch64_sme_umla_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// SINGLE MLSL
def SVMLSL_SINGLE_VG2x1_F16 : Inst<"svmls_za32[_{d}]_vg2x1", "vmdd", "bh", MergeNone, "aarch64_sme_fmlsl_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x2_F16 : Inst<"svmls[_single]_za32[_{d}]_vg2x2", "vm2d", "bh", MergeNone, "aarch64_sme_fmlsl_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x4_F16 : Inst<"svmls[_single]_za32[_{d}]_vg2x4", "vm4d", "bh", MergeNone, "aarch64_sme_fmlsl_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x1_S16 : Inst<"svmls_za32[_{d}]_vg2x1", "vmdd", "s", MergeNone, "aarch64_sme_smlsl_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x2_S16 : Inst<"svmls[_single]_za32[_{d}]_vg2x2", "vm2d", "s", MergeNone, "aarch64_sme_smlsl_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x4_S16 : Inst<"svmls[_single]_za32[_{d}]_vg2x4", "vm4d", "s", MergeNone, "aarch64_sme_smlsl_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x1_U16 : Inst<"svmls_za32[_{d}]_vg2x1", "vmdd", "Us", MergeNone, "aarch64_sme_umlsl_single_vg2x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x2_U16 : Inst<"svmls[_single]_za32[_{d}]_vg2x2", "vm2d", "Us", MergeNone, "aarch64_sme_umlsl_single_vg2x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG2x4_U16 : Inst<"svmls[_single]_za32[_{d}]_vg2x4", "vm4d", "Us", MergeNone, "aarch64_sme_umlsl_single_vg2x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x1_S8 : Inst<"svmls_za32[_{d}]_vg4x1", "vmdd", "c", MergeNone, "aarch64_sme_smls_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x1_U8 : Inst<"svmls_za32[_{d}]_vg4x1", "vmdd", "Uc", MergeNone, "aarch64_sme_umls_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x2_S8 : Inst<"svmls[_single]_za32[_{d}]_vg4x2", "vm2d", "c", MergeNone, "aarch64_sme_smls_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x2_U8 : Inst<"svmls[_single]_za32[_{d}]_vg4x2", "vm2d", "Uc", MergeNone, "aarch64_sme_umls_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x4_S8 : Inst<"svmls[_single]_za32[_{d}]_vg4x4", "vm4d", "c", MergeNone, "aarch64_sme_smls_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x4_U8 : Inst<"svmls[_single]_za32[_{d}]_vg4x4", "vm4d", "Uc", MergeNone, "aarch64_sme_umls_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// INDEXED MLAL
def SVMLAL_LANE_VG2x1_F16 : Inst<"svmla_lane_za32[_{d}]_vg2x1", "vmddi", "bh", MergeNone, "aarch64_sme_fmlal_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x2_F16 : Inst<"svmla_lane_za32[_{d}]_vg2x2", "vm2di", "bh", MergeNone, "aarch64_sme_fmlal_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x4_F16 : Inst<"svmla_lane_za32[_{d}]_vg2x4", "vm4di", "bh", MergeNone, "aarch64_sme_fmlal_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x1_S16 : Inst<"svmla_lane_za32[_{d}]_vg2x1", "vmddi", "s", MergeNone, "aarch64_sme_smlal_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x2_S16 : Inst<"svmla_lane_za32[_{d}]_vg2x2", "vm2di", "s", MergeNone, "aarch64_sme_smlal_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x4_S16 : Inst<"svmla_lane_za32[_{d}]_vg2x4", "vm4di", "s", MergeNone, "aarch64_sme_smlal_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x1_U16 : Inst<"svmla_lane_za32[_{d}]_vg2x1", "vmddi", "Us", MergeNone, "aarch64_sme_umlal_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x2_U16 : Inst<"svmla_lane_za32[_{d}]_vg2x2", "vm2di", "Us", MergeNone, "aarch64_sme_umlal_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG2x4_U16 : Inst<"svmla_lane_za32[_{d}]_vg2x4", "vm4di", "Us", MergeNone, "aarch64_sme_umlal_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x1_S8 : Inst<"svmla_lane_za32[_{d}]_vg4x1", "vmddi", "c", MergeNone, "aarch64_sme_smla_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLAL_LANE_VG4x1_U8 : Inst<"svmla_lane_za32[_{d}]_vg4x1", "vmddi", "Uc", MergeNone, "aarch64_sme_umla_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLAL_LANE_VG4x2_S8 : Inst<"svmla_lane_za32[_{d}]_vg4x2", "vm2di", "c", MergeNone, "aarch64_sme_smla_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLAL_LANE_VG4x2_U8 : Inst<"svmla_lane_za32[_{d}]_vg4x2", "vm2di", "Uc", MergeNone, "aarch64_sme_umla_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLAL_LANE_VG4x4_S8 : Inst<"svmla_lane_za32[_{d}]_vg4x4", "vm4di", "c", MergeNone, "aarch64_sme_smla_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLAL_LANE_VG4x4_U8 : Inst<"svmla_lane_za32[_{d}]_vg4x4", "vm4di", "Uc", MergeNone, "aarch64_sme_umla_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
// INDEXED MLSL
def SVMLSL_LANE_VG2x1_F16 : Inst<"svmls_lane_za32[_{d}]_vg2x1", "vmddi", "bh", MergeNone, "aarch64_sme_fmlsl_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x2_F16 : Inst<"svmls_lane_za32[_{d}]_vg2x2", "vm2di", "bh", MergeNone, "aarch64_sme_fmlsl_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x4_F16 : Inst<"svmls_lane_za32[_{d}]_vg2x4", "vm4di", "bh", MergeNone, "aarch64_sme_fmlsl_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x1_S16 : Inst<"svmls_lane_za32[_{d}]_vg2x1", "vmddi", "s", MergeNone, "aarch64_sme_smlsl_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x2_S16 : Inst<"svmls_lane_za32[_{d}]_vg2x2", "vm2di", "s", MergeNone, "aarch64_sme_smlsl_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x4_S16 : Inst<"svmls_lane_za32[_{d}]_vg2x4", "vm4di", "s", MergeNone, "aarch64_sme_smlsl_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x1_U16 : Inst<"svmls_lane_za32[_{d}]_vg2x1", "vmddi", "Us", MergeNone, "aarch64_sme_umlsl_lane_vg2x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x2_U16 : Inst<"svmls_lane_za32[_{d}]_vg2x2", "vm2di", "Us", MergeNone, "aarch64_sme_umlsl_lane_vg2x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG2x4_U16 : Inst<"svmls_lane_za32[_{d}]_vg2x4", "vm4di", "Us", MergeNone, "aarch64_sme_umlsl_lane_vg2x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x1_S8 : Inst<"svmls_lane_za32[_{d}]_vg4x1", "vmddi", "c", MergeNone, "aarch64_sme_smls_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLSL_LANE_VG4x1_U8 : Inst<"svmls_lane_za32[_{d}]_vg4x1", "vmddi", "Uc", MergeNone, "aarch64_sme_umls_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLSL_LANE_VG4x2_S8 : Inst<"svmls_lane_za32[_{d}]_vg4x2", "vm2di", "c", MergeNone, "aarch64_sme_smls_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLSL_LANE_VG4x2_U8 : Inst<"svmls_lane_za32[_{d}]_vg4x2", "vm2di", "Uc", MergeNone, "aarch64_sme_umls_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLSL_LANE_VG4x4_S8 : Inst<"svmls_lane_za32[_{d}]_vg4x4", "vm4di", "c", MergeNone, "aarch64_sme_smls_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVMLSL_LANE_VG4x4_U8 : Inst<"svmls_lane_za32[_{d}]_vg4x4", "vm4di", "Uc", MergeNone, "aarch64_sme_umls_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
// SINGLE SUMLALL
// Single sumla maps to usmla, with zn & zm operands swapped
def SVSUMLALL_SINGLE_VG4x1 : Inst<"svsumla_za32[_{d}]_vg4x1", "vmdu", "c", MergeNone, "aarch64_sme_usmla_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVSUMLALL_SINGLE_VG4x2 : Inst<"svsumla[_single]_za32[_{d}]_vg4x2", "vm2.du", "c", MergeNone, "aarch64_sme_sumla_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVSUMLALL_SINGLE_VG4x4 : Inst<"svsumla[_single]_za32[_{d}]_vg4x4", "vm4.du", "c", MergeNone, "aarch64_sme_sumla_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// Multi-multi sumla builtins are mapped to usmla, with zn & zm operands swapped
def SVSUMLALL_MULTI_VG4x2 : Inst<"svsumla_za32[_{d}]_vg4x2", "vm2.d2.u", "c", MergeNone, "aarch64_sme_usmla_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVSUMLALL_MULTI_VG4x4 : Inst<"svsumla_za32[_{d}]_vg4x4", "vm4.d4.u", "c", MergeNone, "aarch64_sme_usmla_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
// INDEXED SUMLALL
def SVSUMLALL_LANE_VG4x1 : Inst<"svsumla_lane_za32[_{d}]_vg4x1", "vmdui", "c", MergeNone, "aarch64_sme_sumla_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVSUMLALL_LANE_VG4x2 : Inst<"svsumla_lane_za32[_{d}]_vg4x2", "vm2ui", "c", MergeNone, "aarch64_sme_sumla_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVSUMLALL_LANE_VG4x4 : Inst<"svsumla_lane_za32[_{d}]_vg4x4", "vm4ui", "c", MergeNone, "aarch64_sme_sumla_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
// SINGLE USMLALL
def SVUSMLALL_SINGLE_VG4x1 : Inst<"svusmla_za32[_{d}]_vg4x1", "vmdx", "Uc", MergeNone, "aarch64_sme_usmla_za32_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVUSMLALL_SINGLE_VG4x2 : Inst<"svusmla[_single]_za32[_{d}]_vg4x2", "vm2.dx", "Uc", MergeNone, "aarch64_sme_usmla_za32_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVUSMLALL_SINGLE_VG4x4 : Inst<"svusmla[_single]_za32[_{d}]_vg4x4", "vm4.dx", "Uc", MergeNone, "aarch64_sme_usmla_za32_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// MULTI USMLALL
def SVUSMLALL_MULTI_VG4x2 : Inst<"svusmla_za32[_{d}]_vg4x2", "vm2.d2.x", "Uc", MergeNone, "aarch64_sme_usmla_za32_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVUSMLALL_MULTI_VG4x4 : Inst<"svusmla_za32[_{d}]_vg4x4", "vm4.d4.x", "Uc", MergeNone, "aarch64_sme_usmla_za32_vg4x4", [IsStreaming, IsSharedZA], []>;
// INDEXED USMLALL
def SVUSMLALL_LANE_VG4x1 : Inst<"svusmla_lane_za32[_{d}]_vg4x1", "vmdxi", "Uc", MergeNone, "aarch64_sme_usmla_za32_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVUSMLALL_LANE_VG4x2 : Inst<"svusmla_lane_za32[_{d}]_vg4x2", "vm2xi", "Uc", MergeNone, "aarch64_sme_usmla_za32_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
def SVUSMLALL_LANE_VG4x4 : Inst<"svusmla_lane_za32[_{d}]_vg4x4", "vm4xi", "Uc", MergeNone, "aarch64_sme_usmla_za32_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_15>]>;
}
let TargetGuard = "sme2,sme-i16i64" in {
// MULTI MLAL
def SVMLAL_MULTI_VG4x2_S16 : Inst<"svmla_za64[_{d}]_vg4x2", "vm22", "s", MergeNone, "aarch64_sme_smla_za64_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x2_U16 : Inst<"svmla_za64[_{d}]_vg4x2", "vm22", "Us", MergeNone, "aarch64_sme_umla_za64_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x4_S16 : Inst<"svmla_za64[_{d}]_vg4x4", "vm44", "s", MergeNone, "aarch64_sme_smla_za64_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_MULTI_VG4x4_U16 : Inst<"svmla_za64[_{d}]_vg4x4", "vm44", "Us", MergeNone, "aarch64_sme_umla_za64_vg4x4", [IsStreaming, IsSharedZA], []>;
// MULTI MLSL
def SVMLSL_MULTI_VG4x2_S16 : Inst<"svmls_za64[_{d}]_vg4x2", "vm22", "s", MergeNone, "aarch64_sme_smls_za64_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x2_U16 : Inst<"svmls_za64[_{d}]_vg4x2", "vm22", "Us", MergeNone, "aarch64_sme_umls_za64_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x4_S16 : Inst<"svmls_za64[_{d}]_vg4x4", "vm44", "s", MergeNone, "aarch64_sme_smls_za64_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_MULTI_VG4x4_U16 : Inst<"svmls_za64[_{d}]_vg4x4", "vm44", "Us", MergeNone, "aarch64_sme_umls_za64_vg4x4", [IsStreaming, IsSharedZA], []>;
// SINGLE MLAL
def SVMLAL_SINGLE_VG4x1_S16 : Inst<"svmla_za64[_{d}]_vg4x1", "vmdd", "s", MergeNone, "aarch64_sme_smla_za64_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x1_U16 : Inst<"svmla_za64[_{d}]_vg4x1", "vmdd", "Us", MergeNone, "aarch64_sme_umla_za64_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x2_S16 : Inst<"svmla[_single]_za64[_{d}]_vg4x2", "vm2d", "s", MergeNone, "aarch64_sme_smla_za64_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x2_U16 : Inst<"svmla[_single]_za64[_{d}]_vg4x2", "vm2d", "Us", MergeNone, "aarch64_sme_umla_za64_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x4_S16 : Inst<"svmla[_single]_za64[_{d}]_vg4x4", "vm4d", "s", MergeNone, "aarch64_sme_smla_za64_single_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLAL_SINGLE_VG4x4_U16 : Inst<"svmla[_single]_za64[_{d}]_vg4x4", "vm4d", "Us", MergeNone, "aarch64_sme_umla_za64_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// SINGLE MLSL
def SVMLSL_SINGLE_VG4x1_S16 : Inst<"svmls_za64[_{d}]_vg4x1", "vmdd", "s", MergeNone, "aarch64_sme_smls_za64_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x1_U16 : Inst<"svmls_za64[_{d}]_vg4x1", "vmdd", "Us", MergeNone, "aarch64_sme_umls_za64_single_vg4x1", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x2_S16 : Inst<"svmls[_single]_za64[_{d}]_vg4x2", "vm2d", "s", MergeNone, "aarch64_sme_smls_za64_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x2_U16 : Inst<"svmls[_single]_za64[_{d}]_vg4x2", "vm2d", "Us", MergeNone, "aarch64_sme_umls_za64_single_vg4x2", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x4_S16 : Inst<"svmls[_single]_za64[_{d}]_vg4x4", "vm4d", "s", MergeNone, "aarch64_sme_smls_za64_single_vg4x4", [IsStreaming, IsSharedZA], []>;
def SVMLSL_SINGLE_VG4x4_U16 : Inst<"svmls[_single]_za64[_{d}]_vg4x4", "vm4d", "Us", MergeNone, "aarch64_sme_umls_za64_single_vg4x4", [IsStreaming, IsSharedZA], []>;
// INDEXED MLAL
def SVMLAL_LANE_VG4x1_S16 : Inst<"svmla_lane_za64[_{d}]_vg4x1", "vmddi", "s", MergeNone, "aarch64_sme_smla_za64_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x1_U16 : Inst<"svmla_lane_za64[_{d}]_vg4x1", "vmddi", "Us", MergeNone, "aarch64_sme_umla_za64_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x2_S16 : Inst<"svmla_lane_za64[_{d}]_vg4x2", "vm2di", "s", MergeNone, "aarch64_sme_smla_za64_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x2_U16 : Inst<"svmla_lane_za64[_{d}]_vg4x2", "vm2di", "Us", MergeNone, "aarch64_sme_umla_za64_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x4_S16 : Inst<"svmla_lane_za64[_{d}]_vg4x4", "vm4di", "s", MergeNone, "aarch64_sme_smla_za64_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLAL_LANE_VG4x4_U16 : Inst<"svmla_lane_za64[_{d}]_vg4x4", "vm4di", "Us", MergeNone, "aarch64_sme_umla_za64_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
// INDEXED MLSL
def SVMLSL_LANE_VG4x1_S16 : Inst<"svmls_lane_za64[_{d}]_vg4x1", "vmddi", "s", MergeNone, "aarch64_sme_smls_za64_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x1_U16 : Inst<"svmls_lane_za64[_{d}]_vg4x1", "vmddi", "Us", MergeNone, "aarch64_sme_umls_za64_lane_vg4x1", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x2_S16 : Inst<"svmls_lane_za64[_{d}]_vg4x2", "vm2di", "s", MergeNone, "aarch64_sme_smls_za64_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x2_U16 : Inst<"svmls_lane_za64[_{d}]_vg4x2", "vm2di", "Us", MergeNone, "aarch64_sme_umls_za64_lane_vg4x2", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x4_S16 : Inst<"svmls_lane_za64[_{d}]_vg4x4", "vm4di", "s", MergeNone, "aarch64_sme_smls_za64_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
def SVMLSL_LANE_VG4x4_U16 : Inst<"svmls_lane_za64[_{d}]_vg4x4", "vm4di", "Us", MergeNone, "aarch64_sme_umls_za64_lane_vg4x4", [IsStreaming, IsSharedZA], [ImmCheck<3, ImmCheck0_7>]>;
}
//

File diff suppressed because it is too large Load diff

View file

@ -2540,7 +2540,7 @@ multiclass RVVSignedWidenBinBuiltinSetVwsll
let UnMaskedPolicyScheme = HasPassthruOperand in {
// zvkb
let RequiredFeatures = ["Zvkb"] in {
let RequiredFeatures = ["Zvkb", "Experimental"] in {
defm vandn : RVVUnsignedBinBuiltinSet;
defm vbrev8 : RVVOutBuiltinSetZvbb;
defm vrev8 : RVVOutBuiltinSetZvbb;
@ -2549,7 +2549,7 @@ let UnMaskedPolicyScheme = HasPassthruOperand in {
}
// zvbb
let RequiredFeatures = ["Zvbb"] in {
let RequiredFeatures = ["Zvbb", "Experimental"] in {
defm vbrev : RVVOutBuiltinSetZvbb;
defm vclz : RVVOutBuiltinSetZvbb;
defm vctz : RVVOutBuiltinSetZvbb;
@ -2559,7 +2559,7 @@ let UnMaskedPolicyScheme = HasPassthruOperand in {
}
// zvbc
let RequiredFeatures = ["Zvbc"] in {
let RequiredFeatures = ["Zvbc", "Experimental"] in {
defm vclmul : RVVInt64BinBuiltinSet;
defm vclmulh : RVVInt64BinBuiltinSet;
}
@ -2567,13 +2567,13 @@ let UnMaskedPolicyScheme = HasPassthruOperand in {
let UnMaskedPolicyScheme = HasPolicyOperand, HasMasked = false in {
// zvkg
let RequiredFeatures = ["Zvkg"] in {
let RequiredFeatures = ["Zvkg", "Experimental"] in {
defm vghsh : RVVOutOp2BuiltinSetVVZvk;
defm vgmul : RVVOutBuiltinSetZvk<HasVV=1, HasVS=0>;
}
// zvkned
let RequiredFeatures = ["Zvkned"] in {
let RequiredFeatures = ["Zvkned", "Experimental"] in {
defm vaesdf : RVVOutBuiltinSetZvk;
defm vaesdm : RVVOutBuiltinSetZvk;
defm vaesef : RVVOutBuiltinSetZvk;
@ -2585,28 +2585,28 @@ let UnMaskedPolicyScheme = HasPolicyOperand, HasMasked = false in {
}
// zvknha
let RequiredFeatures = ["Zvknha"] in {
let RequiredFeatures = ["Zvknha", "Experimental"] in {
defm vsha2ch : RVVOutOp2BuiltinSetVVZvk<"i">;
defm vsha2cl : RVVOutOp2BuiltinSetVVZvk<"i">;
defm vsha2ms : RVVOutOp2BuiltinSetVVZvk<"i">;
}
// zvknhb
let RequiredFeatures = ["Zvknhb"] in {
let RequiredFeatures = ["Zvknhb", "Experimental"] in {
defm vsha2ch : RVVOutOp2BuiltinSetVVZvk<"il">;
defm vsha2cl : RVVOutOp2BuiltinSetVVZvk<"il">;
defm vsha2ms : RVVOutOp2BuiltinSetVVZvk<"il">;
}
// zvksed
let RequiredFeatures = ["Zvksed"] in {
let RequiredFeatures = ["Zvksed", "Experimental"] in {
let UnMaskedPolicyScheme = HasPassthruOperand in
defm vsm4k : RVVOutOp1BuiltinSet<"vsm4k", "i", [["vi", "Uv", "UvUvKz"]]>;
defm vsm4r : RVVOutBuiltinSetZvk;
}
// zvksh
let RequiredFeatures = ["Zvksh"] in {
let RequiredFeatures = ["Zvksh", "Experimental"] in {
defm vsm3c : RVVOutOp2BuiltinSetVIZvk;
let UnMaskedPolicyScheme = HasPassthruOperand in
defm vsm3me : RVVOutOp1BuiltinSet<"vsm3me", "i", [["vv", "Uv", "UvUvUv"]]>;

View file

@ -5308,7 +5308,8 @@ def rewrite_objc : Flag<["-"], "rewrite-objc">, Flags<[NoXarchOption]>,
def rewrite_legacy_objc : Flag<["-"], "rewrite-legacy-objc">,
Flags<[NoXarchOption]>,
HelpText<"Rewrite Legacy Objective-C source to C++">;
def rdynamic : Flag<["-"], "rdynamic">, Group<Link_Group>;
def rdynamic : Flag<["-"], "rdynamic">, Group<Link_Group>,
Visibility<[ClangOption, FlangOption]>;
def resource_dir : Separate<["-"], "resource-dir">,
Flags<[NoXarchOption, HelpHidden]>,
Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>,
@ -6999,6 +7000,8 @@ def msign_return_address_key_EQ : Joined<["-"], "msign-return-address-key=">,
Values<"a_key,b_key">;
def mbranch_target_enforce : Flag<["-"], "mbranch-target-enforce">,
MarshallingInfoFlag<LangOpts<"BranchTargetEnforcement">>;
def mbranch_protection_pauth_lr : Flag<["-"], "mbranch-protection-pauth-lr">,
MarshallingInfoFlag<LangOpts<"BranchProtectionPAuthLR">>;
def fno_dllexport_inlines : Flag<["-"], "fno-dllexport-inlines">,
MarshallingInfoNegativeFlag<LangOpts<"DllExportInlines">>;
def cfguard_no_checks : Flag<["-"], "cfguard-no-checks">,

View file

@ -23,8 +23,27 @@ namespace clang {
class CodeCompletionResult;
class CompilerInstance;
void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
std::vector<std::string> &CCResults);
struct ReplCodeCompleter {
ReplCodeCompleter() = default;
std::string Prefix;
/// \param InterpCI [in] The compiler instance that is used to trigger code
/// completion
/// \param Content [in] The string where code completion is triggered.
/// \param Line [in] The line number of the code completion point.
/// \param Col [in] The column number of the code completion point.
/// \param ParentCI [in] The running interpreter compiler instance that
/// provides ASTContexts.
/// \param CCResults [out] The completion results.
void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
unsigned Line, unsigned Col,
const CompilerInstance *ParentCI,
std::vector<std::string> &CCResults);
};
} // namespace clang
#endif

View file

@ -101,6 +101,7 @@ public:
const ASTContext &getASTContext() const;
ASTContext &getASTContext();
const CompilerInstance *getCompilerInstance() const;
CompilerInstance *getCompilerInstance();
llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine();
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);

View file

@ -4799,8 +4799,6 @@ public:
bool CheckAlwaysInlineAttr(const Stmt *OrigSt, const Stmt *CurSt,
const AttributeCommonInfo &A);
bool CheckCountedByAttr(Scope *Scope, const FieldDecl *FD);
/// Adjust the calling convention of a method to be the ABI default if it
/// wasn't specified explicitly. This handles method types formed from
/// function type typedefs and typename template arguments.
@ -5644,7 +5642,6 @@ public:
CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr,
ArrayRef<Expr *> Args = std::nullopt,
DeclContext *LookupCtx = nullptr,
TypoExpr **Out = nullptr);
DeclResult LookupIvarInObjCMethod(LookupResult &Lookup, Scope *S,
@ -9357,8 +9354,7 @@ public:
QualType DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Init,
ParenListExpr *PL = nullptr);
const InitializationKind &Kind, MultiExprArg Init);
QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name,
QualType Type, TypeSourceInfo *TSI,
@ -13851,6 +13847,7 @@ private:
bool CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool ParseSVEImmChecks(CallExpr *TheCall,
SmallVector<std::tuple<int, int, int>, 3> &ImmChecks);
bool CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckARMCoprocessorImmediate(const TargetInfo &TI, const Expr *CoprocArg,

View file

@ -282,7 +282,7 @@ class CorrectionCandidateCallback {
public:
static const unsigned InvalidDistance = TypoCorrection::InvalidDistance;
explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr,
explicit CorrectionCandidateCallback(IdentifierInfo *Typo = nullptr,
NestedNameSpecifier *TypoNNS = nullptr)
: Typo(Typo), TypoNNS(TypoNNS) {}
@ -319,7 +319,7 @@ public:
/// this method.
virtual std::unique_ptr<CorrectionCandidateCallback> clone() = 0;
void setTypoName(const IdentifierInfo *II) { Typo = II; }
void setTypoName(IdentifierInfo *II) { Typo = II; }
void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; }
// Flags for context-dependent keywords. WantFunctionLikeCasts is only
@ -345,13 +345,13 @@ protected:
candidate.getCorrectionSpecifier() == TypoNNS;
}
const IdentifierInfo *Typo;
IdentifierInfo *Typo;
NestedNameSpecifier *TypoNNS;
};
class DefaultFilterCCC final : public CorrectionCandidateCallback {
public:
explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr,
explicit DefaultFilterCCC(IdentifierInfo *Typo = nullptr,
NestedNameSpecifier *TypoNNS = nullptr)
: CorrectionCandidateCallback(Typo, TypoNNS) {}
@ -365,10 +365,6 @@ public:
template <class C>
class DeclFilterCCC final : public CorrectionCandidateCallback {
public:
explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr,
NestedNameSpecifier *TypoNNS = nullptr)
: CorrectionCandidateCallback(Typo, TypoNNS) {}
bool ValidateCandidate(const TypoCorrection &candidate) override {
return candidate.getCorrectionDeclAs<C>();
}

View file

@ -2422,6 +2422,8 @@ public:
CurrentBitsIndex = 0;
}
void advance(uint32_t BitsWidth) { CurrentBitsIndex += BitsWidth; }
bool getNextBit() {
assert(isValid());
return Value & (1 << CurrentBitsIndex++);

View file

@ -564,11 +564,25 @@ private:
unsigned DeclEnumAbbrev = 0;
unsigned DeclObjCIvarAbbrev = 0;
unsigned DeclCXXMethodAbbrev = 0;
unsigned DeclDependentNonTemplateCXXMethodAbbrev = 0;
unsigned DeclTemplateCXXMethodAbbrev = 0;
unsigned DeclMemberSpecializedCXXMethodAbbrev = 0;
unsigned DeclTemplateSpecializedCXXMethodAbbrev = 0;
unsigned DeclDependentSpecializationCXXMethodAbbrev = 0;
unsigned DeclTemplateTypeParmAbbrev = 0;
unsigned DeclUsingShadowAbbrev = 0;
unsigned DeclRefExprAbbrev = 0;
unsigned CharacterLiteralAbbrev = 0;
unsigned IntegerLiteralAbbrev = 0;
unsigned ExprImplicitCastAbbrev = 0;
unsigned BinaryOperatorAbbrev = 0;
unsigned CompoundAssignOperatorAbbrev = 0;
unsigned CallExprAbbrev = 0;
unsigned CXXOperatorCallExprAbbrev = 0;
unsigned CXXMemberCallExprAbbrev = 0;
unsigned CompoundStmtAbbrev = 0;
void WriteDeclAbbrevs();
void WriteDecl(ASTContext &Context, Decl *D);
@ -735,12 +749,41 @@ public:
unsigned getDeclFieldAbbrev() const { return DeclFieldAbbrev; }
unsigned getDeclEnumAbbrev() const { return DeclEnumAbbrev; }
unsigned getDeclObjCIvarAbbrev() const { return DeclObjCIvarAbbrev; }
unsigned getDeclCXXMethodAbbrev() const { return DeclCXXMethodAbbrev; }
unsigned getDeclCXXMethodAbbrev(FunctionDecl::TemplatedKind Kind) const {
switch (Kind) {
case FunctionDecl::TK_NonTemplate:
return DeclCXXMethodAbbrev;
case FunctionDecl::TK_FunctionTemplate:
return DeclTemplateCXXMethodAbbrev;
case FunctionDecl::TK_MemberSpecialization:
return DeclMemberSpecializedCXXMethodAbbrev;
case FunctionDecl::TK_FunctionTemplateSpecialization:
return DeclTemplateSpecializedCXXMethodAbbrev;
case FunctionDecl::TK_DependentNonTemplate:
return DeclDependentNonTemplateCXXMethodAbbrev;
case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
return DeclDependentSpecializationCXXMethodAbbrev;
}
llvm_unreachable("Unknwon Template Kind!");
}
unsigned getDeclTemplateTypeParmAbbrev() const {
return DeclTemplateTypeParmAbbrev;
}
unsigned getDeclUsingShadowAbbrev() const { return DeclUsingShadowAbbrev; }
unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; }
unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; }
unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; }
unsigned getExprImplicitCastAbbrev() const { return ExprImplicitCastAbbrev; }
unsigned getBinaryOperatorAbbrev() const { return BinaryOperatorAbbrev; }
unsigned getCompoundAssignOperatorAbbrev() const {
return CompoundAssignOperatorAbbrev;
}
unsigned getCallExprAbbrev() const { return CallExprAbbrev; }
unsigned getCXXOperatorCallExprAbbrev() { return CXXOperatorCallExprAbbrev; }
unsigned getCXXMemberCallExprAbbrev() { return CXXMemberCallExprAbbrev; }
unsigned getCompoundStmtAbbrev() const { return CompoundStmtAbbrev; }
bool hasChain() const { return Chain; }
ASTReader *getChain() const { return Chain; }
@ -841,46 +884,33 @@ public:
BitsPacker(BitsPacker &&) = delete;
BitsPacker operator=(const BitsPacker &) = delete;
BitsPacker operator=(BitsPacker &&) = delete;
~BitsPacker() {
assert(!hasUnconsumedValues() && "There are unprocessed bits!");
~BitsPacker() = default;
bool canWriteNextNBits(uint32_t BitsWidth) const {
return CurrentBitIndex + BitsWidth < BitIndexUpbound;
}
void reset(uint32_t Value) {
UnderlyingValue = Value;
CurrentBitIndex = 0;
}
void addBit(bool Value) { addBits(Value, 1); }
void addBits(uint32_t Value, uint32_t BitsWidth) {
assert(BitsWidth < BitIndexUpbound);
assert((Value < (1u << BitsWidth)) && "Passing narrower bit width!");
assert(canWriteNextNBits(BitsWidth) &&
"Inserting too much bits into a value!");
if (CurrentBitIndex + BitsWidth >= BitIndexUpbound) {
Values.push_back(0);
CurrentBitIndex = 0;
}
assert(CurrentBitIndex < BitIndexUpbound);
Values.back() |= Value << CurrentBitIndex;
UnderlyingValue |= Value << CurrentBitIndex;
CurrentBitIndex += BitsWidth;
}
bool hasUnconsumedValues() const {
return ConsumingValueIndex < Values.size();
}
uint32_t getNextValue() {
assert(hasUnconsumedValues());
return Values[ConsumingValueIndex++];
}
// We can convert the packer to an uint32_t if there is only one values.
operator uint32_t() {
assert(Values.size() == 1);
return getNextValue();
}
operator uint32_t() { return UnderlyingValue; }
private:
SmallVector<uint64_t, 4> Values;
uint16_t ConsumingValueIndex = 0;
// Initialize CurrentBitIndex with an invalid value
// to make it easier to update Values. See the implementation
// of `addBits` to see the details.
uint16_t CurrentBitIndex = BitIndexUpbound;
uint32_t UnderlyingValue = 0;
uint32_t CurrentBitIndex = 0;
};
} // namespace clang

View file

@ -485,7 +485,7 @@ public:
// RVVRequire should be sync'ed with target features, but only
// required features used in riscv_vector.td.
enum RVVRequire : uint16_t {
enum RVVRequire : uint32_t {
RVV_REQ_None = 0,
RVV_REQ_RV64 = 1 << 0,
RVV_REQ_ZvfhminOrZvfh = 1 << 1,
@ -503,8 +503,9 @@ enum RVVRequire : uint16_t {
RVV_REQ_Zvknhb = 1 << 13,
RVV_REQ_Zvksed = 1 << 14,
RVV_REQ_Zvksh = 1 << 15,
RVV_REQ_Experimental = 1 << 16,
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Zvksh)
LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Experimental)
};
// Raw RVV intrinsic info, used to expand later.
@ -536,7 +537,7 @@ struct RVVIntrinsicRecord {
uint8_t OverloadedSuffixSize;
// Required target features for this intrinsic.
uint16_t RequiredExtensions;
uint32_t RequiredExtensions;
// Supported type, mask of BasicType.
uint8_t TypeRangeMask;

View file

@ -125,7 +125,7 @@ APINotesManager::loadAPINotes(StringRef Buffer) {
bool APINotesManager::loadAPINotes(const DirectoryEntry *HeaderDir,
FileEntryRef APINotesFile) {
assert(Readers.find(HeaderDir) == Readers.end());
assert(!Readers.contains(HeaderDir));
if (auto Reader = loadAPINotes(APINotesFile)) {
Readers[HeaderDir] = Reader.release();
return false;

View file

@ -2771,9 +2771,11 @@ ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
for (auto *FoundDecl : FoundDecls) {
if (!FoundDecl->isInIdentifierNamespace(IDNS))
continue;
if (auto *FoundAlias = dyn_cast<TypeAliasTemplateDecl>(FoundDecl))
return Importer.MapImported(D, FoundAlias);
ConflictingDecls.push_back(FoundDecl);
if (auto *FoundAlias = dyn_cast<TypeAliasTemplateDecl>(FoundDecl)) {
if (IsStructuralMatch(D, FoundAlias))
return Importer.MapImported(D, FoundAlias);
ConflictingDecls.push_back(FoundDecl);
}
}
if (!ConflictingDecls.empty()) {
@ -3418,10 +3420,16 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Stmt *S) {
while (!ToProcess.empty()) {
const Stmt *CurrentS = ToProcess.pop_back_val();
ToProcess.append(CurrentS->child_begin(), CurrentS->child_end());
if (const auto *DeclRef = dyn_cast<DeclRefExpr>(CurrentS))
if (const auto *DeclRef = dyn_cast<DeclRefExpr>(CurrentS)) {
if (const Decl *D = DeclRef->getDecl())
if (isAncestorDeclContextOf(DC, D))
return true;
} else if (const auto *E =
dyn_cast_or_null<SubstNonTypeTemplateParmExpr>(CurrentS)) {
if (const Decl *D = E->getAssociatedDecl())
if (isAncestorDeclContextOf(DC, D))
return true;
}
}
return false;
}
@ -7820,6 +7828,18 @@ ExpectedStmt ASTNodeImporter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
*ToLParenLocOrErr, OCE->getBridgeKind(), E->getCastKind(),
*ToBridgeKeywordLocOrErr, ToTypeInfoAsWritten, ToSubExpr);
}
case Stmt::BuiltinBitCastExprClass: {
auto *BBC = cast<BuiltinBitCastExpr>(E);
ExpectedSLoc ToKWLocOrErr = import(BBC->getBeginLoc());
if (!ToKWLocOrErr)
return ToKWLocOrErr.takeError();
ExpectedSLoc ToRParenLocOrErr = import(BBC->getEndLoc());
if (!ToRParenLocOrErr)
return ToRParenLocOrErr.takeError();
return new (Importer.getToContext()) BuiltinBitCastExpr(
ToType, E->getValueKind(), E->getCastKind(), ToSubExpr,
ToTypeInfoAsWritten, *ToKWLocOrErr, *ToRParenLocOrErr);
}
default:
llvm_unreachable("Cast expression of unsupported type!");
return make_error<ASTImportError>(ASTImportError::UnsupportedConstruct);
@ -9003,10 +9023,6 @@ class AttrImporter {
public:
AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {}
// Useful for accessing the imported attribute.
template <typename T> T *castAttrAs() { return cast<T>(ToAttr); }
template <typename T> const T *castAttrAs() const { return cast<T>(ToAttr); }
// Create an "importer" for an attribute parameter.
// Result of the 'value()' of that object is to be passed to the function
// 'importAttr', in the order that is expected by the attribute class.
@ -9101,6 +9117,12 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
break;
}
case attr::AlignValue: {
auto *From = cast<AlignValueAttr>(FromAttr);
AI.importAttr(From, AI.importArg(From->getAlignment()).value());
break;
}
case attr::Format: {
const auto *From = cast<FormatAttr>(FromAttr);
AI.importAttr(From, Import(From->getType()), From->getFormatIdx(),
@ -9214,15 +9236,6 @@ Expected<Attr *> ASTImporter::Import(const Attr *FromAttr) {
From->args_size());
break;
}
case attr::CountedBy: {
AI.cloneAttr(FromAttr);
const auto *CBA = cast<CountedByAttr>(FromAttr);
Expected<SourceRange> SR = Import(CBA->getCountedByFieldLoc()).get();
if (!SR)
return SR.takeError();
AI.castAttrAs<CountedByAttr>()->setCountedByFieldLoc(SR.get());
break;
}
default: {
// The default branch works for attributes that have no arguments to import.
@ -9391,7 +9404,6 @@ Expected<Decl *> ASTImporter::Import(Decl *FromD) {
setImportDeclError(FromD, *Error);
return make_error<ASTImportError>(*Error);
}
// Make sure that ImportImpl registered the imported decl.
assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?");
if (auto Error = ImportAttrs(ToD, FromD))

View file

@ -1977,6 +1977,18 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
D2->getTemplatedDecl()->getType());
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
TypeAliasTemplateDecl *D1,
TypeAliasTemplateDecl *D2) {
// Check template parameters.
if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2))
return false;
// Check the templated declaration.
return IsStructurallyEquivalent(Context, D1->getTemplatedDecl(),
D2->getTemplatedDecl());
}
static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
ConceptDecl *D1,
ConceptDecl *D2) {

View file

@ -1088,11 +1088,11 @@ bool NamedDecl::isPlaceholderVar(const LangOptions &LangOpts) const {
return false;
if (isa<FieldDecl>(this))
return true;
if (auto *IFD = dyn_cast<IndirectFieldDecl>(this)) {
if (const auto *IFD = dyn_cast<IndirectFieldDecl>(this)) {
if (!getDeclContext()->isFunctionOrMethod() &&
!getDeclContext()->isRecord())
return false;
VarDecl *VD = IFD->getVarDecl();
const VarDecl *VD = IFD->getVarDecl();
return !VD || VD->getStorageDuration() == SD_Automatic;
}
// and it declares a variable with automatic storage duration
@ -1105,7 +1105,7 @@ bool NamedDecl::isPlaceholderVar(const LangOptions &LangOpts) const {
}
if (const auto *BD = dyn_cast<BindingDecl>(this);
BD && getDeclContext()->isFunctionOrMethod()) {
VarDecl *VD = BD->getHoldingVar();
const VarDecl *VD = BD->getHoldingVar();
return !VD || VD->getStorageDuration() == StorageDuration::SD_Automatic;
}
return false;
@ -1843,7 +1843,8 @@ static bool isRedeclarable(Decl::Kind K) {
llvm_unreachable("unknown decl kind");
}
bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
bool NamedDecl::declarationReplaces(const NamedDecl *OldD,
bool IsKnownNewer) const {
assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch");
// Never replace one imported declaration with another; we need both results
@ -1873,13 +1874,13 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
// Using declarations can be replaced if they import the same name from the
// same context.
if (auto *UD = dyn_cast<UsingDecl>(this)) {
if (const auto *UD = dyn_cast<UsingDecl>(this)) {
ASTContext &Context = getASTContext();
return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) ==
Context.getCanonicalNestedNameSpecifier(
cast<UsingDecl>(OldD)->getQualifier());
}
if (auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) {
if (const auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) {
ASTContext &Context = getASTContext();
return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) ==
Context.getCanonicalNestedNameSpecifier(
@ -1896,7 +1897,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const {
// Check whether this is actually newer than OldD. We want to keep the
// newer declaration. This loop will usually only iterate once, because
// OldD is usually the previous declaration.
for (auto *D : redecls()) {
for (const auto *D : redecls()) {
if (D == OldD)
break;
@ -2199,8 +2200,7 @@ static LanguageLinkage getDeclLanguageLinkage(const T &D) {
// Language linkage is a C++ concept, but saying that everything else in C has
// C language linkage fits the implementation nicely.
ASTContext &Context = D.getASTContext();
if (!Context.getLangOpts().CPlusPlus)
if (!D.getASTContext().getLangOpts().CPlusPlus)
return CLanguageLinkage;
// C++ [dcl.link]p4: A C language linkage is ignored in determining the
@ -2943,7 +2943,7 @@ bool ParmVarDecl::isDestroyedInCallee() const {
// FIXME: isParamDestroyedInCallee() should probably imply
// isDestructedType()
auto *RT = getType()->getAs<RecordType>();
const auto *RT = getType()->getAs<RecordType>();
if (RT && RT->getDecl()->isParamDestroyedInCallee() &&
getType().isDestructedType())
return true;
@ -3105,7 +3105,7 @@ FunctionDecl::getDefaultedFunctionInfo() const {
}
bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
for (auto *I : redecls()) {
for (const auto *I : redecls()) {
if (I->doesThisDeclarationHaveABody()) {
Definition = I;
return true;
@ -3116,7 +3116,7 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const {
}
bool FunctionDecl::hasTrivialBody() const {
Stmt *S = getBody();
const Stmt *S = getBody();
if (!S) {
// Since we don't have a body for this function, we don't know if it's
// trivial or not.
@ -3212,7 +3212,7 @@ void FunctionDecl::setPure(bool P) {
template<std::size_t Len>
static bool isNamed(const NamedDecl *ND, const char (&Str)[Len]) {
IdentifierInfo *II = ND->getIdentifier();
const IdentifierInfo *II = ND->getIdentifier();
return II && II->isStr(Str);
}
@ -3305,9 +3305,9 @@ bool FunctionDecl::isReservedGlobalPlacementOperator() const {
if (proto->getNumParams() != 2 || proto->isVariadic())
return false;
ASTContext &Context =
cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext())
->getASTContext();
const ASTContext &Context =
cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext())
->getASTContext();
// The result type and first argument type are constant across all
// these operators. The second argument must be exactly void*.
@ -3342,7 +3342,7 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(
unsigned Params = 1;
QualType Ty = FPT->getParamType(Params);
ASTContext &Ctx = getASTContext();
const ASTContext &Ctx = getASTContext();
auto Consume = [&] {
++Params;
@ -3388,7 +3388,8 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(
QualType T = Ty;
while (const auto *TD = T->getAs<TypedefType>())
T = TD->getDecl()->getUnderlyingType();
IdentifierInfo *II = T->castAs<EnumType>()->getDecl()->getIdentifier();
const IdentifierInfo *II =
T->castAs<EnumType>()->getDecl()->getIdentifier();
if (II && II->isStr("__hot_cold_t"))
Consume();
}
@ -3586,7 +3587,7 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const {
(!hasAttr<ArmBuiltinAliasAttr>() && !hasAttr<BuiltinAliasAttr>()))
return 0;
ASTContext &Context = getASTContext();
const ASTContext &Context = getASTContext();
if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return BuiltinID;
@ -3745,7 +3746,7 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
assert(!doesThisDeclarationHaveABody() &&
"Must have a declaration without a body.");
ASTContext &Context = getASTContext();
const ASTContext &Context = getASTContext();
if (Context.getLangOpts().MSVCCompat) {
const FunctionDecl *Definition;

View file

@ -29,6 +29,7 @@
#include "clang/AST/Type.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/PartialDiagnostic.h"
@ -410,79 +411,6 @@ bool Decl::isFileContextDecl() const {
return DC && DC->isFileContext();
}
bool Decl::isFlexibleArrayMemberLike(
ASTContext &Ctx, const Decl *D, QualType Ty,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution) {
// For compatibility with existing code, we treat arrays of length 0 or
// 1 as flexible array members.
const auto *CAT = Ctx.getAsConstantArrayType(Ty);
if (CAT) {
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
llvm::APInt Size = CAT->getSize();
if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
return false;
// GCC extension, only allowed to represent a FAM.
if (Size.isZero())
return true;
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
return false;
if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
return false;
} else if (!Ctx.getAsIncompleteArrayType(Ty)) {
return false;
}
if (const auto *OID = dyn_cast_if_present<ObjCIvarDecl>(D))
return OID->getNextIvar() == nullptr;
const auto *FD = dyn_cast_if_present<FieldDecl>(D);
if (!FD)
return false;
if (CAT) {
// GCC treats an array memeber of a union as an FAM if the size is one or
// zero.
llvm::APInt Size = CAT->getSize();
if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
return true;
}
// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
if (IgnoreTemplateOrMacroSubstitution) {
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}
if (auto CTL = TL.getAs<ConstantArrayTypeLoc>()) {
if (const Expr *SizeExpr =
dyn_cast_if_present<IntegerLiteral>(CTL.getSizeExpr());
!SizeExpr || SizeExpr->getExprLoc().isMacroID())
return false;
}
break;
}
}
// Test that the field is the last in the structure.
RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
}
TranslationUnitDecl *Decl::getTranslationUnitDecl() {
if (auto *TUD = dyn_cast<TranslationUnitDecl>(this))
return TUD;

View file

@ -205,22 +205,85 @@ bool Expr::isKnownToHaveBooleanValue(bool Semantic) const {
}
bool Expr::isFlexibleArrayMemberLike(
ASTContext &Ctx,
ASTContext &Context,
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel,
bool IgnoreTemplateOrMacroSubstitution) const {
// For compatibility with existing code, we treat arrays of length 0 or
// 1 as flexible array members.
const auto *CAT = Context.getAsConstantArrayType(getType());
if (CAT) {
llvm::APInt Size = CAT->getSize();
using FAMKind = LangOptions::StrictFlexArraysLevelKind;
if (StrictFlexArraysLevel == FAMKind::IncompleteOnly)
return false;
// GCC extension, only allowed to represent a FAM.
if (Size == 0)
return true;
if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete && Size.uge(1))
return false;
if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete && Size.uge(2))
return false;
} else if (!Context.getAsIncompleteArrayType(getType()))
return false;
const Expr *E = IgnoreParens();
const Decl *D = nullptr;
if (const auto *ME = dyn_cast<MemberExpr>(E))
D = ME->getMemberDecl();
else if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
D = DRE->getDecl();
const NamedDecl *ND = nullptr;
if (const auto *DRE = dyn_cast<DeclRefExpr>(E))
ND = DRE->getDecl();
else if (const auto *ME = dyn_cast<MemberExpr>(E))
ND = ME->getMemberDecl();
else if (const auto *IRE = dyn_cast<ObjCIvarRefExpr>(E))
D = IRE->getDecl();
return IRE->getDecl()->getNextIvar() == nullptr;
return Decl::isFlexibleArrayMemberLike(Ctx, D, E->getType(),
StrictFlexArraysLevel,
IgnoreTemplateOrMacroSubstitution);
if (!ND)
return false;
// A flexible array member must be the last member in the class.
// FIXME: If the base type of the member expr is not FD->getParent(),
// this should not be treated as a flexible array member access.
if (const auto *FD = dyn_cast<FieldDecl>(ND)) {
// GCC treats an array memeber of a union as an FAM if the size is one or
// zero.
if (CAT) {
llvm::APInt Size = CAT->getSize();
if (FD->getParent()->isUnion() && (Size.isZero() || Size.isOne()))
return true;
}
// Don't consider sizes resulting from macro expansions or template argument
// substitution to form C89 tail-padded arrays.
if (IgnoreTemplateOrMacroSubstitution) {
TypeSourceInfo *TInfo = FD->getTypeSourceInfo();
while (TInfo) {
TypeLoc TL = TInfo->getTypeLoc();
// Look through typedefs.
if (TypedefTypeLoc TTL = TL.getAsAdjusted<TypedefTypeLoc>()) {
const TypedefNameDecl *TDL = TTL.getTypedefNameDecl();
TInfo = TDL->getTypeSourceInfo();
continue;
}
if (ConstantArrayTypeLoc CTL = TL.getAs<ConstantArrayTypeLoc>()) {
const Expr *SizeExpr = dyn_cast<IntegerLiteral>(CTL.getSizeExpr());
if (!SizeExpr || SizeExpr->getExprLoc().isMacroID())
return false;
}
break;
}
}
RecordDecl::field_iterator FI(
DeclContext::decl_iterator(const_cast<FieldDecl *>(FD)));
return ++FI == FD->getParent()->field_end();
}
return false;
}
const ValueDecl *

View file

@ -726,27 +726,70 @@ void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
// so allow these as an exception.
assert(E.isGLValue() ||
E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
setStorageLocationInternal(E, Loc);
const Expr &CanonE = ignoreCFGOmittedNodes(E);
assert(!ExprToLoc.contains(&CanonE));
ExprToLoc[&CanonE] = &Loc;
}
StorageLocation *Environment::getStorageLocation(const Expr &E) const {
// See comment in `setStorageLocation()`.
assert(E.isGLValue() ||
E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
return getStorageLocationInternal(E);
auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
return It == ExprToLoc.end() ? nullptr : &*It->second;
}
// Returns whether a prvalue of record type is the one that originally
// constructs the object (i.e. it doesn't propagate it from one of its
// children).
static bool isOriginalRecordConstructor(const Expr &RecordPRValue) {
if (auto *Init = dyn_cast<InitListExpr>(&RecordPRValue))
return !Init->isSemanticForm() || !Init->isTransparent();
return isa<CXXConstructExpr>(RecordPRValue) || isa<CallExpr>(RecordPRValue) ||
isa<LambdaExpr>(RecordPRValue) ||
// The framework currently does not propagate the objects created in
// the two branches of a `ConditionalOperator` because there is no way
// to reconcile their storage locations, which are different. We
// therefore claim that the `ConditionalOperator` is the expression
// that originally constructs the object.
// Ultimately, this will be fixed by propagating locations down from
// the result object, rather than up from the original constructor as
// we do now (see also the FIXME in the documentation for
// `getResultObjectLocation()`).
isa<ConditionalOperator>(RecordPRValue);
}
RecordStorageLocation &
Environment::getResultObjectLocation(const Expr &RecordPRValue) {
Environment::getResultObjectLocation(const Expr &RecordPRValue) const {
assert(RecordPRValue.getType()->isRecordType());
assert(RecordPRValue.isPRValue());
if (StorageLocation *ExistingLoc = getStorageLocationInternal(RecordPRValue))
return *cast<RecordStorageLocation>(ExistingLoc);
auto &Loc = cast<RecordStorageLocation>(
DACtx->getStableStorageLocation(RecordPRValue));
setStorageLocationInternal(RecordPRValue, Loc);
return Loc;
// Returns a storage location that we can use if assertions fail.
auto FallbackForAssertFailure =
[this, &RecordPRValue]() -> RecordStorageLocation & {
return cast<RecordStorageLocation>(
DACtx->getStableStorageLocation(RecordPRValue));
};
if (isOriginalRecordConstructor(RecordPRValue)) {
auto *Val = cast_or_null<RecordValue>(getValue(RecordPRValue));
// The builtin transfer function should have created a `RecordValue` for all
// original record constructors.
assert(Val);
if (!Val)
return FallbackForAssertFailure();
return Val->getLoc();
}
// Expression nodes that propagate a record prvalue should have exactly one
// child.
llvm::SmallVector<const Stmt *> children(RecordPRValue.child_begin(),
RecordPRValue.child_end());
assert(children.size() == 1);
if (children.empty())
return FallbackForAssertFailure();
return getResultObjectLocation(*cast<Expr>(children[0]));
}
PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
@ -760,6 +803,11 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) {
}
void Environment::setValue(const Expr &E, Value &Val) {
if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) {
assert(isOriginalRecordConstructor(E) ||
&RecordVal->getLoc() == &getResultObjectLocation(E));
}
assert(E.isPRValue());
ExprToVal[&E] = &Val;
}
@ -799,18 +847,6 @@ Value *Environment::createValue(QualType Type) {
return Val;
}
void Environment::setStorageLocationInternal(const Expr &E,
StorageLocation &Loc) {
const Expr &CanonE = ignoreCFGOmittedNodes(E);
assert(!ExprToLoc.contains(&CanonE));
ExprToLoc[&CanonE] = &Loc;
}
StorageLocation *Environment::getStorageLocationInternal(const Expr &E) const {
auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
return It == ExprToLoc.end() ? nullptr : &*It->second;
}
Value *Environment::createValueUnlessSelfReferential(
QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
int &CreatedValuesCount) {
@ -998,7 +1034,7 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
if (ImplicitObject == nullptr)
return nullptr;
if (ImplicitObject->getType()->isPointerType()) {
if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*ImplicitObject)))
if (auto *Val = Env.get<PointerValue>(*ImplicitObject))
return &cast<RecordStorageLocation>(Val->getPointeeLoc());
return nullptr;
}
@ -1012,11 +1048,11 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
if (Base == nullptr)
return nullptr;
if (ME.isArrow()) {
if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Base)))
if (auto *Val = Env.get<PointerValue>(*Base))
return &cast<RecordStorageLocation>(Val->getPointeeLoc());
return nullptr;
}
return cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Base));
return Env.get<RecordStorageLocation>(*Base);
}
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
@ -1041,9 +1077,10 @@ RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) {
assert(Expr.getType()->isRecordType());
if (Expr.isPRValue()) {
if (auto *ExistingVal = cast_or_null<RecordValue>(Env.getValue(Expr))) {
if (auto *ExistingVal = Env.get<RecordValue>(Expr)) {
auto &NewVal = Env.create<RecordValue>(ExistingVal->getLoc());
Env.setValue(Expr, NewVal);
Env.setValue(NewVal.getLoc(), NewVal);
return NewVal;
}
@ -1052,8 +1089,7 @@ RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) {
return NewVal;
}
if (auto *Loc =
cast_or_null<RecordStorageLocation>(Env.getStorageLocation(Expr))) {
if (auto *Loc = Env.get<RecordStorageLocation>(Expr)) {
auto &NewVal = Env.create<RecordValue>(*Loc);
Env.setValue(*Loc, NewVal);
return NewVal;

View file

@ -226,7 +226,7 @@ auto isComparisonOperatorCall(L lhs_arg_matcher, R rhs_arg_matcher) {
/// Ensures that `Expr` is mapped to a `BoolValue` and returns its formula.
const Formula &forceBoolValue(Environment &Env, const Expr &Expr) {
auto *Value = cast_or_null<BoolValue>(Env.getValue(Expr));
auto *Value = Env.get<BoolValue>(Expr);
if (Value != nullptr)
return Value->formula();
@ -267,7 +267,7 @@ BoolValue *getHasValue(Environment &Env, RecordStorageLocation *OptionalLoc) {
if (OptionalLoc == nullptr)
return nullptr;
StorageLocation &HasValueLoc = locForHasValue(*OptionalLoc);
auto *HasValueVal = cast_or_null<BoolValue>(Env.getValue(HasValueLoc));
auto *HasValueVal = Env.get<BoolValue>(HasValueLoc);
if (HasValueVal == nullptr) {
HasValueVal = &Env.makeAtomicBoolValue();
Env.setValue(HasValueLoc, *HasValueVal);
@ -406,7 +406,7 @@ void transferCallReturningOptional(const CallExpr *E,
if (E->isPRValue()) {
Loc = &State.Env.getResultObjectLocation(*E);
} else {
Loc = cast_or_null<RecordStorageLocation>(State.Env.getStorageLocation(*E));
Loc = State.Env.get<RecordStorageLocation>(*E);
if (Loc == nullptr) {
Loc = &cast<RecordStorageLocation>(State.Env.createStorageLocation(*E));
State.Env.setStorageLocation(*E, *Loc);
@ -449,8 +449,7 @@ BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E,
// This is a constructor/assignment call for `optional<T>` with argument of
// type `optional<U>` such that `T` is constructible from `U`.
auto *Loc =
cast_or_null<RecordStorageLocation>(State.Env.getStorageLocation(E));
auto *Loc = State.Env.get<RecordStorageLocation>(E);
if (auto *HasValueVal = getHasValue(State.Env, Loc))
return *HasValueVal;
return State.Env.makeAtomicBoolValue();
@ -471,8 +470,7 @@ void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal,
LatticeTransferState &State) {
assert(E->getNumArgs() > 0);
if (auto *Loc = cast_or_null<RecordStorageLocation>(
State.Env.getStorageLocation(*E->getArg(0)))) {
if (auto *Loc = State.Env.get<RecordStorageLocation>(*E->getArg(0))) {
createOptionalValue(*Loc, HasValueVal, State.Env);
// Assign a storage location for the whole expression.
@ -534,18 +532,15 @@ void transferSwapCall(const CXXMemberCallExpr *E,
const MatchFinder::MatchResult &,
LatticeTransferState &State) {
assert(E->getNumArgs() == 1);
auto *OtherLoc = cast_or_null<RecordStorageLocation>(
State.Env.getStorageLocation(*E->getArg(0)));
auto *OtherLoc = State.Env.get<RecordStorageLocation>(*E->getArg(0));
transferSwap(getImplicitObjectLocation(*E, State.Env), OtherLoc, State.Env);
}
void transferStdSwapCall(const CallExpr *E, const MatchFinder::MatchResult &,
LatticeTransferState &State) {
assert(E->getNumArgs() == 2);
auto *Arg0Loc = cast_or_null<RecordStorageLocation>(
State.Env.getStorageLocation(*E->getArg(0)));
auto *Arg1Loc = cast_or_null<RecordStorageLocation>(
State.Env.getStorageLocation(*E->getArg(1)));
auto *Arg0Loc = State.Env.get<RecordStorageLocation>(*E->getArg(0));
auto *Arg1Loc = State.Env.get<RecordStorageLocation>(*E->getArg(1));
transferSwap(Arg0Loc, Arg1Loc, State.Env);
}
@ -585,11 +580,9 @@ void transferOptionalAndOptionalCmp(const clang::CXXOperatorCallExpr *CmpExpr,
Environment &Env = State.Env;
auto &A = Env.arena();
auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
auto *Arg0Loc = cast_or_null<RecordStorageLocation>(
Env.getStorageLocation(*CmpExpr->getArg(0)));
auto *Arg0Loc = Env.get<RecordStorageLocation>(*CmpExpr->getArg(0));
if (auto *LHasVal = getHasValue(Env, Arg0Loc)) {
auto *Arg1Loc = cast_or_null<RecordStorageLocation>(
Env.getStorageLocation(*CmpExpr->getArg(1)));
auto *Arg1Loc = Env.get<RecordStorageLocation>(*CmpExpr->getArg(1));
if (auto *RHasVal = getHasValue(Env, Arg1Loc)) {
if (CmpExpr->getOperator() == clang::OO_ExclaimEqual)
CmpValue = &A.makeNot(*CmpValue);
@ -603,7 +596,7 @@ void transferOptionalAndValueCmp(const clang::CXXOperatorCallExpr *CmpExpr,
const clang::Expr *E, Environment &Env) {
auto &A = Env.arena();
auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
auto *Loc = cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*E));
auto *Loc = Env.get<RecordStorageLocation>(*E);
if (auto *HasVal = getHasValue(Env, Loc)) {
if (CmpExpr->getOperator() == clang::OO_ExclaimEqual)
CmpValue = &A.makeNot(*CmpValue);
@ -616,7 +609,7 @@ void transferOptionalAndNulloptCmp(const clang::CXXOperatorCallExpr *CmpExpr,
const clang::Expr *E, Environment &Env) {
auto &A = Env.arena();
auto *CmpValue = &forceBoolValue(Env, *CmpExpr);
auto *Loc = cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*E));
auto *Loc = Env.get<RecordStorageLocation>(*E);
if (auto *HasVal = getHasValue(Env, Loc)) {
if (CmpExpr->getOperator() == clang::OO_ExclaimEqual)
CmpValue = &A.makeNot(*CmpValue);

View file

@ -66,19 +66,8 @@ void clang::dataflow::copyRecord(RecordStorageLocation &Src,
}
}
RecordValue *SrcVal = cast_or_null<RecordValue>(Env.getValue(Src));
RecordValue *DstVal = cast_or_null<RecordValue>(Env.getValue(Dst));
DstVal = &Env.create<RecordValue>(Dst);
RecordValue *DstVal = &Env.create<RecordValue>(Dst);
Env.setValue(Dst, *DstVal);
if (SrcVal == nullptr)
return;
for (const auto &[Name, Value] : SrcVal->properties()) {
if (Value != nullptr)
DstVal->setProperty(Name, *Value);
}
}
bool clang::dataflow::recordsEqual(const RecordStorageLocation &Loc1,
@ -125,25 +114,5 @@ bool clang::dataflow::recordsEqual(const RecordStorageLocation &Loc1,
}
}
llvm::StringMap<Value *> Props1, Props2;
if (RecordValue *Val1 = cast_or_null<RecordValue>(Env1.getValue(Loc1)))
for (const auto &[Name, Value] : Val1->properties())
Props1[Name] = Value;
if (RecordValue *Val2 = cast_or_null<RecordValue>(Env2.getValue(Loc2)))
for (const auto &[Name, Value] : Val2->properties())
Props2[Name] = Value;
if (Props1.size() != Props2.size())
return false;
for (const auto &[Name, Value] : Props1) {
auto It = Props2.find(Name);
if (It == Props2.end())
return false;
if (Value != It->second)
return false;
}
return true;
}

View file

@ -339,8 +339,7 @@ public:
switch (S->getOpcode()) {
case UO_Deref: {
const auto *SubExprVal =
cast_or_null<PointerValue>(Env.getValue(*SubExpr));
const auto *SubExprVal = Env.get<PointerValue>(*SubExpr);
if (SubExprVal == nullptr)
break;
@ -467,8 +466,7 @@ public:
const Expr *Arg = S->getArg(0);
assert(Arg != nullptr);
auto *ArgLoc =
cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg));
auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg);
if (ArgLoc == nullptr)
return;
@ -489,7 +487,6 @@ public:
if (S->getType()->isRecordType()) {
auto &InitialVal = *cast<RecordValue>(Env.createValue(S->getType()));
Env.setValue(*S, InitialVal);
copyRecord(InitialVal.getLoc(), Env.getResultObjectLocation(*S), Env);
}
transferInlineCall(S, ConstructorDecl);
@ -516,14 +513,12 @@ public:
RecordStorageLocation *LocSrc = nullptr;
if (Arg1->isPRValue()) {
if (auto *Val = cast_or_null<RecordValue>(Env.getValue(*Arg1)))
if (auto *Val = Env.get<RecordValue>(*Arg1))
LocSrc = &Val->getLoc();
} else {
LocSrc =
cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg1));
LocSrc = Env.get<RecordStorageLocation>(*Arg1);
}
auto *LocDst =
cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Arg0));
auto *LocDst = Env.get<RecordStorageLocation>(*Arg0);
if (LocSrc == nullptr || LocDst == nullptr)
return;
@ -582,6 +577,14 @@ public:
Env.setValue(*S, *ArgVal);
} else if (const FunctionDecl *F = S->getDirectCallee()) {
transferInlineCall(S, F);
// If this call produces a prvalue of record type, make sure that we have
// a `RecordValue` for it. This is required so that
// `Environment::getResultObjectLocation()` is able to return a location
// for this `CallExpr`.
if (S->getType()->isRecordType() && S->isPRValue())
if (Env.getValue(*S) == nullptr)
refreshRecordValue(*S, Env);
}
}
@ -669,7 +672,7 @@ public:
auto Init = Inits[InitIdx++];
assert(Base.getType().getCanonicalType() ==
Init->getType().getCanonicalType());
auto* BaseVal = cast_or_null<RecordValue>(Env.getValue(*Init));
auto *BaseVal = Env.get<RecordValue>(*Init);
if (!BaseVal)
BaseVal = cast<RecordValue>(Env.createValue(Init->getType()));
// Take ownership of the fields of the `RecordValue` for the base class

View file

@ -130,7 +130,7 @@ private:
if (Env.getValue(Cond) == nullptr)
transfer(StmtToEnv, Cond, Env);
auto *Val = cast_or_null<BoolValue>(Env.getValue(Cond));
auto *Val = Env.get<BoolValue>(Cond);
// Value merging depends on flow conditions from different environments
// being mutually exclusive -- that is, they cannot both be true in their
// entirety (even if they may share some clauses). So, we need *some* value

View file

@ -225,6 +225,7 @@ bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, StringRef,
BPI.SignKey = LangOptions::SignReturnAddressKeyKind::BKey;
BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
return true;
}

View file

@ -419,6 +419,7 @@ bool ARMTargetInfo::validateBranchProtection(StringRef Spec, StringRef Arch,
BPI.SignKey = LangOptions::SignReturnAddressKeyKind::AKey;
BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement;
BPI.BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
return true;
}

View file

@ -350,6 +350,7 @@ bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
.Case("riscv64", Is64Bit)
.Case("32bit", !Is64Bit)
.Case("64bit", Is64Bit)
.Case("experimental", HasExperimental)
.Default(std::nullopt);
if (Result)
return *Result;
@ -382,6 +383,9 @@ bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
FastUnalignedAccess = llvm::is_contained(Features, "+fast-unaligned-access");
if (llvm::is_contained(Features, "+experimental"))
HasExperimental = true;
return true;
}

View file

@ -31,6 +31,7 @@ protected:
private:
bool FastUnalignedAccess;
bool HasExperimental = false;
public:
RISCVTargetInfo(const llvm::Triple &Triple, const TargetOptions &)

View file

@ -57,6 +57,14 @@ std::string getLLVMRevision() {
#endif
}
std::string getClangVendor() {
#ifdef CLANG_VENDOR
return CLANG_VENDOR;
#else
return "";
#endif
}
std::string getClangFullRepositoryVersion() {
std::string buf;
llvm::raw_string_ostream OS(buf);
@ -92,10 +100,7 @@ std::string getClangFullVersion() {
std::string getClangToolFullVersion(StringRef ToolName) {
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
OS << ToolName << " version " CLANG_VERSION_STRING;
OS << getClangVendor() << ToolName << " version " CLANG_VERSION_STRING;
std::string repo = getClangFullRepositoryVersion();
if (!repo.empty()) {
@ -110,10 +115,7 @@ std::string getClangFullCPPVersion() {
// the one we report on the command line.
std::string buf;
llvm::raw_string_ostream OS(buf);
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
OS << "Clang " CLANG_VERSION_STRING;
OS << getClangVendor() << "Clang " CLANG_VERSION_STRING;
std::string repo = getClangFullRepositoryVersion();
if (!repo.empty()) {

View file

@ -198,8 +198,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
}
}
for (unsigned i = 0, e = Opts.Remarks.size(); i != e; ++i) {
StringRef Opt = Opts.Remarks[i];
for (StringRef Opt : Opts.Remarks) {
const auto Flavor = diag::Flavor::Remark;
// Check to see if this warning starts with "no-", if so, this is a

View file

@ -881,7 +881,7 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
<< PluginFN << toString(PassPlugin.takeError());
}
}
for (auto PassCallback : CodeGenOpts.PassBuilderCallbacks)
for (const auto &PassCallback : CodeGenOpts.PassBuilderCallbacks)
PassCallback(PB);
#define HANDLE_EXTENSION(Ext) \
get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB);
@ -1068,11 +1068,8 @@ void EmitAssemblyHelper::RunOptimizationPipeline(
}
}
if (CodeGenOpts.FatLTO) {
// Set module flags, like EnableSplitLTOUnit and UnifiedLTO, since FatLTO
// Set the EnableSplitLTOUnit and UnifiedLTO module flags, since FatLTO
// uses a different action than Backend_EmitBC or Backend_EmitLL.
if (!TheModule->getModuleFlag("ThinLTO"))
TheModule->addModuleFlag(llvm::Module::Error, "ThinLTO",
uint32_t(CodeGenOpts.PrepareForThinLTO));
if (!TheModule->getModuleFlag("EnableSplitLTOUnit"))
TheModule->addModuleFlag(llvm::Module::Error, "EnableSplitLTOUnit",
uint32_t(CodeGenOpts.EnableSplitLTOUnit));

View file

@ -25,7 +25,6 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/OSLog.h"
#include "clang/AST/OperationKinds.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/TargetOptions.h"
@ -232,19 +231,19 @@ static Value *MakeBinaryAtomicValue(
static Value *EmitNontemporalStore(CodeGenFunction &CGF, const CallExpr *E) {
Value *Val = CGF.EmitScalarExpr(E->getArg(0));
Value *Address = CGF.EmitScalarExpr(E->getArg(1));
Address Addr = CGF.EmitPointerWithAlignment(E->getArg(1));
Val = CGF.EmitToMemory(Val, E->getArg(0)->getType());
LValue LV = CGF.MakeNaturalAlignAddrLValue(Address, E->getArg(0)->getType());
LValue LV = CGF.MakeAddrLValue(Addr, E->getArg(0)->getType());
LV.setNontemporal(true);
CGF.EmitStoreOfScalar(Val, LV, false);
return nullptr;
}
static Value *EmitNontemporalLoad(CodeGenFunction &CGF, const CallExpr *E) {
Value *Address = CGF.EmitScalarExpr(E->getArg(0));
Address Addr = CGF.EmitPointerWithAlignment(E->getArg(0));
LValue LV = CGF.MakeNaturalAlignAddrLValue(Address, E->getType());
LValue LV = CGF.MakeAddrLValue(Addr, E->getType());
LV.setNontemporal(true);
return CGF.EmitLoadOfScalar(LV, E->getExprLoc());
}
@ -819,165 +818,6 @@ CodeGenFunction::evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type,
return ConstantInt::get(ResType, ObjectSize, /*isSigned=*/true);
}
llvm::Value *
CodeGenFunction::emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType) {
// The code generated here calculates the size of a struct with a flexible
// array member that uses the counted_by attribute. There are two instances
// we handle:
//
// struct s {
// unsigned long flags;
// int count;
// int array[] __attribute__((counted_by(count)));
// }
//
// 1) bdos of the flexible array itself:
//
// __builtin_dynamic_object_size(p->array, 1) ==
// p->count * sizeof(*p->array)
//
// 2) bdos of a pointer into the flexible array:
//
// __builtin_dynamic_object_size(&p->array[42], 1) ==
// (p->count - 42) * sizeof(*p->array)
//
// 2) bdos of the whole struct, including the flexible array:
//
// __builtin_dynamic_object_size(p, 1) ==
// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
//
ASTContext &Ctx = getContext();
const Expr *Base = E->IgnoreParenImpCasts();
const Expr *Idx = nullptr;
if (const auto *UO = dyn_cast<UnaryOperator>(Base);
UO && UO->getOpcode() == UO_AddrOf) {
Expr *SubExpr = UO->getSubExpr()->IgnoreParenImpCasts();
if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) {
Base = ASE->getBase()->IgnoreParenImpCasts();
Idx = ASE->getIdx()->IgnoreParenImpCasts();
if (const auto *IL = dyn_cast<IntegerLiteral>(Idx)) {
int64_t Val = IL->getValue().getSExtValue();
if (Val < 0)
// __bdos returns 0 for negative indexes into an array in a struct.
return getDefaultBuiltinObjectSizeResult(Type, ResType);
if (Val == 0)
// The index is 0, so we don't need to take it into account.
Idx = nullptr;
}
} else {
// Potential pointer to another element in the struct.
Base = SubExpr;
}
}
// Get the flexible array member Decl.
const ValueDecl *FAMDecl = nullptr;
if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
// Check if \p Base is referencing the FAM itself.
if (const ValueDecl *MD = ME->getMemberDecl()) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
if (!Decl::isFlexibleArrayMemberLike(
Ctx, MD, MD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true))
return nullptr;
FAMDecl = MD;
}
} else if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
// Check if we're pointing to the whole struct.
QualType Ty = DRE->getDecl()->getType();
if (Ty->isPointerType())
Ty = Ty->getPointeeType();
if (const auto *RD = Ty->getAsRecordDecl())
// Don't use the outer lexical record because the FAM might be in a
// different RecordDecl.
FAMDecl = FindFlexibleArrayMemberField(Ctx, RD);
}
if (!FAMDecl || !FAMDecl->hasAttr<CountedByAttr>())
// No flexible array member found or it doesn't have the "counted_by"
// attribute.
return nullptr;
const ValueDecl *CountedByFD = FindCountedByField(Base);
if (!CountedByFD)
// Can't find the field referenced by the "counted_by" attribute.
return nullptr;
// Build a load of the counted_by field.
bool IsSigned = CountedByFD->getType()->isSignedIntegerType();
const Expr *CountedByExpr = BuildCountedByFieldExpr(Base, CountedByFD);
Value *CountedByInst = EmitAnyExprToTemp(CountedByExpr).getScalarVal();
llvm::Type *CountedByTy = CountedByInst->getType();
// Build a load of the index and subtract it from the count.
Value *IdxInst = nullptr;
if (Idx) {
bool IdxSigned = Idx->getType()->isSignedIntegerType();
IdxInst = EmitAnyExprToTemp(Idx).getScalarVal();
IdxInst = IdxSigned ? Builder.CreateSExtOrTrunc(IdxInst, CountedByTy)
: Builder.CreateZExtOrTrunc(IdxInst, CountedByTy);
// We go ahead with the calculation here. If the index turns out to be
// negative, we'll catch it at the end.
CountedByInst =
Builder.CreateSub(CountedByInst, IdxInst, "", !IsSigned, IsSigned);
}
// Calculate how large the flexible array member is in bytes.
const ArrayType *ArrayTy = Ctx.getAsArrayType(FAMDecl->getType());
CharUnits Size = Ctx.getTypeSizeInChars(ArrayTy->getElementType());
llvm::Constant *ElemSize =
llvm::ConstantInt::get(CountedByTy, Size.getQuantity(), IsSigned);
Value *FAMSize =
Builder.CreateMul(CountedByInst, ElemSize, "", !IsSigned, IsSigned);
FAMSize = IsSigned ? Builder.CreateSExtOrTrunc(FAMSize, ResType)
: Builder.CreateZExtOrTrunc(FAMSize, ResType);
Value *Res = FAMSize;
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
// The whole struct is specificed in the __bdos.
const RecordDecl *OuterRD =
CountedByFD->getDeclContext()->getOuterLexicalRecordContext();
const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(OuterRD);
// Get the offset of the FAM.
CharUnits Offset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(FAMDecl));
llvm::Constant *FAMOffset =
ConstantInt::get(ResType, Offset.getQuantity(), IsSigned);
Value *OffsetAndFAMSize =
Builder.CreateAdd(FAMOffset, Res, "", !IsSigned, IsSigned);
// Get the full size of the struct.
llvm::Constant *SizeofStruct =
ConstantInt::get(ResType, Layout.getSize().getQuantity(), IsSigned);
// max(sizeof(struct s),
// offsetof(struct s, array) + p->count * sizeof(*p->array))
Res = IsSigned
? Builder.CreateBinaryIntrinsic(llvm::Intrinsic::smax,
OffsetAndFAMSize, SizeofStruct)
: Builder.CreateBinaryIntrinsic(llvm::Intrinsic::umax,
OffsetAndFAMSize, SizeofStruct);
}
// A negative \p IdxInst or \p CountedByInst means that the index lands
// outside of the flexible array member. If that's the case, we want to
// return 0.
Value *Cmp = Builder.CreateIsNotNeg(CountedByInst);
if (IdxInst)
Cmp = Builder.CreateAnd(Builder.CreateIsNotNeg(IdxInst), Cmp);
return Builder.CreateSelect(Cmp, Res, ConstantInt::get(ResType, 0, IsSigned));
}
/// Returns a Value corresponding to the size of the given expression.
/// This Value may be either of the following:
/// - A llvm::Argument (if E is a param with the pass_object_size attribute on
@ -1010,13 +850,6 @@ CodeGenFunction::emitBuiltinObjectSize(const Expr *E, unsigned Type,
}
}
if (IsDynamic) {
// Emit special code for a flexible array member with the "counted_by"
// attribute.
if (Value *V = emitFlexibleArrayMemberSize(E, Type, ResType))
return V;
}
// LLVM can't handle Type=3 appropriately, and __builtin_object_size shouldn't
// evaluate E for side-effects. In either case, we shouldn't lower to
// @llvm.objectsize.
@ -3214,7 +3047,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
Value *AlignmentValue = EmitScalarExpr(E->getArg(1));
ConstantInt *AlignmentCI = cast<ConstantInt>(AlignmentValue);
if (AlignmentCI->getValue().ugt(llvm::Value::MaximumAlignment))
AlignmentCI = ConstantInt::get(AlignmentCI->getType(),
AlignmentCI = ConstantInt::get(AlignmentCI->getIntegerType(),
llvm::Value::MaximumAlignment);
emitAlignmentAssumption(PtrValue, Ptr,
@ -10485,6 +10318,30 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
return nullptr;
}
static void swapCommutativeSMEOperands(unsigned BuiltinID,
SmallVectorImpl<Value *> &Ops) {
unsigned MultiVec;
switch (BuiltinID) {
default:
return;
case SME::BI__builtin_sme_svsumla_za32_s8_vg4x1:
MultiVec = 1;
break;
case SME::BI__builtin_sme_svsumla_za32_s8_vg4x2:
case SME::BI__builtin_sme_svsudot_za32_s8_vg1x2:
MultiVec = 2;
break;
case SME::BI__builtin_sme_svsudot_za32_s8_vg1x4:
case SME::BI__builtin_sme_svsumla_za32_s8_vg4x4:
MultiVec = 4;
break;
}
if (MultiVec > 0)
for (unsigned I = 0; I < MultiVec; ++I)
std::swap(Ops[I + 1], Ops[I + 1 + MultiVec]);
}
Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
auto *Builtin = findARMVectorIntrinsicInMap(AArch64SMEIntrinsicMap, BuiltinID,
@ -10507,6 +10364,9 @@ Value *CodeGenFunction::EmitAArch64SMEBuiltinExpr(unsigned BuiltinID,
BuiltinID == SME::BI__builtin_sme_svstr_za)
return EmitSMELdrStr(TypeFlags, Ops, Builtin->LLVMIntrinsic);
// Handle builtins which require their multi-vector operands to be swapped
swapCommutativeSMEOperands(BuiltinID, Ops);
// Should not happen!
if (Builtin->LLVMIntrinsic == 0)
return nullptr;
@ -17034,7 +16894,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
Value *Op1 = EmitScalarExpr(E->getArg(1));
ConstantInt *AlignmentCI = cast<ConstantInt>(Op0);
if (AlignmentCI->getValue().ugt(llvm::Value::MaximumAlignment))
AlignmentCI = ConstantInt::get(AlignmentCI->getType(),
AlignmentCI = ConstantInt::get(AlignmentCI->getIntegerType(),
llvm::Value::MaximumAlignment);
emitAlignmentAssumption(Op1, E->getArg(1),
@ -17272,7 +17132,8 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID,
Op0, llvm::FixedVectorType::get(ConvertType(E->getType()), 2));
if (getTarget().isLittleEndian())
Index = ConstantInt::get(Index->getType(), 1 - Index->getZExtValue());
Index =
ConstantInt::get(Index->getIntegerType(), 1 - Index->getZExtValue());
return Builder.CreateExtractElement(Unpacked, Index);
}

View file

@ -30,7 +30,6 @@
#include "clang/Basic/CodeGenOptions.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Intrinsics.h"
@ -926,27 +925,16 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
if (CE->getCastKind() == CK_ArrayToPointerDecay &&
!CE->getSubExpr()->isFlexibleArrayMemberLike(CGF.getContext(),
StrictFlexArraysLevel)) {
CodeGenFunction::SanitizerScope SanScope(&CGF);
IndexedType = CE->getSubExpr()->getType();
const ArrayType *AT = IndexedType->castAsArrayTypeUnsafe();
if (const auto *CAT = dyn_cast<ConstantArrayType>(AT))
return CGF.Builder.getInt(CAT->getSize());
if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
else if (const auto *VAT = dyn_cast<VariableArrayType>(AT))
return CGF.getVLASize(VAT).NumElts;
// Ignore pass_object_size here. It's not applicable on decayed pointers.
}
if (const ValueDecl *VD = CGF.FindCountedByField(Base)) {
IndexedType = Base->getType();
const Expr *E = CGF.BuildCountedByFieldExpr(Base, VD);
return CGF.EmitAnyExprToTemp(E).getScalarVal();
}
}
CodeGenFunction::SanitizerScope SanScope(&CGF);
QualType EltTy{Base->getType()->getPointeeOrArrayElementType(), 0};
if (llvm::Value *POS = CGF.LoadPassedObjectSize(Base, EltTy)) {
IndexedType = Base->getType();
@ -956,122 +944,13 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
return nullptr;
}
const Expr *
CodeGenFunction::BuildCountedByFieldExpr(const Expr *Base,
const ValueDecl *CountedByVD) {
// Find the outer struct expr (i.e. p in p->a.b.c.d).
Expr *CountedByExpr = const_cast<Expr *>(Base)->IgnoreParenImpCasts();
// Work our way up the expression until we reach the DeclRefExpr.
while (!isa<DeclRefExpr>(CountedByExpr))
if (const auto *ME = dyn_cast<MemberExpr>(CountedByExpr))
CountedByExpr = ME->getBase()->IgnoreParenImpCasts();
// Add back an implicit cast to create the required pr-value.
CountedByExpr = ImplicitCastExpr::Create(
getContext(), CountedByExpr->getType(), CK_LValueToRValue, CountedByExpr,
nullptr, VK_PRValue, FPOptionsOverride());
if (const auto *IFD = dyn_cast<IndirectFieldDecl>(CountedByVD)) {
// The counted_by field is inside an anonymous struct / union. The
// IndirectFieldDecl has the correct order of FieldDecls to build this
// easily. (Yay!)
for (NamedDecl *ND : IFD->chain()) {
auto *VD = cast<ValueDecl>(ND);
CountedByExpr =
MemberExpr::CreateImplicit(getContext(), CountedByExpr,
CountedByExpr->getType()->isPointerType(),
VD, VD->getType(), VK_LValue, OK_Ordinary);
}
} else {
CountedByExpr = MemberExpr::CreateImplicit(
getContext(), const_cast<Expr *>(CountedByExpr),
CountedByExpr->getType()->isPointerType(),
const_cast<ValueDecl *>(CountedByVD), CountedByVD->getType(), VK_LValue,
OK_Ordinary);
}
return CountedByExpr;
}
const ValueDecl *
CodeGenFunction::FindFlexibleArrayMemberField(ASTContext &Ctx,
const RecordDecl *RD) {
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
for (const Decl *D : RD->decls()) {
if (const auto *VD = dyn_cast<ValueDecl>(D);
VD && Decl::isFlexibleArrayMemberLike(
Ctx, VD, VD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true))
return VD;
if (const auto *Record = dyn_cast<RecordDecl>(D))
if (const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, Record))
return VD;
}
return nullptr;
}
const ValueDecl *CodeGenFunction::FindCountedByField(const Expr *Base) {
ASTContext &Ctx = getContext();
const RecordDecl *OuterRD = nullptr;
const FieldDecl *FD = nullptr;
Base = Base->IgnoreParenImpCasts();
// Get the outer-most lexical RecordDecl.
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base)) {
QualType Ty = DRE->getDecl()->getType();
if (Ty->isPointerType())
Ty = Ty->getPointeeType();
if (const auto *RD = Ty->getAsRecordDecl())
OuterRD = RD->getOuterLexicalRecordContext();
} else if (const auto *ME = dyn_cast<MemberExpr>(Base)) {
if (const ValueDecl *MD = ME->getMemberDecl()) {
OuterRD = MD->getDeclContext()->getOuterLexicalRecordContext();
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
if (Decl::isFlexibleArrayMemberLike(
Ctx, MD, MD->getType(), StrictFlexArraysLevel,
/*IgnoreTemplateOrMacroSubstitution=*/true))
// Base is referencing the FAM itself.
FD = dyn_cast<FieldDecl>(MD);
}
}
if (!OuterRD)
return nullptr;
if (!FD) {
const ValueDecl *VD = FindFlexibleArrayMemberField(Ctx, OuterRD);
FD = dyn_cast_if_present<FieldDecl>(VD);
if (!FD)
return nullptr;
}
const auto *CBA = FD->getAttr<CountedByAttr>();
if (!CBA)
return nullptr;
DeclarationName DName(CBA->getCountedByField());
DeclContext::lookup_result Lookup = OuterRD->lookup(DName);
if (Lookup.empty())
return nullptr;
return dyn_cast<ValueDecl>(Lookup.front());
}
void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
llvm::Value *Index, QualType IndexType,
bool Accessed) {
assert(SanOpts.has(SanitizerKind::ArrayBounds) &&
"should not be called unless adding bounds checks");
SanitizerScope SanScope(this);
const LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
getLangOpts().getStrictFlexArraysLevel();
@ -1081,8 +960,6 @@ void CodeGenFunction::EmitBoundsCheck(const Expr *E, const Expr *Base,
if (!Bound)
return;
SanitizerScope SanScope(this);
bool IndexSigned = IndexType->isSignedIntegerOrEnumerationType();
llvm::Value *IndexVal = Builder.CreateIntCast(Index, SizeTy, IndexSigned);
llvm::Value *BoundVal = Builder.CreateIntCast(Bound, SizeTy, false);

View file

@ -1894,8 +1894,8 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
// initializer, since LLVM optimizers generally do not want to touch
// shuffles.
unsigned CurIdx = 0;
bool VIsUndefShuffle = false;
llvm::Value *V = llvm::UndefValue::get(VType);
bool VIsPoisonShuffle = false;
llvm::Value *V = llvm::PoisonValue::get(VType);
for (unsigned i = 0; i != NumInitElements; ++i) {
Expr *IE = E->getInit(i);
Value *Init = Visit(IE);
@ -1915,16 +1915,16 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
llvm::ConstantInt *C = cast<llvm::ConstantInt>(EI->getIndexOperand());
Value *LHS = nullptr, *RHS = nullptr;
if (CurIdx == 0) {
// insert into undef -> shuffle (src, undef)
// insert into poison -> shuffle (src, poison)
// shufflemask must use an i32
Args.push_back(getAsInt32(C, CGF.Int32Ty));
Args.resize(ResElts, -1);
LHS = EI->getVectorOperand();
RHS = V;
VIsUndefShuffle = true;
} else if (VIsUndefShuffle) {
// insert into undefshuffle && size match -> shuffle (v, src)
VIsPoisonShuffle = true;
} else if (VIsPoisonShuffle) {
// insert into poison shuffle && size match -> shuffle (v, src)
llvm::ShuffleVectorInst *SVV = cast<llvm::ShuffleVectorInst>(V);
for (unsigned j = 0; j != CurIdx; ++j)
Args.push_back(getMaskElt(SVV, j, 0));
@ -1933,7 +1933,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
LHS = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
RHS = EI->getVectorOperand();
VIsUndefShuffle = false;
VIsPoisonShuffle = false;
}
if (!Args.empty()) {
V = Builder.CreateShuffleVector(LHS, RHS, Args);
@ -1944,7 +1944,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
}
V = Builder.CreateInsertElement(V, Init, Builder.getInt32(CurIdx),
"vecinit");
VIsUndefShuffle = false;
VIsPoisonShuffle = false;
++CurIdx;
continue;
}
@ -1962,9 +1962,9 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
if (OpTy->getNumElements() == ResElts) {
for (unsigned j = 0; j != CurIdx; ++j) {
// If the current vector initializer is a shuffle with undef, merge
// If the current vector initializer is a shuffle with poison, merge
// this shuffle directly into it.
if (VIsUndefShuffle) {
if (VIsPoisonShuffle) {
Args.push_back(getMaskElt(cast<llvm::ShuffleVectorInst>(V), j, 0));
} else {
Args.push_back(j);
@ -1974,7 +1974,7 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Args.push_back(getMaskElt(SVI, j, Offset));
Args.resize(ResElts, -1);
if (VIsUndefShuffle)
if (VIsPoisonShuffle)
V = cast<llvm::ShuffleVectorInst>(V)->getOperand(0);
Init = SVOp;
@ -1997,12 +1997,12 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
Args.resize(ResElts, -1);
}
// If V is undef, make sure it ends up on the RHS of the shuffle to aid
// If V is poison, make sure it ends up on the RHS of the shuffle to aid
// merging subsequent shuffles into this one.
if (CurIdx == 0)
std::swap(V, Init);
V = Builder.CreateShuffleVector(V, Init, Args, "vecinit");
VIsUndefShuffle = isa<llvm::UndefValue>(Init);
VIsPoisonShuffle = isa<llvm::PoisonValue>(Init);
CurIdx += InitElts;
}

View file

@ -182,10 +182,8 @@ void CGHLSLRuntime::finishCodeGen() {
llvm::hlsl::ResourceKind RK = Buf.IsCBuffer
? llvm::hlsl::ResourceKind::CBuffer
: llvm::hlsl::ResourceKind::TBuffer;
std::string TyName =
Buf.Name.str() + (Buf.IsCBuffer ? ".cb." : ".tb.") + "ty";
addBufferResourceAnnotation(GV, TyName, RC, RK, /*IsROV=*/false,
Buf.Binding);
addBufferResourceAnnotation(GV, RC, RK, /*IsROV=*/false,
llvm::hlsl::ElementType::Invalid, Buf.Binding);
}
}
@ -194,10 +192,10 @@ CGHLSLRuntime::Buffer::Buffer(const HLSLBufferDecl *D)
Binding(D->getAttr<HLSLResourceBindingAttr>()) {}
void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::StringRef TyName,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK,
bool IsROV,
llvm::hlsl::ElementType ET,
BufferResBinding &Binding) {
llvm::Module &M = CGM.getModule();
@ -216,15 +214,62 @@ void CGHLSLRuntime::addBufferResourceAnnotation(llvm::GlobalVariable *GV,
assert(false && "Unsupported buffer type!");
return;
}
assert(ResourceMD != nullptr &&
"ResourceMD must have been set by the switch above.");
llvm::hlsl::FrontendResource Res(
GV, TyName, RK, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
GV, RK, ET, IsROV, Binding.Reg.value_or(UINT_MAX), Binding.Space);
ResourceMD->addOperand(Res.getMetadata());
}
static llvm::hlsl::ElementType
calculateElementType(const ASTContext &Context, const clang::Type *ResourceTy) {
using llvm::hlsl::ElementType;
// TODO: We may need to update this when we add things like ByteAddressBuffer
// that don't have a template parameter (or, indeed, an element type).
const auto *TST = ResourceTy->getAs<TemplateSpecializationType>();
assert(TST && "Resource types must be template specializations");
ArrayRef<TemplateArgument> Args = TST->template_arguments();
assert(!Args.empty() && "Resource has no element type");
// At this point we have a resource with an element type, so we can assume
// that it's valid or we would have diagnosed the error earlier.
QualType ElTy = Args[0].getAsType();
// We should either have a basic type or a vector of a basic type.
if (const auto *VecTy = ElTy->getAs<clang::VectorType>())
ElTy = VecTy->getElementType();
if (ElTy->isSignedIntegerType()) {
switch (Context.getTypeSize(ElTy)) {
case 16:
return ElementType::I16;
case 32:
return ElementType::I32;
case 64:
return ElementType::I64;
}
} else if (ElTy->isUnsignedIntegerType()) {
switch (Context.getTypeSize(ElTy)) {
case 16:
return ElementType::U16;
case 32:
return ElementType::U32;
case 64:
return ElementType::U64;
}
} else if (ElTy->isSpecificBuiltinType(BuiltinType::Half))
return ElementType::F16;
else if (ElTy->isSpecificBuiltinType(BuiltinType::Float))
return ElementType::F32;
else if (ElTy->isSpecificBuiltinType(BuiltinType::Double))
return ElementType::F64;
// TODO: We need to handle unorm/snorm float types here once we support them
llvm_unreachable("Invalid element type for resource");
}
void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
const Type *Ty = D->getType()->getPointeeOrArrayElementType();
if (!Ty)
@ -239,10 +284,10 @@ void CGHLSLRuntime::annotateHLSLResource(const VarDecl *D, GlobalVariable *GV) {
llvm::hlsl::ResourceClass RC = Attr->getResourceClass();
llvm::hlsl::ResourceKind RK = Attr->getResourceKind();
bool IsROV = Attr->getIsROV();
llvm::hlsl::ElementType ET = calculateElementType(CGM.getContext(), Ty);
QualType QT(Ty, 0);
BufferResBinding Binding(D->getAttr<HLSLResourceBindingAttr>());
addBufferResourceAnnotation(GV, QT.getAsString(), RC, RK, IsROV, Binding);
addBufferResourceAnnotation(GV, RC, RK, IsROV, ET, Binding);
}
CGHLSLRuntime::BufferResBinding::BufferResBinding(

View file

@ -90,9 +90,9 @@ public:
private:
void addBufferResourceAnnotation(llvm::GlobalVariable *GV,
llvm::StringRef TyName,
llvm::hlsl::ResourceClass RC,
llvm::hlsl::ResourceKind RK, bool IsROV,
llvm::hlsl::ElementType ET,
BufferResBinding &Binding);
void addConstant(VarDecl *D, Buffer &CB);
void addBufferDecls(const DeclContext *DC, Buffer &CB);

View file

@ -6811,8 +6811,10 @@ private:
OpenMPMapClauseKind MapType, ArrayRef<OpenMPMapModifierKind> MapModifiers,
ArrayRef<OpenMPMotionModifierKind> MotionModifiers,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
MapCombinedInfoTy &CombinedInfo, StructRangeInfoTy &PartialStruct,
bool IsFirstComponentList, bool IsImplicit,
MapCombinedInfoTy &CombinedInfo,
MapCombinedInfoTy &StructBaseCombinedInfo,
StructRangeInfoTy &PartialStruct, bool IsFirstComponentList,
bool IsImplicit, bool GenerateAllInfoForClauses,
const ValueDecl *Mapper = nullptr, bool ForDeviceAddr = false,
const ValueDecl *BaseDecl = nullptr, const Expr *MapExpr = nullptr,
ArrayRef<OMPClauseMappableExprCommon::MappableExprComponentListRef>
@ -7098,6 +7100,25 @@ private:
bool IsNonContiguous = CombinedInfo.NonContigInfo.IsNonContiguous;
bool IsPrevMemberReference = false;
// We need to check if we will be encountering any MEs. If we do not
// encounter any ME expression it means we will be mapping the whole struct.
// In that case we need to skip adding an entry for the struct to the
// CombinedInfo list and instead add an entry to the StructBaseCombinedInfo
// list only when generating all info for clauses.
bool IsMappingWholeStruct = true;
if (!GenerateAllInfoForClauses) {
IsMappingWholeStruct = false;
} else {
for (auto TempI = I; TempI != CE; ++TempI) {
const MemberExpr *PossibleME =
dyn_cast<MemberExpr>(TempI->getAssociatedExpression());
if (PossibleME) {
IsMappingWholeStruct = false;
break;
}
}
}
for (; I != CE; ++I) {
// If the current component is member of a struct (parent struct) mark it.
if (!EncounteredME) {
@ -7317,21 +7338,41 @@ private:
break;
}
llvm::Value *Size = getExprTypeSize(I->getAssociatedExpression());
// Skip adding an entry in the CurInfo of this combined entry if the
// whole struct is currently being mapped. The struct needs to be added
// in the first position before any data internal to the struct is being
// mapped.
if (!IsMemberPointerOrAddr ||
(Next == CE && MapType != OMPC_MAP_unknown)) {
CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
CombinedInfo.BasePointers.push_back(BP.getPointer());
CombinedInfo.DevicePtrDecls.push_back(nullptr);
CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
CombinedInfo.Pointers.push_back(LB.getPointer());
CombinedInfo.Sizes.push_back(
CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true));
CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize
: 1);
if (!IsMappingWholeStruct) {
CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
CombinedInfo.BasePointers.push_back(BP.getPointer());
CombinedInfo.DevicePtrDecls.push_back(nullptr);
CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
CombinedInfo.Pointers.push_back(LB.getPointer());
CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
Size, CGF.Int64Ty, /*isSigned=*/true));
CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize
: 1);
} else {
StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr);
StructBaseCombinedInfo.BasePointers.push_back(BP.getPointer());
StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr);
StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None);
StructBaseCombinedInfo.Pointers.push_back(LB.getPointer());
StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast(
Size, CGF.Int64Ty, /*isSigned=*/true));
StructBaseCombinedInfo.NonContigInfo.Dims.push_back(
IsNonContiguous ? DimSize : 1);
}
// If Mapper is valid, the last component inherits the mapper.
bool HasMapper = Mapper && Next == CE;
CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr);
if (!IsMappingWholeStruct)
CombinedInfo.Mappers.push_back(HasMapper ? Mapper : nullptr);
else
StructBaseCombinedInfo.Mappers.push_back(HasMapper ? Mapper
: nullptr);
// We need to add a pointer flag for each map that comes from the
// same expression except for the first one. We also need to signal
@ -7363,7 +7404,10 @@ private:
}
}
CombinedInfo.Types.push_back(Flags);
if (!IsMappingWholeStruct)
CombinedInfo.Types.push_back(Flags);
else
StructBaseCombinedInfo.Types.push_back(Flags);
}
// If we have encountered a member expression so far, keep track of the
@ -7954,8 +7998,10 @@ private:
for (const auto &Data : Info) {
StructRangeInfoTy PartialStruct;
// Temporary generated information.
// Current struct information:
MapCombinedInfoTy CurInfo;
// Current struct base information:
MapCombinedInfoTy StructBaseCurInfo;
const Decl *D = Data.first;
const ValueDecl *VD = cast_or_null<ValueDecl>(D);
for (const auto &M : Data.second) {
@ -7965,29 +8011,55 @@ private:
// Remember the current base pointer index.
unsigned CurrentBasePointersIdx = CurInfo.BasePointers.size();
unsigned StructBasePointersIdx =
StructBaseCurInfo.BasePointers.size();
CurInfo.NonContigInfo.IsNonContiguous =
L.Components.back().isNonContiguous();
generateInfoForComponentList(
L.MapType, L.MapModifiers, L.MotionModifiers, L.Components,
CurInfo, PartialStruct, /*IsFirstComponentList=*/false,
L.IsImplicit, L.Mapper, L.ForDeviceAddr, VD, L.VarRef);
CurInfo, StructBaseCurInfo, PartialStruct,
/*IsFirstComponentList=*/false, L.IsImplicit,
/*GenerateAllInfoForClauses*/ true, L.Mapper, L.ForDeviceAddr, VD,
L.VarRef);
// If this entry relates with a device pointer, set the relevant
// If this entry relates to a device pointer, set the relevant
// declaration and add the 'return pointer' flag.
if (L.ReturnDevicePointer) {
assert(CurInfo.BasePointers.size() > CurrentBasePointersIdx &&
// Check whether a value was added to either CurInfo or
// StructBaseCurInfo and error if no value was added to either of
// them:
assert((CurrentBasePointersIdx < CurInfo.BasePointers.size() ||
StructBasePointersIdx <
StructBaseCurInfo.BasePointers.size()) &&
"Unexpected number of mapped base pointers.");
// Choose a base pointer index which is always valid:
const ValueDecl *RelevantVD =
L.Components.back().getAssociatedDeclaration();
assert(RelevantVD &&
"No relevant declaration related with device pointer??");
CurInfo.DevicePtrDecls[CurrentBasePointersIdx] = RelevantVD;
CurInfo.DevicePointers[CurrentBasePointersIdx] =
L.ForDeviceAddr ? DeviceInfoTy::Address : DeviceInfoTy::Pointer;
CurInfo.Types[CurrentBasePointersIdx] |=
OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
// If StructBaseCurInfo has been updated this iteration then work on
// the first new entry added to it i.e. make sure that when multiple
// values are added to any of the lists, the first value added is
// being modified by the assignments below (not the last value
// added).
if (StructBasePointersIdx < StructBaseCurInfo.BasePointers.size()) {
StructBaseCurInfo.DevicePtrDecls[StructBasePointersIdx] =
RelevantVD;
StructBaseCurInfo.DevicePointers[StructBasePointersIdx] =
L.ForDeviceAddr ? DeviceInfoTy::Address
: DeviceInfoTy::Pointer;
StructBaseCurInfo.Types[StructBasePointersIdx] |=
OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
} else {
CurInfo.DevicePtrDecls[CurrentBasePointersIdx] = RelevantVD;
CurInfo.DevicePointers[CurrentBasePointersIdx] =
L.ForDeviceAddr ? DeviceInfoTy::Address
: DeviceInfoTy::Pointer;
CurInfo.Types[CurrentBasePointersIdx] |=
OpenMPOffloadMappingFlags::OMP_MAP_RETURN_PARAM;
}
}
}
}
@ -8034,17 +8106,24 @@ private:
CurInfo.Mappers.push_back(nullptr);
}
}
// Unify entries in one list making sure the struct mapping precedes the
// individual fields:
MapCombinedInfoTy UnionCurInfo;
UnionCurInfo.append(StructBaseCurInfo);
UnionCurInfo.append(CurInfo);
// If there is an entry in PartialStruct it means we have a struct with
// individual members mapped. Emit an extra combined entry.
if (PartialStruct.Base.isValid()) {
CurInfo.NonContigInfo.Dims.push_back(0);
emitCombinedEntry(CombinedInfo, CurInfo.Types, PartialStruct,
UnionCurInfo.NonContigInfo.Dims.push_back(0);
// Emit a combined entry:
emitCombinedEntry(CombinedInfo, UnionCurInfo.Types, PartialStruct,
/*IsMapThis*/ !VD, OMPBuilder, VD);
}
// We need to append the results of this capture to what we already
// have.
CombinedInfo.append(CurInfo);
// We need to append the results of this capture to what we already have.
CombinedInfo.append(UnionCurInfo);
}
// Append data for use_device_ptr clauses.
CombinedInfo.append(UseDeviceDataCombinedInfo);
@ -8554,6 +8633,7 @@ public:
// Associated with a capture, because the mapping flags depend on it.
// Go through all of the elements with the overlapped elements.
bool IsFirstComponentList = true;
MapCombinedInfoTy StructBaseCombinedInfo;
for (const auto &Pair : OverlappedData) {
const MapData &L = *Pair.getFirst();
OMPClauseMappableExprCommon::MappableExprComponentListRef Components;
@ -8568,7 +8648,8 @@ public:
OverlappedComponents = Pair.getSecond();
generateInfoForComponentList(
MapType, MapModifiers, std::nullopt, Components, CombinedInfo,
PartialStruct, IsFirstComponentList, IsImplicit, Mapper,
StructBaseCombinedInfo, PartialStruct, IsFirstComponentList,
IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef, OverlappedComponents);
IsFirstComponentList = false;
}
@ -8584,10 +8665,11 @@ public:
L;
auto It = OverlappedData.find(&L);
if (It == OverlappedData.end())
generateInfoForComponentList(MapType, MapModifiers, std::nullopt,
Components, CombinedInfo, PartialStruct,
IsFirstComponentList, IsImplicit, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef);
generateInfoForComponentList(
MapType, MapModifiers, std::nullopt, Components, CombinedInfo,
StructBaseCombinedInfo, PartialStruct, IsFirstComponentList,
IsImplicit, /*GenerateAllInfoForClauses*/ false, Mapper,
/*ForDeviceAddr=*/false, VD, VarRef);
IsFirstComponentList = false;
}
}

View file

@ -3022,19 +3022,6 @@ public:
void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index,
QualType IndexType, bool Accessed);
// Find a struct's flexible array member. It may be embedded inside multiple
// sub-structs, but must still be the last field.
const ValueDecl *FindFlexibleArrayMemberField(ASTContext &Ctx,
const RecordDecl *RD);
/// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns
/// \p nullptr if either the attribute or the field doesn't exist.
const ValueDecl *FindCountedByField(const Expr *Base);
/// Build an expression accessing the "counted_by" field.
const Expr *BuildCountedByFieldExpr(const Expr *Base,
const ValueDecl *CountedByVD);
llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
bool isInc, bool isPre);
ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
@ -4830,9 +4817,6 @@ private:
llvm::Value *EmittedE,
bool IsDynamic);
llvm::Value *emitFlexibleArrayMemberSize(const Expr *E, unsigned Type,
llvm::IntegerType *ResType);
void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D,
Address Loc);

View file

@ -995,12 +995,7 @@ void CodeGenModule::Release() {
uint32_t(CLANG_VERSION_MINOR));
getModule().addModuleFlag(llvm::Module::Warning, "zos_product_patchlevel",
uint32_t(CLANG_VERSION_PATCHLEVEL));
std::string ProductId;
#ifdef CLANG_VENDOR
ProductId = #CLANG_VENDOR;
#else
ProductId = "clang";
#endif
std::string ProductId = getClangVendor() + "clang";
getModule().addModuleFlag(llvm::Module::Error, "zos_product_id",
llvm::MDString::get(VMContext, ProductId));
@ -1111,6 +1106,9 @@ void CodeGenModule::Release() {
if (LangOpts.BranchTargetEnforcement)
getModule().addModuleFlag(llvm::Module::Min, "branch-target-enforcement",
1);
if (LangOpts.BranchProtectionPAuthLR)
getModule().addModuleFlag(llvm::Module::Min, "branch-protection-pauth-lr",
1);
if (LangOpts.hasSignReturnAddress())
getModule().addModuleFlag(llvm::Module::Min, "sign-return-address", 1);
if (LangOpts.isSignReturnAddressScopeAll())

View file

@ -136,6 +136,8 @@ public:
Fn->addFnAttr("branch-target-enforcement",
BPI.BranchTargetEnforcement ? "true" : "false");
Fn->addFnAttr("branch-protection-pauth-lr",
BPI.BranchProtectionPAuthLR ? "true" : "false");
}
bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,

View file

@ -328,6 +328,12 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
if (D.IsFlangMode()) {
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
addFortranRuntimeLibs(ToolChain, Args, CmdArgs);
CmdArgs.push_back("-lm");
CmdArgs.push_back("-lpthread");
}
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
Exec, CmdArgs, Inputs, Output));

View file

@ -45,6 +45,10 @@ static bool getArchFeatures(const Driver &D, StringRef Arch,
(*ISAInfo)->toFeatures(
Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); },
/*AddAllExtensions=*/true);
if (EnableExperimentalExtensions)
Features.push_back(Args.MakeArgString("+experimental"));
return true;
}

View file

@ -1497,7 +1497,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< Triple.getArchName();
StringRef Scope, Key;
bool IndirectBranches;
bool IndirectBranches, BranchProtectionPAuthLR;
if (A->getOption().matches(options::OPT_msign_return_address_EQ)) {
Scope = A->getValue();
@ -1506,6 +1506,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< A->getSpelling() << Scope;
Key = "a_key";
IndirectBranches = false;
BranchProtectionPAuthLR = false;
} else {
StringRef DiagMsg;
llvm::ARM::ParsedBranchProtection PBP;
@ -1517,6 +1518,7 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
<< "b-key" << A->getAsString(Args);
Scope = PBP.Scope;
Key = PBP.Key;
BranchProtectionPAuthLR = PBP.BranchProtectionPAuthLR;
IndirectBranches = PBP.BranchTargetEnforcement;
}
@ -1525,6 +1527,9 @@ static void CollectARMPACBTIOptions(const ToolChain &TC, const ArgList &Args,
if (!Scope.equals("none"))
CmdArgs.push_back(
Args.MakeArgString(Twine("-msign-return-address-key=") + Key));
if (BranchProtectionPAuthLR)
CmdArgs.push_back(
Args.MakeArgString(Twine("-mbranch-protection-pauth-lr")));
if (IndirectBranches)
CmdArgs.push_back("-mbranch-target-enforce");
}
@ -3198,13 +3203,13 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
options::OPT_fstrict_float_cast_overflow, false))
CmdArgs.push_back("-fno-strict-float-cast-overflow");
if (const Arg *A = Args.getLastArg(options::OPT_fcx_limited_range))
if (Args.hasArg(options::OPT_fcx_limited_range))
CmdArgs.push_back("-fcx-limited-range");
if (const Arg *A = Args.getLastArg(options::OPT_fcx_fortran_rules))
if (Args.hasArg(options::OPT_fcx_fortran_rules))
CmdArgs.push_back("-fcx-fortran-rules");
if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_limited_range))
if (Args.hasArg(options::OPT_fno_cx_limited_range))
CmdArgs.push_back("-fno-cx-limited-range");
if (const Arg *A = Args.getLastArg(options::OPT_fno_cx_fortran_rules))
if (Args.hasArg(options::OPT_fno_cx_fortran_rules))
CmdArgs.push_back("-fno-cx-fortran-rules");
}

View file

@ -1174,8 +1174,9 @@ static void addFortranMain(const ToolChain &TC, const ArgList &Args,
// The --whole-archive option needs to be part of the link line to make
// sure that the main() function from Fortran_main.a is pulled in by the
// linker. However, it shouldn't be used if it's already active.
// TODO: Find an equivalent of `--whole-archive` for Darwin.
if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX()) {
// TODO: Find an equivalent of `--whole-archive` for Darwin and AIX.
if (!isWholeArchivePresent(Args) && !TC.getTriple().isMacOSX() &&
!TC.getTriple().isOSAIX()) {
CmdArgs.push_back("--whole-archive");
CmdArgs.push_back("-lFortran_main");
CmdArgs.push_back("--no-whole-archive");
@ -1317,28 +1318,28 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Collect shared runtimes.
if (SanArgs.needsSharedRt()) {
if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsAsanRt()) {
SharedRuntimes.push_back("asan");
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
HelperStaticRuntimes.push_back("asan-preinit");
}
if (SanArgs.needsMemProfRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsMemProfRt()) {
SharedRuntimes.push_back("memprof");
if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
HelperStaticRuntimes.push_back("memprof-preinit");
}
if (SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime())
SharedRuntimes.push_back("ubsan_minimal");
else
SharedRuntimes.push_back("ubsan_standalone");
}
if (SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsScudoRt()) {
SharedRuntimes.push_back("scudo_standalone");
}
if (SanArgs.needsTsanRt() && SanArgs.linkRuntimes())
if (SanArgs.needsTsanRt())
SharedRuntimes.push_back("tsan");
if (SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt())
SharedRuntimes.push_back("hwasan_aliases");
else
@ -1349,7 +1350,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
}
// The stats_client library is also statically linked into DSOs.
if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes())
if (SanArgs.needsStatsRt())
StaticRuntimes.push_back("stats_client");
// Always link the static runtime regardless of DSO or executable.
@ -1365,20 +1366,19 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
// Each static runtime that has a DSO counterpart above is excluded below,
// but runtimes that exist only as static are not affected by needsSharedRt.
if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt()) {
StaticRuntimes.push_back("asan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("asan_cxx");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt() &&
SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsMemProfRt()) {
StaticRuntimes.push_back("memprof");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("memprof_cxx");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt() && SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsHwasanRt()) {
if (SanArgs.needsHwasanAliasesRt()) {
StaticRuntimes.push_back("hwasan_aliases");
if (SanArgs.linkCXXRuntimes())
@ -1389,22 +1389,21 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("hwasan_cxx");
}
}
if (SanArgs.needsDfsanRt() && SanArgs.linkRuntimes())
if (SanArgs.needsDfsanRt())
StaticRuntimes.push_back("dfsan");
if (SanArgs.needsLsanRt() && SanArgs.linkRuntimes())
if (SanArgs.needsLsanRt())
StaticRuntimes.push_back("lsan");
if (SanArgs.needsMsanRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsMsanRt()) {
StaticRuntimes.push_back("msan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("msan_cxx");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt() &&
SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsTsanRt()) {
StaticRuntimes.push_back("tsan");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("tsan_cxx");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsUbsanRt()) {
if (SanArgs.requiresMinimalRuntime()) {
StaticRuntimes.push_back("ubsan_minimal");
} else {
@ -1413,24 +1412,24 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
if (SanArgs.needsSafeStackRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsSafeStackRt()) {
NonWholeStaticRuntimes.push_back("safestack");
RequiredSymbols.push_back("__safestack_init");
}
if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt() && SanArgs.linkRuntimes())) {
if (SanArgs.needsCfiRt() && SanArgs.linkRuntimes())
if (!(SanArgs.needsSharedRt() && SanArgs.needsUbsanRt())) {
if (SanArgs.needsCfiRt())
StaticRuntimes.push_back("cfi");
if (SanArgs.needsCfiDiagRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsCfiDiagRt()) {
StaticRuntimes.push_back("cfi_diag");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("ubsan_standalone_cxx");
}
}
if (SanArgs.needsStatsRt() && SanArgs.linkRuntimes()) {
if (SanArgs.needsStatsRt()) {
NonWholeStaticRuntimes.push_back("stats");
RequiredSymbols.push_back("__sanitizer_stats_register");
}
if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt() && SanArgs.linkRuntimes()) {
if (!SanArgs.needsSharedRt() && SanArgs.needsScudoRt()) {
StaticRuntimes.push_back("scudo_standalone");
if (SanArgs.linkCXXRuntimes())
StaticRuntimes.push_back("scudo_standalone_cxx");
@ -1441,13 +1440,15 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
// C runtime, etc). Returns true if sanitizer system deps need to be linked in.
bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes,
NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols;
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
if (SanArgs.linkRuntimes()) {
collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes,
NonWholeStaticRuntimes, HelperStaticRuntimes,
RequiredSymbols);
}
const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
// Inject libfuzzer dependencies.
if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() &&
!Args.hasArg(options::OPT_shared)) {

View file

@ -30,6 +30,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/TargetParser/TargetParser.h"
#include <system_error>
@ -1715,6 +1716,129 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
Result.Multilibs = CSKYMultilibs;
}
/// Extend the multi-lib re-use selection mechanism for RISC-V.
/// This function will try to re-use multi-lib if they are compatible.
/// Definition of compatible:
/// - ABI must be the same.
/// - multi-lib is a subset of current arch, e.g. multi-lib=march=rv32im
/// is a subset of march=rv32imc.
/// - march that contains atomic extension can't reuse multi-lib that
/// doesn't have atomic, vice versa. e.g. multi-lib=march=rv32im and
/// march=rv32ima are not compatible, because software and hardware
/// atomic operation can't work together correctly.
static bool
selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
const Multilib::flags_list &Flags,
llvm::SmallVectorImpl<Multilib> &SelectedMultilibs) {
// Try to find the perfect matching multi-lib first.
if (RISCVMultilibSet.select(Flags, SelectedMultilibs))
return true;
Multilib::flags_list NewFlags;
std::vector<MultilibBuilder> NewMultilibs;
llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> ParseResult =
llvm::RISCVISAInfo::parseArchString(
Arch, /*EnableExperimentalExtension=*/true,
/*ExperimentalExtensionVersionCheck=*/false);
if (!ParseResult) {
// Ignore any error here, we assume it will be handled in another place.
consumeError(ParseResult.takeError());
return false;
}
auto &ISAInfo = *ParseResult;
addMultilibFlag(ISAInfo->getXLen() == 32, "-m32", NewFlags);
addMultilibFlag(ISAInfo->getXLen() == 64, "-m64", NewFlags);
// Collect all flags except march=*
for (StringRef Flag : Flags) {
if (Flag.starts_with("!march=") || Flag.starts_with("-march="))
continue;
NewFlags.push_back(Flag.str());
}
llvm::StringSet<> AllArchExts;
// Reconstruct multi-lib list, and break march option into separated
// extension. e.g. march=rv32im -> +i +m
for (const auto &M : RISCVMultilibSet) {
bool Skip = false;
MultilibBuilder NewMultilib =
MultilibBuilder(M.gccSuffix(), M.osSuffix(), M.includeSuffix());
for (StringRef Flag : M.flags()) {
// Add back all flags except -march.
if (!Flag.consume_front("-march=")) {
NewMultilib.flag(Flag);
continue;
}
// Break down -march into individual extension.
llvm::Expected<std::unique_ptr<llvm::RISCVISAInfo>> MLConfigParseResult =
llvm::RISCVISAInfo::parseArchString(
Flag, /*EnableExperimentalExtension=*/true,
/*ExperimentalExtensionVersionCheck=*/false);
if (!MLConfigParseResult) {
// Ignore any error here, we assume it will handled in another place.
llvm::consumeError(MLConfigParseResult.takeError());
// We might get a parsing error if rv32e in the list, we could just skip
// that and process the rest of multi-lib configs.
Skip = true;
continue;
}
auto &MLConfigISAInfo = *MLConfigParseResult;
const llvm::RISCVISAInfo::OrderedExtensionMap &MLConfigArchExts =
MLConfigISAInfo->getExtensions();
for (auto MLConfigArchExt : MLConfigArchExts) {
auto ExtName = MLConfigArchExt.first;
NewMultilib.flag(Twine("-", ExtName).str());
if (AllArchExts.insert(ExtName).second) {
addMultilibFlag(ISAInfo->hasExtension(ExtName),
Twine("-", ExtName).str(), NewFlags);
}
}
// Check the XLEN explicitly.
if (MLConfigISAInfo->getXLen() == 32) {
NewMultilib.flag("-m32");
NewMultilib.flag("-m64", /*Disallow*/ true);
} else {
NewMultilib.flag("-m32", /*Disallow*/ true);
NewMultilib.flag("-m64");
}
// Atomic extension must be explicitly checked, soft and hard atomic
// operation never co-work correctly.
if (!MLConfigISAInfo->hasExtension("a"))
NewMultilib.flag("-a", /*Disallow*/ true);
}
if (Skip)
continue;
NewMultilibs.emplace_back(NewMultilib);
}
// Build an internal used only multi-lib list, used for checking any
// compatible multi-lib.
MultilibSet NewRISCVMultilibs =
MultilibSetBuilder().Either(NewMultilibs).makeMultilibSet();
if (NewRISCVMultilibs.select(NewFlags, SelectedMultilibs))
for (const Multilib &NewSelectedM : SelectedMultilibs)
for (const auto &M : RISCVMultilibSet)
// Look up the corresponding multi-lib entry in original multi-lib set.
if (M.gccSuffix() == NewSelectedM.gccSuffix())
return true;
return false;
}
static void findRISCVBareMetalMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
@ -1766,7 +1890,8 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
}
}
if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
if (selectRISCVMultilib(RISCVMultilibs, MArch, Flags,
Result.SelectedMultilibs))
Result.Multilibs = RISCVMultilibs;
}

View file

@ -583,17 +583,15 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
}
// If the return type spans multiple lines, wrap before the function name.
if (((Current.is(TT_FunctionDeclarationName) &&
!State.Line->ReturnTypeWrapped &&
// Don't break before a C# function when no break after return type.
(!Style.isCSharp() ||
Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) &&
// Don't always break between a JavaScript `function` and the function
// name.
!Style.isJavaScript()) ||
(Current.is(tok::kw_operator) && Previous.isNot(tok::coloncolon))) &&
Previous.isNot(tok::kw_template) && CurrentState.BreakBeforeParameter) {
if (Current.is(TT_FunctionDeclarationName) &&
!State.Line->ReturnTypeWrapped &&
// Don't break before a C# function when no break after return type.
(!Style.isCSharp() ||
Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) &&
// Don't always break between a JavaScript `function` and the function
// name.
!Style.isJavaScript() && Previous.isNot(tok::kw_template) &&
CurrentState.BreakBeforeParameter) {
return true;
}

View file

@ -1315,7 +1315,6 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
Expanded.BraceWrapping.AfterStruct = true;
Expanded.BraceWrapping.AfterUnion = true;
Expanded.BraceWrapping.AfterExternBlock = true;
Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
Expanded.BraceWrapping.SplitEmptyFunction = true;
Expanded.BraceWrapping.SplitEmptyRecord = false;
break;
@ -1335,7 +1334,6 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
Expanded.BraceWrapping.AfterStruct = true;
Expanded.BraceWrapping.AfterUnion = true;
Expanded.BraceWrapping.AfterExternBlock = true;
Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
Expanded.BraceWrapping.BeforeCatch = true;
Expanded.BraceWrapping.BeforeElse = true;
Expanded.BraceWrapping.BeforeLambdaBody = true;
@ -1350,7 +1348,6 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
Expanded.BraceWrapping.AfterObjCDeclaration = true;
Expanded.BraceWrapping.AfterStruct = true;
Expanded.BraceWrapping.AfterExternBlock = true;
Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
Expanded.BraceWrapping.BeforeCatch = true;
Expanded.BraceWrapping.BeforeElse = true;
Expanded.BraceWrapping.BeforeLambdaBody = true;
@ -1375,7 +1372,6 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
/*SplitEmptyFunction=*/true,
/*SplitEmptyRecord=*/true,
/*SplitEmptyNamespace=*/true};
Expanded.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
@ -1702,6 +1698,9 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
/*BasedOnStyle=*/"google",
},
};
GoogleStyle.AttributeMacros.push_back("GUARDED_BY");
GoogleStyle.AttributeMacros.push_back("ABSL_GUARDED_BY");
GoogleStyle.SpacesBeforeTrailingComments = 2;
GoogleStyle.Standard = FormatStyle::LS_Auto;
@ -1909,7 +1908,6 @@ FormatStyle getMicrosoftStyle(FormatStyle::LanguageKind Language) {
Style.BraceWrapping.AfterObjCDeclaration = true;
Style.BraceWrapping.AfterStruct = true;
Style.BraceWrapping.AfterExternBlock = true;
Style.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock;
Style.BraceWrapping.BeforeCatch = true;
Style.BraceWrapping.BeforeElse = true;
Style.BraceWrapping.BeforeWhile = false;

View file

@ -0,0 +1,122 @@
//===--- MatchFilePath.cpp - Match file path with pattern -------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements the functionality of matching a file path name to
/// a pattern, similar to the POSIX fnmatch() function.
///
//===----------------------------------------------------------------------===//
#include "MatchFilePath.h"
using namespace llvm;
namespace clang {
namespace format {
// Check whether `FilePath` matches `Pattern` based on POSIX (1003.1-2008)
// 2.13.1, 2.13.2, and Rule 1 of 2.13.3.
bool matchFilePath(StringRef Pattern, StringRef FilePath) {
assert(!Pattern.empty());
assert(!FilePath.empty());
// No match if `Pattern` ends with a non-meta character not equal to the last
// character of `FilePath`.
if (const auto C = Pattern.back(); !strchr("?*]", C) && C != FilePath.back())
return false;
constexpr auto Separator = '/';
const auto EOP = Pattern.size(); // End of `Pattern`.
const auto End = FilePath.size(); // End of `FilePath`.
unsigned I = 0; // Index to `Pattern`.
for (unsigned J = 0; J < End; ++J) {
if (I == EOP)
return false;
switch (const auto F = FilePath[J]; Pattern[I]) {
case '\\':
if (++I == EOP || F != Pattern[I])
return false;
break;
case '?':
if (F == Separator)
return false;
break;
case '*': {
while (++I < EOP && Pattern[I] == '*') { // Skip consecutive stars.
}
const auto K = FilePath.find(Separator, J); // Index of next `Separator`.
const bool NoMoreSeparatorsInFilePath = K == StringRef::npos;
if (I == EOP) // `Pattern` ends with a star.
return NoMoreSeparatorsInFilePath;
// `Pattern` ends with a lone backslash.
if (Pattern[I] == '\\' && ++I == EOP)
return false;
// The star is followed by a (possibly escaped) `Separator`.
if (Pattern[I] == Separator) {
if (NoMoreSeparatorsInFilePath)
return false;
J = K; // Skip to next `Separator` in `FilePath`.
break;
}
// Recurse.
for (auto Pat = Pattern.substr(I); J < End && FilePath[J] != Separator;
++J) {
if (matchFilePath(Pat, FilePath.substr(J)))
return true;
}
return false;
}
case '[':
// Skip e.g. `[!]`.
if (I + 3 < EOP || (I + 3 == EOP && Pattern[I + 1] != '!')) {
// Skip unpaired `[`, brackets containing slashes, and `[]`.
if (const auto K = Pattern.find_first_of("]/", I + 1);
K != StringRef::npos && Pattern[K] == ']' && K > I + 1) {
if (F == Separator)
return false;
++I; // After the `[`.
bool Negated = false;
if (Pattern[I] == '!') {
Negated = true;
++I; // After the `!`.
}
bool Match = false;
do {
if (I + 2 < K && Pattern[I + 1] == '-') {
Match = Pattern[I] <= F && F <= Pattern[I + 2];
I += 3; // After the range, e.g. `A-Z`.
} else {
Match = F == Pattern[I++];
}
} while (!Match && I < K);
if (Negated ? Match : !Match)
return false;
I = K + 1; // After the `]`.
continue;
}
}
[[fallthrough]]; // Match `[` literally.
default:
if (F != Pattern[I])
return false;
}
++I;
}
// Match trailing stars with null strings.
while (I < EOP && Pattern[I] == '*')
++I;
return I == EOP;
}
} // namespace format
} // namespace clang

View file

@ -0,0 +1,22 @@
//===--- MatchFilePath.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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_LIB_FORMAT_MATCHFILEPATH_H
#define LLVM_CLANG_LIB_FORMAT_MATCHFILEPATH_H
#include "llvm/ADT/StringRef.h"
namespace clang {
namespace format {
bool matchFilePath(llvm::StringRef Pattern, llvm::StringRef FilePath);
} // end namespace format
} // end namespace clang
#endif

View file

@ -3403,7 +3403,8 @@ static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current,
continue;
}
if (Tok->is(tok::kw_const) || Tok->isSimpleTypeSpecifier() ||
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis)) {
Tok->isOneOf(TT_PointerOrReference, TT_StartOfName, tok::ellipsis,
TT_TypeName)) {
return true;
}
if (Tok->isOneOf(tok::l_brace, TT_ObjCMethodExpr) || Tok->Tok.isLiteral())

View file

@ -1650,8 +1650,10 @@ void UnwrappedLineParser::parseStructuralElement(
return;
}
// In Verilog labels can be any expression, so we don't do them here.
if (!Style.isVerilog() && Tokens->peekNextToken()->is(tok::colon) &&
!Line->MustBeDeclaration) {
// JS doesn't have macros, and within classes colons indicate fields, not
// labels.
if (!Style.isJavaScript() && !Style.isVerilog() &&
Tokens->peekNextToken()->is(tok::colon) && !Line->MustBeDeclaration) {
nextToken();
Line->Tokens.begin()->Tok->MustBreakBefore = true;
FormatTok->setFinalizedType(TT_GotoLabelColon);

View file

@ -0,0 +1,160 @@
/*===---- adcintrin.h - ADC 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
*
*===-----------------------------------------------------------------------===
*/
#ifndef __ADCINTRIN_H
#define __ADCINTRIN_H
#if !defined(__i386__) && !defined(__x86_64__)
#error "This header is only meant to be used on x86 and x64 architecture"
#endif
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
/* Use C++ inline semantics in C++, GNU inline for C mode. */
#if defined(__cplusplus)
#define __INLINE __inline
#else
#define __INLINE static __inline
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/// Adds unsigned 32-bit integers \a __x and \a __y, plus 0 or 1 as indicated
/// by the carry flag \a __cf. Stores the unsigned 32-bit sum in the memory
/// at \a __p, and returns the 8-bit carry-out (carry flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store32(__p, __x + __y + temp)
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// A 32-bit unsigned addend.
/// \param __y
/// A 32-bit unsigned addend.
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS _addcarry_u32(unsigned char __cf,
unsigned int __x,
unsigned int __y,
unsigned int *__p) {
return __builtin_ia32_addcarryx_u32(__cf, __x, __y, __p);
}
/// Adds unsigned 32-bit integer \a __y to 0 or 1 as indicated by the carry
/// flag \a __cf, and subtracts the result from unsigned 32-bit integer
/// \a __x. Stores the unsigned 32-bit difference in the memory at \a __p,
/// and returns the 8-bit carry-out (carry or overflow flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store32(__p, __x - (__y + temp))
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c SBB instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// The 32-bit unsigned minuend.
/// \param __y
/// The 32-bit unsigned subtrahend.
/// \param __p
/// Pointer to memory for storing the difference.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS _subborrow_u32(unsigned char __cf,
unsigned int __x,
unsigned int __y,
unsigned int *__p) {
return __builtin_ia32_subborrow_u32(__cf, __x, __y, __p);
}
#ifdef __x86_64__
/// Adds unsigned 64-bit integers \a __x and \a __y, plus 0 or 1 as indicated
/// by the carry flag \a __cf. Stores the unsigned 64-bit sum in the memory
/// at \a __p, and returns the 8-bit carry-out (carry flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store64(__p, __x + __y + temp)
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// A 64-bit unsigned addend.
/// \param __y
/// A 64-bit unsigned addend.
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS
_addcarry_u64(unsigned char __cf, unsigned long long __x,
unsigned long long __y, unsigned long long *__p) {
return __builtin_ia32_addcarryx_u64(__cf, __x, __y, __p);
}
/// Adds unsigned 64-bit integer \a __y to 0 or 1 as indicated by the carry
/// flag \a __cf, and subtracts the result from unsigned 64-bit integer
/// \a __x. Stores the unsigned 64-bit difference in the memory at \a __p,
/// and returns the 8-bit carry-out (carry or overflow flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store64(__p, __x - (__y + temp))
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// The 64-bit unsigned minuend.
/// \param __y
/// The 64-bit unsigned subtrahend.
/// \param __p
/// Pointer to memory for storing the difference.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS
_subborrow_u64(unsigned char __cf, unsigned long long __x,
unsigned long long __y, unsigned long long *__p) {
return __builtin_ia32_subborrow_u64(__cf, __x, __y, __p);
}
#endif
#if defined(__cplusplus)
}
#endif
#undef __INLINE
#undef __DEFAULT_FN_ATTRS
#endif /* __ADCINTRIN_H */

View file

@ -15,7 +15,8 @@
#define __ADXINTRIN_H
/* Define the default attributes for the functions in this file. */
#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__))
#define __DEFAULT_FN_ATTRS \
__attribute__((__always_inline__, __nodebug__, __target__("adx")))
/* Use C++ inline semantics in C++, GNU inline for C mode. */
#if defined(__cplusplus)
@ -53,10 +54,10 @@ extern "C" {
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char
__attribute__((__always_inline__, __nodebug__, __target__("adx")))
_addcarryx_u32(unsigned char __cf, unsigned int __x, unsigned int __y,
unsigned int *__p) {
__INLINE unsigned char __DEFAULT_FN_ATTRS _addcarryx_u32(unsigned char __cf,
unsigned int __x,
unsigned int __y,
unsigned int *__p) {
return __builtin_ia32_addcarryx_u32(__cf, __x, __y, __p);
}
@ -84,137 +85,10 @@ __INLINE unsigned char
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char
__attribute__((__always_inline__, __nodebug__, __target__("adx")))
_addcarryx_u64(unsigned char __cf, unsigned long long __x,
unsigned long long __y, unsigned long long *__p) {
return __builtin_ia32_addcarryx_u64(__cf, __x, __y, __p);
}
#endif
/* Intrinsics that are also available if __ADX__ is undefined. */
/// Adds unsigned 32-bit integers \a __x and \a __y, plus 0 or 1 as indicated
/// by the carry flag \a __cf. Stores the unsigned 32-bit sum in the memory
/// at \a __p, and returns the 8-bit carry-out (carry flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store32(__p, __x + __y + temp)
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// A 32-bit unsigned addend.
/// \param __y
/// A 32-bit unsigned addend.
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS _addcarry_u32(unsigned char __cf,
unsigned int __x,
unsigned int __y,
unsigned int *__p) {
return __builtin_ia32_addcarryx_u32(__cf, __x, __y, __p);
}
#ifdef __x86_64__
/// Adds unsigned 64-bit integers \a __x and \a __y, plus 0 or 1 as indicated
/// by the carry flag \a __cf. Stores the unsigned 64-bit sum in the memory
/// at \a __p, and returns the 8-bit carry-out (carry flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store64(__p, __x + __y + temp)
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// A 64-bit unsigned addend.
/// \param __y
/// A 64-bit unsigned addend.
/// \param __p
/// Pointer to memory for storing the sum.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS
_addcarry_u64(unsigned char __cf, unsigned long long __x,
unsigned long long __y, unsigned long long *__p) {
return __builtin_ia32_addcarryx_u64(__cf, __x, __y, __p);
}
#endif
/// Adds unsigned 32-bit integer \a __y to 0 or 1 as indicated by the carry
/// flag \a __cf, and subtracts the result from unsigned 32-bit integer
/// \a __x. Stores the unsigned 32-bit difference in the memory at \a __p,
/// and returns the 8-bit carry-out (carry or overflow flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store32(__p, __x - (__y + temp))
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c SBB instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// The 32-bit unsigned minuend.
/// \param __y
/// The 32-bit unsigned subtrahend.
/// \param __p
/// Pointer to memory for storing the difference.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS _subborrow_u32(unsigned char __cf,
unsigned int __x,
unsigned int __y,
unsigned int *__p) {
return __builtin_ia32_subborrow_u32(__cf, __x, __y, __p);
}
#ifdef __x86_64__
/// Adds unsigned 64-bit integer \a __y to 0 or 1 as indicated by the carry
/// flag \a __cf, and subtracts the result from unsigned 64-bit integer
/// \a __x. Stores the unsigned 64-bit difference in the memory at \a __p,
/// and returns the 8-bit carry-out (carry or overflow flag).
///
/// \code{.operation}
/// temp := (__cf == 0) ? 0 : 1
/// Store64(__p, __x - (__y + temp))
/// result := CF
/// \endcode
///
/// \headerfile <immintrin.h>
///
/// This intrinsic corresponds to the \c ADC instruction.
///
/// \param __cf
/// The 8-bit unsigned carry flag; any non-zero value indicates carry.
/// \param __x
/// The 64-bit unsigned minuend.
/// \param __y
/// The 64-bit unsigned subtrahend.
/// \param __p
/// Pointer to memory for storing the difference.
/// \returns The 8-bit unsigned carry-out value.
__INLINE unsigned char __DEFAULT_FN_ATTRS
_subborrow_u64(unsigned char __cf, unsigned long long __x,
_addcarryx_u64(unsigned char __cf, unsigned long long __x,
unsigned long long __y, unsigned long long *__p) {
return __builtin_ia32_subborrow_u64(__cf, __x, __y, __p);
return __builtin_ia32_addcarryx_u64(__cf, __x, __y, __p);
}
#endif
@ -222,6 +96,7 @@ _subborrow_u64(unsigned char __cf, unsigned long long __x,
}
#endif
#undef __INLINE
#undef __DEFAULT_FN_ATTRS
#endif /* __ADXINTRIN_H */

View file

@ -580,9 +580,13 @@ _storebe_i64(void * __P, long long __D) {
#include <cetintrin.h>
#endif
/* Some intrinsics inside adxintrin.h are available only on processors with ADX,
* whereas others are also available at all times. */
/* Intrinsics inside adcintrin.h are available at all times. */
#include <adcintrin.h>
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
defined(__ADX__)
#include <adxintrin.h>
#endif
#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
defined(__RDSEED__)

View file

@ -34,7 +34,7 @@ __riscv_ctz_32(uint32_t __x) {
static __inline__ unsigned __attribute__((__always_inline__, __nodebug__))
__riscv_cpop_32(uint32_t __x) {
return __builtin_riscv_cpop_32(__x);
return __builtin_popcount(__x);
}
#if __riscv_xlen == 64
@ -55,7 +55,7 @@ __riscv_ctz_64(uint64_t __x) {
static __inline__ unsigned __attribute__((__always_inline__, __nodebug__))
__riscv_cpop_64(uint64_t __x) {
return __builtin_riscv_cpop_64(__x);
return __builtin_popcountll(__x);
}
#endif
#endif // defined(__riscv_zbb)
@ -120,7 +120,23 @@ __riscv_zip_32(uint32_t __x) {
#endif
#endif // defined(__riscv_zbkb)
#if defined(__riscv_zbkc)
#if defined(__riscv_zbc)
#if __riscv_xlen == 32
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
__riscv_clmulr_32(uint32_t __x, uint32_t __y) {
return __builtin_riscv_clmulr_32(__x, __y);
}
#endif
#if __riscv_xlen == 64
static __inline__ uint64_t __attribute__((__always_inline__, __nodebug__))
__riscv_clmulr_64(uint64_t __x, uint64_t __y) {
return __builtin_riscv_clmulr_64(__x, __y);
}
#endif
#endif // defined(__riscv_zbc)
#if defined(__riscv_zbkc) || defined(__riscv_zbc)
static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__))
__riscv_clmul_32(uint32_t __x, uint32_t __y) {
return __builtin_riscv_clmul_32(__x, __y);
@ -144,7 +160,7 @@ __riscv_clmulh_64(uint64_t __x, uint64_t __y) {
return __builtin_riscv_clmulh_64(__x, __y);
}
#endif
#endif // defined(__riscv_zbkc)
#endif // defined(__riscv_zbkc) || defined(__riscv_zbc)
#if defined(__riscv_zbkx)
#if __riscv_xlen == 32

View file

@ -12,6 +12,7 @@
#include "clang/Interpreter/CodeCompletion.h"
#include "clang/AST/ASTImporter.h"
#include "clang/AST/DeclLookups.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/ExternalASTSource.h"
#include "clang/Basic/IdentifierTable.h"
@ -23,6 +24,8 @@
#include "clang/Sema/CodeCompleteConsumer.h"
#include "clang/Sema/CodeCompleteOptions.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "REPLCC"
namespace clang {
@ -39,11 +42,15 @@ clang::CodeCompleteOptions getClangCompleteOpts() {
class ReplCompletionConsumer : public CodeCompleteConsumer {
public:
ReplCompletionConsumer(std::vector<std::string> &Results)
ReplCompletionConsumer(std::vector<std::string> &Results,
ReplCodeCompleter &CC)
: CodeCompleteConsumer(getClangCompleteOpts()),
CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
CCTUInfo(CCAllocator), Results(Results){};
CCTUInfo(CCAllocator), Results(Results), CC(CC) {}
// The entry of handling code completion. When the function is called, we
// create a `Context`-based handler (see classes defined below) to handle each
// completion result.
void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
CodeCompletionResult *InResults,
unsigned NumResults) final;
@ -56,26 +63,147 @@ private:
std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
CodeCompletionTUInfo CCTUInfo;
std::vector<std::string> &Results;
ReplCodeCompleter &CC;
};
/// The class CompletionContextHandler contains four interfaces, each of
/// which handles one type of completion result.
/// Its derived classes are used to create concrete handlers based on
/// \c CodeCompletionContext.
class CompletionContextHandler {
protected:
CodeCompletionContext CCC;
std::vector<std::string> &Results;
private:
Sema &S;
public:
CompletionContextHandler(Sema &S, CodeCompletionContext CCC,
std::vector<std::string> &Results)
: CCC(CCC), Results(Results), S(S) {}
virtual ~CompletionContextHandler() = default;
/// Converts a Declaration completion result to a completion string, and then
/// stores it in Results.
virtual void handleDeclaration(const CodeCompletionResult &Result) {
auto PreferredType = CCC.getPreferredType();
if (PreferredType.isNull()) {
Results.push_back(Result.Declaration->getName().str());
return;
}
if (auto *VD = dyn_cast<VarDecl>(Result.Declaration)) {
auto ArgumentType = VD->getType();
if (PreferredType->isReferenceType()) {
QualType RT = PreferredType->castAs<ReferenceType>()->getPointeeType();
Sema::ReferenceConversions RefConv;
Sema::ReferenceCompareResult RefRelationship =
S.CompareReferenceRelationship(SourceLocation(), RT, ArgumentType,
&RefConv);
switch (RefRelationship) {
case Sema::Ref_Compatible:
case Sema::Ref_Related:
Results.push_back(VD->getName().str());
break;
case Sema::Ref_Incompatible:
break;
}
} else if (S.Context.hasSameType(ArgumentType, PreferredType)) {
Results.push_back(VD->getName().str());
}
}
}
/// Converts a Keyword completion result to a completion string, and then
/// stores it in Results.
virtual void handleKeyword(const CodeCompletionResult &Result) {
auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
// Add keyword to the completion results only if we are in a type-aware
// situation.
if (!CCC.getBaseType().isNull() || !CCC.getPreferredType().isNull())
return;
if (StringRef(Result.Keyword).starts_with(Prefix))
Results.push_back(Result.Keyword);
}
/// Converts a Pattern completion result to a completion string, and then
/// stores it in Results.
virtual void handlePattern(const CodeCompletionResult &Result) {}
/// Converts a Macro completion result to a completion string, and then stores
/// it in Results.
virtual void handleMacro(const CodeCompletionResult &Result) {}
};
class DotMemberAccessHandler : public CompletionContextHandler {
public:
DotMemberAccessHandler(Sema &S, CodeCompletionContext CCC,
std::vector<std::string> &Results)
: CompletionContextHandler(S, CCC, Results) {}
void handleDeclaration(const CodeCompletionResult &Result) override {
auto *ID = Result.Declaration->getIdentifier();
if (!ID)
return;
if (!isa<CXXMethodDecl>(Result.Declaration))
return;
const auto *Fun = cast<CXXMethodDecl>(Result.Declaration);
if (Fun->getParent()->getCanonicalDecl() ==
CCC.getBaseType()->getAsCXXRecordDecl()->getCanonicalDecl()) {
LLVM_DEBUG(llvm::dbgs() << "[In HandleCodeCompleteDOT] Name : "
<< ID->getName() << "\n");
Results.push_back(ID->getName().str());
}
}
void handleKeyword(const CodeCompletionResult &Result) override {}
};
void ReplCompletionConsumer::ProcessCodeCompleteResults(
class Sema &S, CodeCompletionContext Context,
CodeCompletionResult *InResults, unsigned NumResults) {
for (unsigned I = 0; I < NumResults; ++I) {
auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
CC.Prefix = Prefix;
std::unique_ptr<CompletionContextHandler> CCH;
// initialize fine-grained code completion handler based on the code
// completion context.
switch (Context.getKind()) {
case CodeCompletionContext::CCC_DotMemberAccess:
CCH.reset(new DotMemberAccessHandler(S, Context, this->Results));
break;
default:
CCH.reset(new CompletionContextHandler(S, Context, this->Results));
};
for (unsigned I = 0; I < NumResults; I++) {
auto &Result = InResults[I];
switch (Result.Kind) {
case CodeCompletionResult::RK_Declaration:
if (auto *ID = Result.Declaration->getIdentifier()) {
Results.push_back(ID->getName().str());
if (Result.Hidden) {
break;
}
if (!Result.Declaration->getDeclName().isIdentifier() ||
!Result.Declaration->getName().starts_with(Prefix)) {
break;
}
CCH->handleDeclaration(Result);
break;
case CodeCompletionResult::RK_Keyword:
Results.push_back(Result.Keyword);
CCH->handleKeyword(Result);
break;
default:
case CodeCompletionResult::RK_Macro:
CCH->handleMacro(Result);
break;
case CodeCompletionResult::RK_Pattern:
CCH->handlePattern(Result);
break;
}
}
std::sort(Results.begin(), Results.end());
}
class IncrementalSyntaxOnlyAction : public SyntaxOnlyAction {
@ -118,6 +246,16 @@ void IncrementalSyntaxOnlyAction::ExecuteAction() {
CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(
true);
// Load all external decls into current context. Under the hood, it calls
// ExternalSource::completeVisibleDeclsMap, which make all decls on the redecl
// chain visible.
//
// This is crucial to code completion on dot members, since a bound variable
// before "." would be otherwise treated out-of-scope.
//
// clang-repl> Foo f1;
// clang-repl> f1.<tab>
CI.getASTContext().getTranslationUnitDecl()->lookups();
SyntaxOnlyAction::ExecuteAction();
}
@ -134,6 +272,7 @@ ExternalSource::ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
bool ExternalSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
DeclarationName Name) {
IdentifierTable &ParentIdTable = ParentASTCtxt.Idents;
auto ParentDeclName =
@ -159,29 +298,67 @@ void ExternalSource::completeVisibleDeclsMap(
for (auto *DeclCtxt = ParentTUDeclCtxt; DeclCtxt != nullptr;
DeclCtxt = DeclCtxt->getPreviousDecl()) {
for (auto &IDeclContext : DeclCtxt->decls()) {
if (NamedDecl *Decl = llvm::dyn_cast<NamedDecl>(IDeclContext)) {
if (auto DeclOrErr = Importer->Import(Decl)) {
if (NamedDecl *importedNamedDecl =
llvm::dyn_cast<NamedDecl>(*DeclOrErr)) {
SetExternalVisibleDeclsForName(ChildDeclContext,
importedNamedDecl->getDeclName(),
importedNamedDecl);
}
if (!llvm::isa<NamedDecl>(IDeclContext))
continue;
} else {
llvm::consumeError(DeclOrErr.takeError());
}
NamedDecl *Decl = llvm::cast<NamedDecl>(IDeclContext);
auto DeclOrErr = Importer->Import(Decl);
if (!DeclOrErr) {
// if an error happens, it usually means the decl has already been
// imported or the decl is a result of a failed import. But in our
// case, every import is fresh each time code completion is
// triggered. So Import usually doesn't fail. If it does, it just means
// the related decl can't be used in code completion and we can safely
// drop it.
llvm::consumeError(DeclOrErr.takeError());
continue;
}
if (!llvm::isa<NamedDecl>(*DeclOrErr))
continue;
NamedDecl *importedNamedDecl = llvm::cast<NamedDecl>(*DeclOrErr);
SetExternalVisibleDeclsForName(ChildDeclContext,
importedNamedDecl->getDeclName(),
importedNamedDecl);
if (!llvm::isa<CXXRecordDecl>(importedNamedDecl))
continue;
auto *Record = llvm::cast<CXXRecordDecl>(importedNamedDecl);
if (auto Err = Importer->ImportDefinition(Decl)) {
// the same as above
consumeError(std::move(Err));
continue;
}
Record->setHasLoadedFieldsFromExternalStorage(true);
LLVM_DEBUG(llvm::dbgs()
<< "\nCXXRecrod : " << Record->getName() << " size(methods): "
<< std::distance(Record->method_begin(), Record->method_end())
<< " has def?: " << Record->hasDefinition()
<< " # (methods): "
<< std::distance(Record->getDefinition()->method_begin(),
Record->getDefinition()->method_end())
<< "\n");
for (auto *Meth : Record->methods())
SetExternalVisibleDeclsForName(ChildDeclContext, Meth->getDeclName(),
Meth);
}
ChildDeclContext->setHasExternalLexicalStorage(false);
}
}
void codeComplete(CompilerInstance *InterpCI, llvm::StringRef Content,
unsigned Line, unsigned Col, const CompilerInstance *ParentCI,
std::vector<std::string> &CCResults) {
void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI,
llvm::StringRef Content, unsigned Line,
unsigned Col,
const CompilerInstance *ParentCI,
std::vector<std::string> &CCResults) {
auto DiagOpts = DiagnosticOptions();
auto consumer = ReplCompletionConsumer(CCResults);
auto consumer = ReplCompletionConsumer(CCResults, *this);
auto diag = InterpCI->getDiagnosticsPtr();
std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(

View file

@ -319,6 +319,10 @@ const CompilerInstance *Interpreter::getCompilerInstance() const {
return IncrParser->getCI();
}
CompilerInstance *Interpreter::getCompilerInstance() {
return IncrParser->getCI();
}
llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
if (!IncrExecutor) {
if (auto Err = CreateExecutor())

View file

@ -1858,11 +1858,18 @@ static void diagnoseAutoModuleImport(
// path to the file, build a properly-cased replacement in the vector,
// and return true if the replacement should be suggested.
static bool trySimplifyPath(SmallVectorImpl<StringRef> &Components,
StringRef RealPathName) {
StringRef RealPathName,
llvm::sys::path::Style Separator) {
auto RealPathComponentIter = llvm::sys::path::rbegin(RealPathName);
auto RealPathComponentEnd = llvm::sys::path::rend(RealPathName);
int Cnt = 0;
bool SuggestReplacement = false;
auto IsSep = [Separator](StringRef Component) {
return Component.size() == 1 &&
llvm::sys::path::is_separator(Component[0], Separator);
};
// Below is a best-effort to handle ".." in paths. It is admittedly
// not 100% correct in the presence of symlinks.
for (auto &Component : llvm::reverse(Components)) {
@ -1872,10 +1879,11 @@ static bool trySimplifyPath(SmallVectorImpl<StringRef> &Components,
} else if (Cnt) {
--Cnt;
} else if (RealPathComponentIter != RealPathComponentEnd) {
if (Component != *RealPathComponentIter) {
// If these path components differ by more than just case, then we
// may be looking at symlinked paths. Bail on this diagnostic to avoid
// noisy false positives.
if (!IsSep(Component) && !IsSep(*RealPathComponentIter) &&
Component != *RealPathComponentIter) {
// If these non-separator path components differ by more than just case,
// then we may be looking at symlinked paths. Bail on this diagnostic to
// avoid noisy false positives.
SuggestReplacement =
RealPathComponentIter->equals_insensitive(Component);
if (!SuggestReplacement)
@ -2451,7 +2459,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
}
#endif
if (trySimplifyPath(Components, RealPathName)) {
if (trySimplifyPath(Components, RealPathName, BackslashStyle)) {
SmallString<128> Path;
Path.reserve(Name.size()+2);
Path.push_back(isAngled ? '<' : '"');
@ -2474,7 +2482,7 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
// got copied when the C: was processed and we want to skip that entry.
if (!(Component.size() == 1 && IsSep(Component[0])))
Path.append(Component);
else if (!Path.empty())
else if (Path.size() != 1)
continue;
// Append the separator(s) the user used, or the close quote

View file

@ -69,6 +69,29 @@ OpenACCDirectiveKindEx getOpenACCDirectiveKind(Token Tok) {
.Default(OpenACCDirectiveKindEx::Invalid);
}
// Translate single-token string representations to the OpenCC Clause Kind.
OpenACCClauseKind getOpenACCClauseKind(Token Tok) {
// auto is a keyword in some language modes, so make sure we parse it
// correctly.
if (Tok.is(tok::kw_auto))
return OpenACCClauseKind::Auto;
if (!Tok.is(tok::identifier))
return OpenACCClauseKind::Invalid;
return llvm::StringSwitch<OpenACCClauseKind>(
Tok.getIdentifierInfo()->getName())
.Case("auto", OpenACCClauseKind::Auto)
.Case("finalize", OpenACCClauseKind::Finalize)
.Case("if_present", OpenACCClauseKind::IfPresent)
.Case("independent", OpenACCClauseKind::Independent)
.Case("nohost", OpenACCClauseKind::NoHost)
.Case("seq", OpenACCClauseKind::Seq)
.Case("vector", OpenACCClauseKind::Vector)
.Case("worker", OpenACCClauseKind::Worker)
.Default(OpenACCClauseKind::Invalid);
}
// Since 'atomic' is effectively a compound directive, this will decode the
// second part of the directive.
OpenACCAtomicKind getOpenACCAtomicKind(Token Tok) {
@ -164,6 +187,10 @@ ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
return OpenACCDirectiveKind::Invalid;
}
// Consume the second name anyway, this way we can continue on without making
// this oddly look like a clause.
P.ConsumeAnyToken();
if (!isOpenACCDirectiveKind(OpenACCDirectiveKind::Data, SecondTok)) {
if (!SecondTok.is(tok::identifier))
P.Diag(SecondTok, diag::err_expected) << tok::identifier;
@ -174,8 +201,6 @@ ParseOpenACCEnterExitDataDirective(Parser &P, Token FirstTok,
return OpenACCDirectiveKind::Invalid;
}
P.ConsumeToken();
return ExtDirKind == OpenACCDirectiveKindEx::Enter
? OpenACCDirectiveKind::EnterData
: OpenACCDirectiveKind::ExitData;
@ -208,6 +233,10 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
// introspect on the spelling before then.
if (FirstTok.isNot(tok::identifier)) {
P.Diag(FirstTok, diag::err_acc_missing_directive);
if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
return OpenACCDirectiveKind::Invalid;
}
@ -262,12 +291,57 @@ OpenACCDirectiveKind ParseOpenACCDirectiveKind(Parser &P) {
return DirKind;
}
// The OpenACC Clause List is a comma or space-delimited list of clauses (see
// the comment on ParseOpenACCClauseList). The concept of a 'clause' doesn't
// really have its owner grammar and each individual one has its own definition.
// However, they all are named with a single-identifier (or auto!) token,
// followed in some cases by either braces or parens.
bool ParseOpenACCClause(Parser &P) {
if (!P.getCurToken().isOneOf(tok::identifier, tok::kw_auto))
return P.Diag(P.getCurToken(), diag::err_expected) << tok::identifier;
OpenACCClauseKind Kind = getOpenACCClauseKind(P.getCurToken());
if (Kind == OpenACCClauseKind::Invalid)
return P.Diag(P.getCurToken(), diag::err_acc_invalid_clause)
<< P.getCurToken().getIdentifierInfo();
// Consume the clause name.
P.ConsumeToken();
// FIXME: For future clauses, we need to handle parens/etc below.
return false;
}
// Skip until we see the end of pragma token, but don't consume it. This is us
// just giving up on the rest of the pragma so we can continue executing. We
// have to do this because 'SkipUntil' considers paren balancing, which isn't
// what we want.
void SkipUntilEndOfDirective(Parser &P) {
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.ConsumeAnyToken();
}
// OpenACC 3.3, section 1.7:
// To simplify the specification and convey appropriate constraint information,
// a pqr-list is a comma-separated list of pdr items. The one exception is a
// clause-list, which is a list of one or more clauses optionally separated by
// commas.
void ParseOpenACCClauseList(Parser &P) {
// FIXME: In the future, we'll start parsing the clauses here, but for now we
// haven't implemented that, so just emit the unimplemented diagnostic and
// fail reasonably.
if (P.getCurToken().isNot(tok::annot_pragma_openacc_end))
P.Diag(P.getCurToken(), diag::warn_pragma_acc_unimplemented_clause_parsing);
bool FirstClause = true;
while (P.getCurToken().isNot(tok::annot_pragma_openacc_end)) {
// Comma is optional in a clause-list.
if (!FirstClause && P.getCurToken().is(tok::comma))
P.ConsumeToken();
FirstClause = false;
// Recovering from a bad clause is really difficult, so we just give up on
// error.
if (ParseOpenACCClause(P)) {
SkipUntilEndOfDirective(P);
return;
}
}
}
} // namespace
@ -499,7 +573,9 @@ void Parser::ParseOpenACCDirective() {
ParseOpenACCClauseList(*this);
Diag(getCurToken(), diag::warn_pragma_acc_unimplemented);
SkipUntil(tok::annot_pragma_openacc_end);
assert(Tok.is(tok::annot_pragma_openacc_end) &&
"Didn't parse all OpenACC Clauses");
ConsumeAnnotationToken();
}
// Parse OpenACC directive on a declaration.

View file

@ -3156,7 +3156,6 @@ static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
const FunctionDecl *FD,
ArmStreamingType BuiltinType) {
ArmStreamingType FnType = getArmStreamingFnType(FD);
if (FnType == ArmStreaming && BuiltinType == ArmNonStreaming) {
S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin)
<< TheCall->getSourceRange() << "streaming";
@ -3168,9 +3167,77 @@ static void checkArmStreamingBuiltin(Sema &S, CallExpr *TheCall,
<< TheCall->getSourceRange() << "streaming compatible";
return;
}
if (FnType == ArmNonStreaming && BuiltinType == ArmStreaming) {
S.Diag(TheCall->getBeginLoc(), diag::warn_attribute_arm_sm_incompat_builtin)
<< TheCall->getSourceRange() << "non-streaming";
}
}
static bool hasSMEZAState(const FunctionDecl *FD) {
if (FD->hasAttr<ArmNewZAAttr>())
return true;
if (const auto *T = FD->getType()->getAs<FunctionProtoType>())
if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask)
return true;
return false;
}
static bool hasSMEZAState(unsigned BuiltinID) {
switch (BuiltinID) {
default:
return false;
#define GET_SME_BUILTIN_HAS_ZA_STATE
#include "clang/Basic/arm_sme_builtins_za_state.inc"
#undef GET_SME_BUILTIN_HAS_ZA_STATE
}
}
bool Sema::CheckSMEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (const FunctionDecl *FD = getCurFunctionDecl()) {
std::optional<ArmStreamingType> BuiltinType;
switch (BuiltinID) {
#define GET_SME_STREAMING_ATTRS
#include "clang/Basic/arm_sme_streaming_attrs.inc"
#undef GET_SME_STREAMING_ATTRS
}
if (BuiltinType)
checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType);
if (hasSMEZAState(BuiltinID) && !hasSMEZAState(FD))
Diag(TheCall->getBeginLoc(),
diag::warn_attribute_arm_za_builtin_no_za_state)
<< TheCall->getSourceRange();
}
// Range check SME intrinsics that take immediate values.
SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
switch (BuiltinID) {
default:
return false;
#define GET_SME_IMMEDIATE_CHECK
#include "clang/Basic/arm_sme_sema_rangechecks.inc"
#undef GET_SME_IMMEDIATE_CHECK
}
return ParseSVEImmChecks(TheCall, ImmChecks);
}
bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (const FunctionDecl *FD = getCurFunctionDecl()) {
std::optional<ArmStreamingType> BuiltinType;
switch (BuiltinID) {
#define GET_SVE_STREAMING_ATTRS
#include "clang/Basic/arm_sve_streaming_attrs.inc"
#undef GET_SVE_STREAMING_ATTRS
}
if (BuiltinType)
checkArmStreamingBuiltin(*this, TheCall, FD, *BuiltinType);
}
// Range check SVE intrinsics that take immediate values.
SmallVector<std::tuple<int, int, int>, 3> ImmChecks;
@ -3180,9 +3247,6 @@ bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
#define GET_SVE_IMMEDIATE_CHECK
#include "clang/Basic/arm_sve_sema_rangechecks.inc"
#undef GET_SVE_IMMEDIATE_CHECK
#define GET_SME_IMMEDIATE_CHECK
#include "clang/Basic/arm_sme_sema_rangechecks.inc"
#undef GET_SME_IMMEDIATE_CHECK
}
return ParseSVEImmChecks(TheCall, ImmChecks);
@ -3569,6 +3633,9 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall))
return true;
if (CheckSMEBuiltinFunctionCall(BuiltinID, TheCall))
return true;
// For intrinsics which take an immediate value as part of the instruction,
// range check them here.
unsigned i = 0, l = 0, u = 0;
@ -5322,7 +5389,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
QualType Op2Type = TheCall->getArg(1)->getType();
QualType Op3Type = TheCall->getArg(2)->getType();
uint64_t ElemSize = Op1Type->isRVVType(32, false) ? 32 : 64;
if (ElemSize == 64 && !TI.hasFeature("experimental-zvknhb"))
if (ElemSize == 64 && !TI.hasFeature("zvknhb"))
return Diag(TheCall->getBeginLoc(),
diag::err_riscv_type_requires_extension)
<< Op1Type << "zvknhb";

View file

@ -2005,12 +2005,12 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
if (D->isInvalidDecl())
return false;
if (auto *DD = dyn_cast<DecompositionDecl>(D)) {
if (const auto *DD = dyn_cast<DecompositionDecl>(D)) {
// For a decomposition declaration, warn if none of the bindings are
// referenced, instead of if the variable itself is referenced (which
// it is, by the bindings' expressions).
bool IsAllPlaceholders = true;
for (auto *BD : DD->bindings()) {
for (const auto *BD : DD->bindings()) {
if (BD->isReferenced())
return false;
IsAllPlaceholders = IsAllPlaceholders && BD->isPlaceholderVar(LangOpts);
@ -2054,7 +2054,7 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const Expr *Init = VD->getInit();
if (const auto *Cleanups = dyn_cast_or_null<ExprWithCleanups>(Init))
if (const auto *Cleanups = dyn_cast_if_present<ExprWithCleanups>(Init))
Init = Cleanups->getSubExpr();
const auto *Ty = VD->getType().getTypePtr();
@ -2068,11 +2068,10 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
// Warn for reference variables whose initializtion performs lifetime
// extension.
if (const auto *MTE = dyn_cast_or_null<MaterializeTemporaryExpr>(Init)) {
if (MTE->getExtendingDecl()) {
Ty = VD->getType().getNonReferenceType().getTypePtr();
Init = MTE->getSubExpr()->IgnoreImplicitAsWritten();
}
if (const auto *MTE = dyn_cast_if_present<MaterializeTemporaryExpr>(Init);
MTE && MTE->getExtendingDecl()) {
Ty = VD->getType().getNonReferenceType().getTypePtr();
Init = MTE->getSubExpr()->IgnoreImplicitAsWritten();
}
// If we failed to complete the type for some reason, or if the type is
@ -2089,15 +2088,14 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
if (Tag->hasAttr<UnusedAttr>())
return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (!RD->hasTrivialDestructor() && !RD->hasAttr<WarnUnusedAttr>())
return false;
if (Init) {
const CXXConstructExpr *Construct =
dyn_cast<CXXConstructExpr>(Init);
const auto *Construct = dyn_cast<CXXConstructExpr>(Init);
if (Construct && !Construct->isElidable()) {
CXXConstructorDecl *CD = Construct->getConstructor();
const CXXConstructorDecl *CD = Construct->getConstructor();
if (!CD->isTrivial() && !RD->hasAttr<WarnUnusedAttr>() &&
(VD->getInit()->isValueDependent() || !VD->evaluateValue()))
return false;
@ -2211,10 +2209,9 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD,
return;
// In C++, don't warn for record types that don't have WarnUnusedAttr, to
// mimic gcc's behavior.
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (!RD->hasAttr<WarnUnusedAttr>())
return;
}
if (const auto *RD = dyn_cast<CXXRecordDecl>(Tag);
RD && !RD->hasAttr<WarnUnusedAttr>())
return;
}
// Don't warn about __block Objective-C pointer variables, as they might
@ -12957,7 +12954,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
// FIXME: Initialization should not be taking a mutable list of inits.
SmallVector<Expr*, 8> InitsCopy(DeduceInits.begin(), DeduceInits.end());
return DeduceTemplateSpecializationFromInitializer(TSI, Entity, Kind,
InitsCopy, PL);
InitsCopy);
}
if (DirectInit) {
@ -19518,20 +19515,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
CDecl->setIvarRBraceLoc(RBrac);
}
}
// Check the "counted_by" attribute to ensure that the count field exists in
// the struct. Make sure we're performing this check on the outer-most
// record. This is a C-only feature.
if (!getLangOpts().CPlusPlus && Record &&
!isa<RecordDecl>(Record->getParent())) {
auto Pred = [](const Decl *D) {
if (const auto *FD = dyn_cast_if_present<FieldDecl>(D))
return FD->hasAttr<CountedByAttr>();
return false;
};
if (const FieldDecl *FD = Record->findFieldIf(Pred))
CheckCountedByAttr(S, FD);
}
}
/// Determine whether the given integral value is representable within

View file

@ -8445,92 +8445,6 @@ static void handleZeroCallUsedRegsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
D->addAttr(ZeroCallUsedRegsAttr::Create(S.Context, Kind, AL));
}
static void handleCountedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
if (!AL.isArgIdent(0)) {
S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
<< AL << AANT_ArgumentIdentifier;
return;
}
IdentifierLoc *IL = AL.getArgAsIdent(0);
CountedByAttr *CBA =
::new (S.Context) CountedByAttr(S.Context, AL, IL->Ident);
CBA->setCountedByFieldLoc(IL->Loc);
D->addAttr(CBA);
}
bool Sema::CheckCountedByAttr(Scope *S, const FieldDecl *FD) {
const auto *CBA = FD->getAttr<CountedByAttr>();
const IdentifierInfo *FieldName = CBA->getCountedByField();
DeclarationNameInfo NameInfo(FieldName,
CBA->getCountedByFieldLoc().getBegin());
LookupResult MemResult(*this, NameInfo, Sema::LookupMemberName);
LookupName(MemResult, S);
if (MemResult.empty()) {
// The "counted_by" field needs to exist within the struct.
LookupResult OrdResult(*this, NameInfo, Sema::LookupOrdinaryName);
LookupName(OrdResult, S);
if (!OrdResult.empty()) {
SourceRange SR = FD->getLocation();
Diag(SR.getBegin(), diag::err_counted_by_must_be_in_structure)
<< FieldName << SR;
if (auto *ND = OrdResult.getAsSingle<NamedDecl>()) {
SR = ND->getLocation();
Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
<< ND << SR;
}
return true;
}
CXXScopeSpec SS;
DeclFilterCCC<FieldDecl> Filter(FieldName);
return DiagnoseEmptyLookup(S, SS, MemResult, Filter, nullptr, std::nullopt,
const_cast<DeclContext *>(FD->getDeclContext()));
}
LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
if (!Decl::isFlexibleArrayMemberLike(Context, FD, FD->getType(),
StrictFlexArraysLevel, true)) {
// The "counted_by" attribute must be on a flexible array member.
SourceRange SR = FD->getLocation();
Diag(SR.getBegin(), diag::err_counted_by_attr_not_on_flexible_array_member)
<< SR;
return true;
}
if (const FieldDecl *Field = MemResult.getAsSingle<FieldDecl>()) {
if (Field->hasAttr<CountedByAttr>()) {
// The "counted_by" field can't point to the flexible array member.
SourceRange SR = CBA->getCountedByFieldLoc();
Diag(SR.getBegin(), diag::err_counted_by_attr_refers_to_flexible_array)
<< CBA->getCountedByField() << SR;
return true;
}
if (!Field->getType()->isIntegerType() ||
Field->getType()->isBooleanType()) {
// The "counted_by" field must have an integer type.
SourceRange SR = CBA->getCountedByFieldLoc();
Diag(SR.getBegin(),
diag::err_flexible_array_counted_by_attr_field_not_integer)
<< CBA->getCountedByField() << SR;
SR = Field->getLocation();
Diag(SR.getBegin(), diag::note_flexible_array_counted_by_attr_field)
<< Field << SR;
return true;
}
}
return false;
}
static void handleFunctionReturnThunksAttr(Sema &S, Decl *D,
const ParsedAttr &AL) {
StringRef KindStr;
@ -9488,10 +9402,6 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
handleAvailableOnlyInDefaultEvalMethod(S, D, AL);
break;
case ParsedAttr::AT_CountedBy:
handleCountedByAttr(S, D, AL);
break;
// Microsoft attributes:
case ParsedAttr::AT_LayoutVersion:
handleLayoutVersion(S, D, AL);

View file

@ -2469,8 +2469,7 @@ bool Sema::DiagnoseDependentMemberLookup(const LookupResult &R) {
bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
CorrectionCandidateCallback &CCC,
TemplateArgumentListInfo *ExplicitTemplateArgs,
ArrayRef<Expr *> Args, DeclContext *LookupCtx,
TypoExpr **Out) {
ArrayRef<Expr *> Args, TypoExpr **Out) {
DeclarationName Name = R.getLookupName();
unsigned diagnostic = diag::err_undeclared_var_use;
@ -2486,8 +2485,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// unqualified lookup. This is useful when (for example) the
// original lookup would not have found something because it was a
// dependent name.
DeclContext *DC =
LookupCtx ? LookupCtx : (SS.isEmpty() ? CurContext : nullptr);
DeclContext *DC = SS.isEmpty() ? CurContext : nullptr;
while (DC) {
if (isa<CXXRecordDecl>(DC)) {
LookupQualifiedName(R, DC);
@ -2530,12 +2528,12 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
emitEmptyLookupTypoDiagnostic(TC, *this, SS, Name, TypoLoc, Args,
diagnostic, diagnostic_suggest);
},
nullptr, CTK_ErrorRecovery, LookupCtx);
nullptr, CTK_ErrorRecovery);
if (*Out)
return true;
} else if (S && (Corrected =
CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S,
&SS, CCC, CTK_ErrorRecovery, LookupCtx))) {
} else if (S &&
(Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
S, &SS, CCC, CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
@ -2825,7 +2823,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
// a template name, but we happen to have always already looked up the name
// before we get here if it must be a template name.
if (DiagnoseEmptyLookup(S, SS, R, CCC ? *CCC : DefaultValidator, nullptr,
std::nullopt, nullptr, &TE)) {
std::nullopt, &TE)) {
if (TE && KeywordReplacement) {
auto &State = getTypoExprState(TE);
auto BestTC = State.Consumer->getNextCorrection();

View file

@ -843,21 +843,21 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) {
// operation from the operand to the exception object (15.1) can be
// omitted by constructing the automatic object directly into the
// exception object
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
if (VarDecl *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) {
for( ; S; S = S->getParent()) {
if (S->isDeclScope(Var)) {
IsThrownVarInScope = true;
break;
}
// FIXME: Many of the scope checks here seem incorrect.
if (S->getFlags() &
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
Scope::ObjCMethodScope | Scope::TryScope))
break;
if (const auto *DRE = dyn_cast<DeclRefExpr>(Ex->IgnoreParens()))
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl());
Var && Var->hasLocalStorage() &&
!Var->getType().isVolatileQualified()) {
for (; S; S = S->getParent()) {
if (S->isDeclScope(Var)) {
IsThrownVarInScope = true;
break;
}
// FIXME: Many of the scope checks here seem incorrect.
if (S->getFlags() &
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
Scope::ObjCMethodScope | Scope::TryScope))
break;
}
}
}

View file

@ -253,7 +253,9 @@ static void diagnoseInstanceReference(Sema &SemaRef,
SemaRef.Diag(Loc, diag::err_member_call_without_object)
<< Range << /*static*/ 0;
else {
const auto *Callee = dyn_cast<CXXMethodDecl>(Rep);
if (const auto *Tpl = dyn_cast<FunctionTemplateDecl>(Rep))
Rep = Tpl->getTemplatedDecl();
const auto *Callee = cast<CXXMethodDecl>(Rep);
auto Diag = SemaRef.Diag(Loc, diag::err_member_call_without_object)
<< Range << Callee->isExplicitObjectMemberFunction();
if (!Replacement.empty())

View file

@ -25,6 +25,7 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/FoldingSet.h"
@ -465,8 +466,7 @@ class InitListChecker {
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass,
bool FillWithNoInit = false,
bool WarnIfMissing = false);
bool FillWithNoInit = false);
void FillInEmptyInitializations(const InitializedEntity &Entity,
InitListExpr *ILE, bool &RequiresSecondPass,
InitListExpr *OuterILE, unsigned OuterIndex,
@ -655,16 +655,11 @@ void InitListChecker::FillInEmptyInitForBase(
}
}
static bool hasAnyDesignatedInits(const InitListExpr *IL) {
return llvm::any_of(*IL, [=](const Stmt *Init) {
return isa_and_nonnull<DesignatedInitExpr>(Init);
});
}
void InitListChecker::FillInEmptyInitForField(
unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass, bool FillWithNoInit,
bool WarnIfMissing) {
void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
bool &RequiresSecondPass,
bool FillWithNoInit) {
SourceLocation Loc = ILE->getEndLoc();
unsigned NumInits = ILE->getNumInits();
InitializedEntity MemberEntity
@ -732,52 +727,15 @@ void InitListChecker::FillInEmptyInitForField(
if (hadError || VerifyOnly) {
// Do nothing
} else {
if (WarnIfMissing) {
auto CheckAnonMember = [&](const FieldDecl *FD,
auto &&CheckAnonMember) -> FieldDecl * {
FieldDecl *Uninitialized = nullptr;
RecordDecl *RD = FD->getType()->getAsRecordDecl();
assert(RD && "Not anonymous member checked?");
for (auto *F : RD->fields()) {
FieldDecl *UninitializedFieldInF = nullptr;
if (F->isAnonymousStructOrUnion())
UninitializedFieldInF = CheckAnonMember(F, CheckAnonMember);
else if (!F->isUnnamedBitfield() &&
!F->getType()->isIncompleteArrayType() &&
!F->hasInClassInitializer())
UninitializedFieldInF = F;
if (RD->isUnion() && !UninitializedFieldInF)
return nullptr;
if (!Uninitialized)
Uninitialized = UninitializedFieldInF;
}
return Uninitialized;
};
FieldDecl *FieldToDiagnose = nullptr;
if (Field->isAnonymousStructOrUnion())
FieldToDiagnose = CheckAnonMember(Field, CheckAnonMember);
else if (!Field->isUnnamedBitfield() &&
!Field->getType()->isIncompleteArrayType())
FieldToDiagnose = Field;
if (FieldToDiagnose)
SemaRef.Diag(Loc, diag::warn_missing_field_initializers)
<< FieldToDiagnose;
}
if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
} else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
// Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
RequiresSecondPass = true;
}
} else if (Init < NumInits) {
ILE->setInit(Init, MemberInit.getAs<Expr>());
} else if (!isa<ImplicitValueInitExpr>(MemberInit.get())) {
// Empty initialization requires a constructor call, so
// extend the initializer list to include the constructor
// call and make a note that we'll need to take another pass
// through the initializer list.
ILE->updateInit(SemaRef.Context, Init, MemberInit.getAs<Expr>());
RequiresSecondPass = true;
}
} else if (InitListExpr *InnerILE
= dyn_cast<InitListExpr>(ILE->getInit(Init))) {
@ -845,36 +803,9 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
} else {
InitListExpr *SForm =
ILE->isSyntacticForm() ? ILE : ILE->getSyntacticForm();
// The fields beyond ILE->getNumInits() are default initialized, so in
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
// Some checks that are required for missing fields warning are bound to
// how many elements the initializer list originally was provided; perform
// them before the list is expanded.
bool WarnIfMissingField =
!SForm->isIdiomaticZeroInitializer(SemaRef.getLangOpts()) &&
ILE->getNumInits();
// Disable check for missing fields when designators are used in C to
// match gcc behaviour.
// FIXME: Should we emulate possible gcc warning bug?
WarnIfMissingField &=
SemaRef.getLangOpts().CPlusPlus || !hasAnyDesignatedInits(SForm);
if (OuterILE) {
// When nested designators are present, there might be two nested init
// lists created and only outer will contain designated initializer
// expression, so check outer list as well.
InitListExpr *OuterSForm = OuterILE->isSyntacticForm()
? OuterILE
: OuterILE->getSyntacticForm();
WarnIfMissingField &= SemaRef.getLangOpts().CPlusPlus ||
!hasAnyDesignatedInits(OuterSForm);
}
unsigned NumElems = numStructUnionElements(ILE->getType());
if (!RDecl->isUnion() && RDecl->hasFlexibleArrayMember())
++NumElems;
@ -902,7 +833,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
return;
FillInEmptyInitForField(Init, Field, Entity, ILE, RequiresSecondPass,
FillWithNoInit, WarnIfMissingField);
FillWithNoInit);
if (hadError)
return;
@ -1017,6 +948,13 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
static bool hasAnyDesignatedInits(const InitListExpr *IL) {
for (const Stmt *Init : *IL)
if (isa_and_nonnull<DesignatedInitExpr>(Init))
return true;
return false;
}
InitListChecker::InitListChecker(
Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T,
bool VerifyOnly, bool TreatUnavailableAsInvalid, bool InOverloadResolution,
@ -2288,8 +2226,12 @@ void InitListChecker::CheckStructUnionTypes(
size_t NumRecordDecls = llvm::count_if(RD->decls(), [&](const Decl *D) {
return isa<FieldDecl>(D) || isa<RecordDecl>(D);
});
bool CheckForMissingFields =
!IList->isIdiomaticZeroInitializer(SemaRef.getLangOpts());
bool HasDesignatedInit = false;
llvm::SmallPtrSet<FieldDecl *, 4> InitializedFields;
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
SourceLocation InitLoc = Init->getBeginLoc();
@ -2313,17 +2255,24 @@ void InitListChecker::CheckStructUnionTypes(
// Find the field named by the designated initializer.
DesignatedInitExpr::Designator *D = DIE->getDesignator(0);
if (!VerifyOnly && D->isFieldDesignator() && !DesignatedInitFailed) {
if (!VerifyOnly && D->isFieldDesignator()) {
FieldDecl *F = D->getFieldDecl();
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
InitializedFields.insert(F);
if (!DesignatedInitFailed) {
QualType ET = SemaRef.Context.getBaseElementType(F->getType());
if (checkDestructorReference(ET, InitLoc, SemaRef)) {
hadError = true;
return;
}
}
}
InitializedSomething = true;
// Disable check for missing fields when designators are used.
// This matches gcc behaviour.
if (!SemaRef.getLangOpts().CPlusPlus)
CheckForMissingFields = false;
continue;
}
@ -2402,6 +2351,7 @@ void InitListChecker::CheckStructUnionTypes(
CheckSubElementType(MemberEntity, IList, Field->getType(), Index,
StructuredList, StructuredIndex);
InitializedSomething = true;
InitializedFields.insert(*Field);
if (RD->isUnion() && StructuredList) {
// Initialize the first field within the union.
@ -2411,6 +2361,28 @@ void InitListChecker::CheckStructUnionTypes(
++Field;
}
// Emit warnings for missing struct field initializers.
if (!VerifyOnly && InitializedSomething && CheckForMissingFields &&
!RD->isUnion()) {
// It is possible we have one or more unnamed bitfields remaining.
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = HasDesignatedInit ? RD->field_begin()
: Field,
end = RD->field_end();
it != end; ++it) {
if (HasDesignatedInit && InitializedFields.count(*it))
continue;
if (!it->isUnnamedBitfield() && !it->hasInClassInitializer() &&
!it->getType()->isIncompleteArrayType()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
diag::warn_missing_field_initializers)
<< *it;
break;
}
}
}
// Check that any remaining fields can be value-initialized if we're not
// building a structured list. (If we are, we'll check this later.)
if (!StructuredList && Field != FieldEnd && !RD->isUnion() &&
@ -5458,18 +5430,12 @@ static void TryOrBuildParenListInitialization(
auto HandleInitializedEntity = [&](const InitializedEntity &SubEntity,
const InitializationKind &SubKind,
Expr *Arg, Expr **InitExpr = nullptr) {
InitializationSequence IS = [&]() {
if (Arg)
return InitializationSequence(S, SubEntity, SubKind, Arg);
return InitializationSequence(S, SubEntity, SubKind, std::nullopt);
}();
InitializationSequence IS = InitializationSequence(
S, SubEntity, SubKind, Arg ? MultiExprArg(Arg) : std::nullopt);
if (IS.Failed()) {
if (!VerifyOnly) {
if (Arg)
IS.Diagnose(S, SubEntity, SubKind, Arg);
else
IS.Diagnose(S, SubEntity, SubKind, std::nullopt);
IS.Diagnose(S, SubEntity, SubKind, Arg ? ArrayRef(Arg) : std::nullopt);
} else {
Sequence.SetFailed(
InitializationSequence::FK_ParenthesizedListInitFailed);
@ -5479,10 +5445,8 @@ static void TryOrBuildParenListInitialization(
}
if (!VerifyOnly) {
ExprResult ER;
if (Arg)
ER = IS.Perform(S, SubEntity, SubKind, Arg);
else
ER = IS.Perform(S, SubEntity, SubKind, std::nullopt);
ER = IS.Perform(S, SubEntity, SubKind,
Arg ? MultiExprArg(Arg) : std::nullopt);
if (InitExpr)
*InitExpr = ER.get();
else
@ -10439,40 +10403,53 @@ static void DiagnoseNarrowingInInitList(Sema &S,
// No narrowing occurred.
return;
case NK_Type_Narrowing:
case NK_Type_Narrowing: {
// This was a floating-to-integer conversion, which is always considered a
// narrowing conversion even if the value is a constant and can be
// represented exactly as an integer.
S.Diag(PostInit->getBeginLoc(), NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_type_narrowing
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
case NK_Constant_Narrowing:
// A constant value was narrowed.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_constant_narrowing
? (T == EntityType
? diag::ext_init_list_type_narrowing
: diag::ext_init_list_type_narrowing_const_reference)
: diag::warn_init_list_type_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< T.getLocalUnqualifiedType();
break;
}
case NK_Constant_Narrowing: {
// A constant value was narrowed.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? (T == EntityType
? diag::ext_init_list_constant_narrowing
: diag::ext_init_list_constant_narrowing_const_reference)
: diag::warn_init_list_constant_narrowing)
<< PostInit->getSourceRange()
<< ConstantValue.getAsString(S.getASTContext(), ConstantType)
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
}
case NK_Variable_Narrowing:
case NK_Variable_Narrowing: {
// A variable's value may have been narrowed.
QualType T = EntityType.getNonReferenceType();
S.Diag(PostInit->getBeginLoc(),
NarrowingErrs(S.getLangOpts())
? diag::ext_init_list_variable_narrowing
? (T == EntityType
? diag::ext_init_list_variable_narrowing
: diag::ext_init_list_variable_narrowing_const_reference)
: diag::warn_init_list_variable_narrowing)
<< PostInit->getSourceRange()
<< PreNarrowingType.getLocalUnqualifiedType()
<< EntityType.getNonReferenceType().getLocalUnqualifiedType();
break;
}
}
SmallString<128> StaticCast;
llvm::raw_svector_ostream OS(StaticCast);
@ -10590,7 +10567,7 @@ static bool isOrIsDerivedFromSpecializationOf(CXXRecordDecl *RD,
QualType Sema::DeduceTemplateSpecializationFromInitializer(
TypeSourceInfo *TSInfo, const InitializedEntity &Entity,
const InitializationKind &Kind, MultiExprArg Inits, ParenListExpr *PL) {
const InitializationKind &Kind, MultiExprArg Inits) {
auto *DeducedTST = dyn_cast<DeducedTemplateSpecializationType>(
TSInfo->getType()->getContainedDeducedType());
assert(DeducedTST && "not a deduced template specialization type");
@ -10821,9 +10798,12 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (getLangOpts().CPlusPlus20 && !HasAnyDeductionGuide) {
if (ListInit && ListInit->getNumInits()) {
SynthesizeAggrGuide(ListInit);
} else if (PL && PL->getNumExprs()) {
InitListExpr TempListInit(getASTContext(), PL->getLParenLoc(),
PL->exprs(), PL->getRParenLoc());
} else if (Inits.size()) { // parenthesized expression-list
// Inits are expressions inside the parentheses. We don't have
// the parentheses source locations, use the begin/end of Inits as the
// best heuristic.
InitListExpr TempListInit(getASTContext(), Inits.front()->getBeginLoc(),
Inits, Inits.back()->getEndLoc());
SynthesizeAggrGuide(&TempListInit);
}
}

View file

@ -14658,6 +14658,19 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
}
setFunctionHasBranchProtectedScope();
const OMPClause *BareClause = nullptr;
bool HasThreadLimitAndNumTeamsClause = hasClauses(Clauses, OMPC_num_teams) &&
hasClauses(Clauses, OMPC_thread_limit);
bool HasBareClause = llvm::any_of(Clauses, [&](const OMPClause *C) {
BareClause = C;
return C->getClauseKind() == OMPC_ompx_bare;
});
if (HasBareClause && !HasThreadLimitAndNumTeamsClause) {
Diag(BareClause->getBeginLoc(), diag::err_ompx_bare_no_grid);
return StmtError();
}
return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}

View file

@ -206,15 +206,16 @@ void RISCVIntrinsicManagerImpl::ConstructRVVIntrinsics(
{"xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq},
{"xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod},
{"xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq},
{"experimental-zvbb", RVV_REQ_Zvbb},
{"experimental-zvbc", RVV_REQ_Zvbc},
{"experimental-zvkb", RVV_REQ_Zvkb},
{"experimental-zvkg", RVV_REQ_Zvkg},
{"experimental-zvkned", RVV_REQ_Zvkned},
{"experimental-zvknha", RVV_REQ_Zvknha},
{"experimental-zvknhb", RVV_REQ_Zvknhb},
{"experimental-zvksed", RVV_REQ_Zvksed},
{"experimental-zvksh", RVV_REQ_Zvksh}};
{"zvbb", RVV_REQ_Zvbb},
{"zvbc", RVV_REQ_Zvbc},
{"zvkb", RVV_REQ_Zvkb},
{"zvkg", RVV_REQ_Zvkg},
{"zvkned", RVV_REQ_Zvkned},
{"zvknha", RVV_REQ_Zvknha},
{"zvknhb", RVV_REQ_Zvknhb},
{"zvksed", RVV_REQ_Zvksed},
{"zvksh", RVV_REQ_Zvksh},
{"experimental", RVV_REQ_Experimental}};
// Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
// in RISCVVEmitter.cpp.

View file

@ -1271,6 +1271,9 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
bool CaseListIsErroneous = false;
// FIXME: We'd better diagnose missing or duplicate default labels even
// in the dependent case. Because default labels themselves are never
// dependent.
for (SwitchCase *SC = SS->getSwitchCaseList(); SC && !HasDependentValue;
SC = SC->getNextSwitchCase()) {
@ -1327,9 +1330,6 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
}
}
if (!TheDefaultStmt)
Diag(SwitchLoc, diag::warn_switch_default);
if (!HasDependentValue) {
// If we don't have a default statement, check whether the
// condition is constant.
@ -1344,6 +1344,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
assert(!HasConstantCond ||
(ConstantCondValue.getBitWidth() == CondWidth &&
ConstantCondValue.isSigned() == CondIsSigned));
Diag(SwitchLoc, diag::warn_switch_default);
}
bool ShouldCheckConstantCond = HasConstantCond;

View file

@ -1824,6 +1824,15 @@ static void SetNestedNameSpecifier(Sema &S, TagDecl *T,
T->setQualifierInfo(SS.getWithLocInContext(S.Context));
}
// Returns the template parameter list with all default template argument
// information.
static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
// Make sure we get the template parameter list from the most
// recent declaration, since that is the only one that is guaranteed to
// have all the default template argument information.
return cast<TemplateDecl>(TD->getMostRecentDecl())->getTemplateParameters();
}
DeclResult Sema::CheckClassTemplate(
Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc,
CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc,
@ -2061,13 +2070,13 @@ DeclResult Sema::CheckClassTemplate(
if (!(TUK == TUK_Friend && CurContext->isDependentContext()) &&
CheckTemplateParameterList(
TemplateParams,
PrevClassTemplate
? PrevClassTemplate->getMostRecentDecl()->getTemplateParameters()
: nullptr,
PrevClassTemplate ? GetTemplateParameterList(PrevClassTemplate)
: nullptr,
(SS.isSet() && SemanticContext && SemanticContext->isRecord() &&
SemanticContext->isDependentContext())
? TPC_ClassTemplateMember
: TUK == TUK_Friend ? TPC_FriendClassTemplate : TPC_ClassTemplate,
: TUK == TUK_Friend ? TPC_FriendClassTemplate
: TPC_ClassTemplate,
SkipBody))
Invalid = true;
@ -2298,7 +2307,7 @@ struct ConvertConstructorToDeductionGuideTransform {
// -- The template parameters are the template parameters of the class
// template followed by the template parameters (including default
// template arguments) of the constructor, if any.
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
TemplateParameterList *TemplateParams = GetTemplateParameterList(Template);
if (FTD) {
TemplateParameterList *InnerParams = FTD->getTemplateParameters();
SmallVector<NamedDecl *, 16> AllParams;
@ -2424,7 +2433,7 @@ struct ConvertConstructorToDeductionGuideTransform {
Params.push_back(NewParam);
}
return buildDeductionGuide(Template->getTemplateParameters(), nullptr,
return buildDeductionGuide(GetTemplateParameterList(Template), nullptr,
ExplicitSpecifier(), TSI, Loc, Loc, Loc);
}
@ -5956,12 +5965,7 @@ bool Sema::CheckTemplateArgumentList(
// template.
TemplateArgumentListInfo NewArgs = TemplateArgs;
// Make sure we get the template parameter list from the most
// recent declaration, since that is the only one that is guaranteed to
// have all the default template argument information.
TemplateParameterList *Params =
cast<TemplateDecl>(Template->getMostRecentDecl())
->getTemplateParameters();
TemplateParameterList *Params = GetTemplateParameterList(Template);
SourceLocation RAngleLoc = NewArgs.getRAngleLoc();

View file

@ -584,7 +584,18 @@ void ASTDeclReader::Visit(Decl *D) {
void ASTDeclReader::VisitDecl(Decl *D) {
BitsUnpacker DeclBits(Record.readInt());
auto ModuleOwnership =
(Decl::ModuleOwnershipKind)DeclBits.getNextBits(/*Width=*/3);
D->setReferenced(DeclBits.getNextBit());
D->Used = DeclBits.getNextBit();
IsDeclMarkedUsed |= D->Used;
D->setAccess((AccessSpecifier)DeclBits.getNextBits(/*Width=*/2));
D->setImplicit(DeclBits.getNextBit());
bool HasStandaloneLexicalDC = DeclBits.getNextBit();
bool HasAttrs = DeclBits.getNextBit();
D->setTopLevelDeclInObjCContainer(DeclBits.getNextBit());
D->InvalidDecl = DeclBits.getNextBit();
D->FromASTFile = true;
if (D->isTemplateParameter() || D->isTemplateParameterPack() ||
isa<ParmVarDecl, ObjCTypeParamDecl>(D)) {
@ -623,20 +634,6 @@ void ASTDeclReader::VisitDecl(Decl *D) {
}
D->setLocation(ThisDeclLoc);
D->InvalidDecl = DeclBits.getNextBit();
bool HasAttrs = DeclBits.getNextBit();
D->setImplicit(DeclBits.getNextBit());
D->Used = DeclBits.getNextBit();
IsDeclMarkedUsed |= D->Used;
D->setReferenced(DeclBits.getNextBit());
D->setTopLevelDeclInObjCContainer(DeclBits.getNextBit());
D->setAccess((AccessSpecifier)DeclBits.getNextBits(/*Width=*/2));
D->FromASTFile = true;
auto ModuleOwnership =
(Decl::ModuleOwnershipKind)DeclBits.getNextBits(/*Width=*/3);
bool ModulePrivate =
(ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);
if (HasAttrs) {
AttrVec Attrs;
Record.readAttributes(Attrs);
@ -647,8 +644,9 @@ void ASTDeclReader::VisitDecl(Decl *D) {
// Determine whether this declaration is part of a (sub)module. If so, it
// may not yet be visible.
bool ModulePrivate =
(ModuleOwnership == Decl::ModuleOwnershipKind::ModulePrivate);
if (unsigned SubmoduleID = readSubmoduleID()) {
switch (ModuleOwnership) {
case Decl::ModuleOwnershipKind::Visible:
ModuleOwnership = Decl::ModuleOwnershipKind::VisibleWhenImported;
@ -1065,9 +1063,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
// after everything else is read.
BitsUnpacker FunctionDeclBits(Record.readInt());
FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setStorageClass((StorageClass)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setInlineSpecified(FunctionDeclBits.getNextBit());
FD->setImplicitlyInline(FunctionDeclBits.getNextBit());
FD->setHasSkippedBody(FunctionDeclBits.getNextBit());
FD->setVirtualAsWritten(FunctionDeclBits.getNextBit());
// We defer calling `FunctionDecl::setPure()` here as for methods of
// `CXXTemplateSpecializationDecl`s, we may not have connected up the
@ -1081,16 +1081,14 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setDefaulted(FunctionDeclBits.getNextBit());
FD->setExplicitlyDefaulted(FunctionDeclBits.getNextBit());
FD->setIneligibleOrNotSelected(FunctionDeclBits.getNextBit());
FD->setHasImplicitReturnZero(FunctionDeclBits.getNextBit());
FD->setConstexprKind(
(ConstexprSpecKind)FunctionDeclBits.getNextBits(/*Width=*/2));
FD->setUsesSEHTry(FunctionDeclBits.getNextBit());
FD->setHasSkippedBody(FunctionDeclBits.getNextBit());
FD->setHasImplicitReturnZero(FunctionDeclBits.getNextBit());
FD->setIsMultiVersion(FunctionDeclBits.getNextBit());
FD->setLateTemplateParsed(FunctionDeclBits.getNextBit());
FD->setFriendConstraintRefersToEnclosingTemplate(
FunctionDeclBits.getNextBit());
FD->setCachedLinkage((Linkage)FunctionDeclBits.getNextBits(/*Width=*/3));
FD->setUsesSEHTry(FunctionDeclBits.getNextBit());
FD->EndRangeLoc = readSourceLocation();
if (FD->isExplicitlyDefaulted())
@ -1597,6 +1595,8 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VisitDeclaratorDecl(VD);
BitsUnpacker VarDeclBits(Record.readInt());
auto VarLinkage = Linkage(VarDeclBits.getNextBits(/*Width=*/3));
bool DefGeneratedInModule = VarDeclBits.getNextBit();
VD->VarDeclBits.SClass = (StorageClass)VarDeclBits.getNextBits(/*Width=*/3);
VD->VarDeclBits.TSCSpec = VarDeclBits.getNextBits(/*Width=*/2);
VD->VarDeclBits.InitStyle = VarDeclBits.getNextBits(/*Width=*/2);
@ -1608,17 +1608,20 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->NonParmVarDeclBits.ExceptionVar = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.NRVOVariable = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.CXXForRangeDecl = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.IsInline = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.IsInlineSpecified = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.IsConstexpr = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.IsInitCapture = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.PreviousDeclInSameBlockScope =
VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.ImplicitParamKind =
VarDeclBits.getNextBits(/*Width*/ 3);
VD->NonParmVarDeclBits.EscapingByref = VarDeclBits.getNextBit();
HasDeducedType = VarDeclBits.getNextBit();
VD->NonParmVarDeclBits.ImplicitParamKind =
VarDeclBits.getNextBits(/*Width*/ 3);
VD->NonParmVarDeclBits.ObjCForDecl = VarDeclBits.getNextBit();
}
// If this variable has a deduced type, defer reading that type until we are
@ -1630,7 +1633,6 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->setType(Reader.GetType(DeferredTypeID));
DeferredTypeID = 0;
auto VarLinkage = Linkage(VarDeclBits.getNextBits(/*Width=*/3));
VD->setCachedLinkage(VarLinkage);
// Reconstruct the one piece of the IdentifierNamespace that we need.
@ -1638,7 +1640,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) {
VD->getLexicalDeclContext()->isFunctionOrMethod())
VD->setLocalExternDecl();
if (VarDeclBits.getNextBit()) {
if (DefGeneratedInModule) {
Reader.DefinitionSource[VD] =
Loc.F->Kind == ModuleKind::MK_MainFile ||
Reader.getContext().getLangOpts().BuildingPCHWithObjectFile;
@ -2660,7 +2662,7 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
D->setDeclaredWithTypename(Record.readInt());
if (Record.readBool()) {
if (D->hasTypeConstraint()) {
ConceptReference *CR = nullptr;
if (Record.readBool())
CR = Record.readConceptReference();

View file

@ -73,6 +73,8 @@ namespace clang {
ASTRecordReader &Record;
llvm::BitstreamCursor &DeclsCursor;
std::optional<BitsUnpacker> CurrentUnpackingBits;
SourceLocation readSourceLocation() {
return Record.readSourceLocation();
}
@ -110,6 +112,9 @@ namespace clang {
/// itself.
static const unsigned NumExprFields = NumStmtFields + 2;
/// The number of bits required for the packing bits for the Expr class.
static const unsigned NumExprBits = 10;
/// Read and initialize a ExplicitTemplateArgumentList structure.
void ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args,
TemplateArgumentLoc *ArgsLocArray,
@ -214,9 +219,11 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) {
void ASTStmtReader::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
bool HasElse = Record.readInt();
bool HasVar = Record.readInt();
bool HasInit = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
bool HasElse = CurrentUnpackingBits->getNextBit();
bool HasVar = CurrentUnpackingBits->getNextBit();
bool HasInit = CurrentUnpackingBits->getNextBit();
S->setStatementKind(static_cast<IfStatementKind>(Record.readInt()));
S->setCond(Record.readSubExpr());
@ -523,14 +530,15 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
void ASTStmtReader::VisitExpr(Expr *E) {
VisitStmt(E);
CurrentUnpackingBits.emplace(Record.readInt());
E->setDependence(static_cast<ExprDependence>(
CurrentUnpackingBits->getNextBits(/*Width=*/5)));
E->setValueKind(static_cast<ExprValueKind>(
CurrentUnpackingBits->getNextBits(/*Width=*/2)));
E->setObjectKind(static_cast<ExprObjectKind>(
CurrentUnpackingBits->getNextBits(/*Width=*/3)));
E->setType(Record.readType());
BitsUnpacker ExprBits(Record.readInt());
E->setDependence(
static_cast<ExprDependence>(ExprBits.getNextBits(/*Width=*/5)));
E->setValueKind(
static_cast<ExprValueKind>(ExprBits.getNextBits(/*Width=*/2)));
E->setObjectKind(
static_cast<ExprObjectKind>(ExprBits.getNextBits(/*Width=*/3)));
assert(Record.getIdx() == NumExprFields &&
"Incorrect expression field count");
}
@ -591,13 +599,17 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) {
void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
E->DeclRefExprBits.HasQualifier = Record.readInt();
E->DeclRefExprBits.HasFoundDecl = Record.readInt();
E->DeclRefExprBits.HasTemplateKWAndArgsInfo = Record.readInt();
E->DeclRefExprBits.HadMultipleCandidates = Record.readInt();
E->DeclRefExprBits.RefersToEnclosingVariableOrCapture = Record.readInt();
E->DeclRefExprBits.NonOdrUseReason = Record.readInt();
E->DeclRefExprBits.IsImmediateEscalating = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
E->DeclRefExprBits.HadMultipleCandidates = CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.RefersToEnclosingVariableOrCapture =
CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.NonOdrUseReason =
CurrentUnpackingBits->getNextBits(/*Width=*/2);
E->DeclRefExprBits.IsImmediateEscalating = CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.HasFoundDecl = CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.HasQualifier = CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.HasTemplateKWAndArgsInfo =
CurrentUnpackingBits->getNextBit();
E->DeclRefExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
unsigned NumTemplateArgs = 0;
if (E->hasTemplateKWAndArgsInfo())
@ -706,12 +718,13 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) {
void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) {
VisitExpr(E);
bool hasFP_Features = Record.readInt();
bool hasFP_Features = CurrentUnpackingBits->getNextBit();
assert(hasFP_Features == E->hasStoredFPFeatures());
E->setSubExpr(Record.readSubExpr());
E->setOpcode((UnaryOperator::Opcode)Record.readInt());
E->setOpcode(
(UnaryOperator::Opcode)CurrentUnpackingBits->getNextBits(/*Width=*/5));
E->setOperatorLoc(readSourceLocation());
E->setCanOverflow(Record.readInt());
E->setCanOverflow(CurrentUnpackingBits->getNextBit());
if (hasFP_Features)
E->setStoredFPFeatures(
FPOptionsOverride::getFromOpaqueInt(Record.readInt()));
@ -1000,12 +1013,11 @@ void ASTStmtReader::VisitOMPIteratorExpr(OMPIteratorExpr *E) {
void ASTStmtReader::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
BitsUnpacker CallExprBits = Record.readInt();
unsigned NumArgs = CallExprBits.getNextBits(/*Width=*/16);
bool HasFPFeatures = CallExprBits.getNextBit();
unsigned NumArgs = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
E->setADLCallKind(
static_cast<CallExpr::ADLCallKind>(CallExprBits.getNextBit()));
static_cast<CallExpr::ADLCallKind>(CurrentUnpackingBits->getNextBit()));
bool HasFPFeatures = CurrentUnpackingBits->getNextBit();
assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!");
E->setRParenLoc(readSourceLocation());
E->setCallee(Record.readSubExpr());
@ -1024,27 +1036,29 @@ void ASTStmtReader::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
VisitExpr(E);
bool HasQualifier = Record.readInt();
bool HasFoundDecl = Record.readInt();
bool HasTemplateInfo = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
bool HasQualifier = CurrentUnpackingBits->getNextBit();
bool HasFoundDecl = CurrentUnpackingBits->getNextBit();
bool HasTemplateInfo = CurrentUnpackingBits->getNextBit();
unsigned NumTemplateArgs = Record.readInt();
E->Base = Record.readSubExpr();
E->MemberDecl = Record.readDeclAs<ValueDecl>();
E->MemberDNLoc = Record.readDeclarationNameLoc(E->MemberDecl->getDeclName());
E->MemberLoc = Record.readSourceLocation();
E->MemberExprBits.IsArrow = Record.readInt();
E->MemberExprBits.IsArrow = CurrentUnpackingBits->getNextBit();
E->MemberExprBits.HasQualifierOrFoundDecl = HasQualifier || HasFoundDecl;
E->MemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo;
E->MemberExprBits.HadMultipleCandidates = Record.readInt();
E->MemberExprBits.NonOdrUseReason = Record.readInt();
E->MemberExprBits.HadMultipleCandidates = CurrentUnpackingBits->getNextBit();
E->MemberExprBits.NonOdrUseReason =
CurrentUnpackingBits->getNextBits(/*Width=*/2);
E->MemberExprBits.OperatorLoc = Record.readSourceLocation();
if (HasQualifier || HasFoundDecl) {
DeclAccessPair FoundDecl;
if (HasFoundDecl) {
auto *FoundD = Record.readDeclAs<NamedDecl>();
auto AS = (AccessSpecifier)Record.readInt();
auto AS = (AccessSpecifier)CurrentUnpackingBits->getNextBits(/*Width=*/2);
FoundDecl = DeclAccessPair::make(FoundD, AS);
} else {
FoundDecl = DeclAccessPair::make(E->MemberDecl,
@ -1091,10 +1105,14 @@ void ASTStmtReader::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
unsigned NumBaseSpecs = Record.readInt();
assert(NumBaseSpecs == E->path_size());
unsigned HasFPFeatures = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
E->setCastKind((CastKind)CurrentUnpackingBits->getNextBits(/*Width=*/7));
unsigned HasFPFeatures = CurrentUnpackingBits->getNextBit();
assert(E->hasStoredFPFeatures() == HasFPFeatures);
E->setSubExpr(Record.readSubExpr());
E->setCastKind((CastKind)Record.readInt());
CastExpr::path_iterator BaseI = E->path_begin();
while (NumBaseSpecs--) {
auto *BaseSpec = new (Record.getContext()) CXXBaseSpecifier;
@ -1107,10 +1125,12 @@ void ASTStmtReader::VisitCastExpr(CastExpr *E) {
}
void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) {
bool hasFP_Features;
VisitExpr(E);
E->setHasStoredFPFeatures(hasFP_Features = Record.readInt());
E->setOpcode((BinaryOperator::Opcode)Record.readInt());
CurrentUnpackingBits.emplace(Record.readInt());
E->setOpcode(
(BinaryOperator::Opcode)CurrentUnpackingBits->getNextBits(/*Width=*/6));
bool hasFP_Features = CurrentUnpackingBits->getNextBit();
E->setHasStoredFPFeatures(hasFP_Features);
E->setLHS(Record.readSubExpr());
E->setRHS(Record.readSubExpr());
E->setOperatorLoc(readSourceLocation());
@ -1148,7 +1168,7 @@ ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
VisitCastExpr(E);
E->setIsPartOfExplicitCast(Record.readInt());
E->setIsPartOfExplicitCast(CurrentUnpackingBits->getNextBit());
}
void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
@ -1764,8 +1784,8 @@ void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
SourceRange R = readSourceRange();
E->Loc = R.getBegin();
E->RParenLoc = R.getEnd();
R = readSourceRange();
E->AngleBrackets = R;
if (CurrentUnpackingBits->getNextBit())
E->AngleBrackets = readSourceRange();
}
void ASTStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
@ -1961,9 +1981,10 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *E) {
VisitExpr(E);
bool HasTemplateKWAndArgsInfo = Record.readInt();
unsigned NumTemplateArgs = Record.readInt();
bool HasFirstQualifierFoundInScope = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit();
bool HasFirstQualifierFoundInScope = CurrentUnpackingBits->getNextBit();
assert((HasTemplateKWAndArgsInfo == E->hasTemplateKWAndArgsInfo()) &&
"Wrong HasTemplateKWAndArgsInfo!");
@ -1979,11 +2000,18 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr(
assert((NumTemplateArgs == E->getNumTemplateArgs()) &&
"Wrong NumTemplateArgs!");
E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt();
E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
E->CXXDependentScopeMemberExprBits.IsArrow =
CurrentUnpackingBits->getNextBit();
E->BaseType = Record.readType();
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
E->Base = Record.readSubExpr();
// not ImplicitAccess
if (CurrentUnpackingBits->getNextBit())
E->Base = Record.readSubExpr();
else
E->Base = nullptr;
E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation();
if (HasFirstQualifierFoundInScope)
*E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>();
@ -1995,11 +2023,11 @@ void
ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
VisitExpr(E);
if (Record.readInt()) // HasTemplateKWAndArgsInfo
if (CurrentUnpackingBits->getNextBit()) // HasTemplateKWAndArgsInfo
ReadTemplateKWAndArgsInfo(
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(),
E->getTrailingObjects<TemplateArgumentLoc>(),
/*NumTemplateArgs=*/Record.readInt());
/*NumTemplateArgs=*/CurrentUnpackingBits->getNextBits(/*Width=*/16));
E->QualifierLoc = Record.readNestedNameSpecifierLoc();
E->NameInfo = Record.readDeclarationNameInfo();
@ -2022,15 +2050,15 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
BitsUnpacker OverloadExprBits = Record.readInt();
unsigned NumResults = OverloadExprBits.getNextBits(/*Width=*/14);
bool HasTemplateKWAndArgsInfo = OverloadExprBits.getNextBit();
unsigned NumResults = Record.readInt();
CurrentUnpackingBits.emplace(Record.readInt());
bool HasTemplateKWAndArgsInfo = CurrentUnpackingBits->getNextBit();
assert((E->getNumDecls() == NumResults) && "Wrong NumResults!");
assert((E->hasTemplateKWAndArgsInfo() == HasTemplateKWAndArgsInfo) &&
"Wrong HasTemplateKWAndArgsInfo!");
if (HasTemplateKWAndArgsInfo) {
unsigned NumTemplateArgs = OverloadExprBits.getNextBits(/*Width=*/14);
unsigned NumTemplateArgs = Record.readInt();
ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(),
E->getTrailingTemplateArgumentLoc(),
NumTemplateArgs);
@ -2057,17 +2085,24 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) {
void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
VisitOverloadExpr(E);
E->UnresolvedMemberExprBits.IsArrow = Record.readInt();
E->UnresolvedMemberExprBits.HasUnresolvedUsing = Record.readInt();
E->Base = Record.readSubExpr();
E->BaseType = Record.readType();
E->UnresolvedMemberExprBits.IsArrow = CurrentUnpackingBits->getNextBit();
E->UnresolvedMemberExprBits.HasUnresolvedUsing =
CurrentUnpackingBits->getNextBit();
if (/*!isImplicitAccess=*/CurrentUnpackingBits->getNextBit())
E->Base = Record.readSubExpr();
else
E->Base = nullptr;
E->OperatorLoc = readSourceLocation();
E->BaseType = Record.readType();
}
void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
E->UnresolvedLookupExprBits.RequiresADL = Record.readInt();
E->UnresolvedLookupExprBits.Overloaded = Record.readInt();
E->UnresolvedLookupExprBits.RequiresADL = CurrentUnpackingBits->getNextBit();
E->UnresolvedLookupExprBits.Overloaded = CurrentUnpackingBits->getNextBit();
E->NamingClass = readDeclAs<CXXRecordDecl>();
}
@ -2142,9 +2177,12 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
E->AssociatedDeclAndRef.setPointer(readDeclAs<Decl>());
E->AssociatedDeclAndRef.setInt(Record.readInt());
E->Index = Record.readInt();
E->PackIndex = Record.readInt();
E->AssociatedDeclAndRef.setInt(CurrentUnpackingBits->getNextBit());
E->Index = CurrentUnpackingBits->getNextBits(/*Width=*/12);
if (CurrentUnpackingBits->getNextBit())
E->PackIndex = Record.readInt();
else
E->PackIndex = 0;
E->SubstNonTypeTemplateParmExprBits.NameLoc = readSourceLocation();
E->Replacement = Record.readSubExpr();
}
@ -2836,11 +2874,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) NullStmt(Empty);
break;
case STMT_COMPOUND:
S = CompoundStmt::CreateEmpty(
Context, /*NumStmts=*/Record[ASTStmtReader::NumStmtFields],
/*HasFPFeatures=*/Record[ASTStmtReader::NumStmtFields + 1]);
case STMT_COMPOUND: {
unsigned NumStmts = Record[ASTStmtReader::NumStmtFields];
bool HasFPFeatures = Record[ASTStmtReader::NumStmtFields + 1];
S = CompoundStmt::CreateEmpty(Context, NumStmts, HasFPFeatures);
break;
}
case STMT_CASE:
S = CaseStmt::CreateEmpty(
@ -2862,13 +2901,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/*NumAttrs*/Record[ASTStmtReader::NumStmtFields]);
break;
case STMT_IF:
S = IfStmt::CreateEmpty(
Context,
/* HasElse=*/Record[ASTStmtReader::NumStmtFields],
/* HasVar=*/Record[ASTStmtReader::NumStmtFields + 1],
/* HasInit=*/Record[ASTStmtReader::NumStmtFields + 2]);
case STMT_IF: {
BitsUnpacker IfStmtBits(Record[ASTStmtReader::NumStmtFields]);
bool HasElse = IfStmtBits.getNextBit();
bool HasVar = IfStmtBits.getNextBit();
bool HasInit = IfStmtBits.getNextBit();
S = IfStmt::CreateEmpty(Context, HasElse, HasVar, HasInit);
break;
}
case STMT_SWITCH:
S = SwitchStmt::CreateEmpty(
@ -2945,17 +2985,19 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/*HasFunctionName*/ Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_DECL_REF:
S = DeclRefExpr::CreateEmpty(
Context,
/*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
/*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields + 2],
/*NumTemplateArgs=*/
Record[ASTStmtReader::NumExprFields + 2]
? Record[ASTStmtReader::NumExprFields + 7]
: 0);
case EXPR_DECL_REF: {
BitsUnpacker DeclRefExprBits(Record[ASTStmtReader::NumExprFields]);
DeclRefExprBits.advance(5);
bool HasFoundDecl = DeclRefExprBits.getNextBit();
bool HasQualifier = DeclRefExprBits.getNextBit();
bool HasTemplateKWAndArgsInfo = DeclRefExprBits.getNextBit();
unsigned NumTemplateArgs = HasTemplateKWAndArgsInfo
? Record[ASTStmtReader::NumExprFields + 1]
: 0;
S = DeclRefExpr::CreateEmpty(Context, HasQualifier, HasFoundDecl,
HasTemplateKWAndArgsInfo, NumTemplateArgs);
break;
}
case EXPR_INTEGER_LITERAL:
S = IntegerLiteral::Create(Context, Empty);
@ -2995,10 +3037,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/* NumExprs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_UNARY_OPERATOR:
S = UnaryOperator::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields]);
case EXPR_UNARY_OPERATOR: {
BitsUnpacker UnaryOperatorBits(Record[ASTStmtReader::NumStmtFields]);
UnaryOperatorBits.advance(ASTStmtReader::NumExprBits);
bool HasFPFeatures = UnaryOperatorBits.getNextBit();
S = UnaryOperator::CreateEmpty(Context, HasFPFeatures);
break;
}
case EXPR_OFFSETOF:
S = OffsetOfExpr::CreateEmpty(Context,
@ -3033,8 +3078,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CALL: {
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CallExprBits.advance(1);
auto HasFPFeatures = CallExprBits.getNextBit();
S = CallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures, Empty);
break;
@ -3045,22 +3091,32 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_MEMBER:
S = MemberExpr::CreateEmpty(Context, Record[ASTStmtReader::NumExprFields],
Record[ASTStmtReader::NumExprFields + 1],
Record[ASTStmtReader::NumExprFields + 2],
Record[ASTStmtReader::NumExprFields + 3]);
case EXPR_MEMBER: {
BitsUnpacker ExprMemberBits(Record[ASTStmtReader::NumExprFields]);
bool HasQualifier = ExprMemberBits.getNextBit();
bool HasFoundDecl = ExprMemberBits.getNextBit();
bool HasTemplateInfo = ExprMemberBits.getNextBit();
unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields + 1];
S = MemberExpr::CreateEmpty(Context, HasQualifier, HasFoundDecl,
HasTemplateInfo, NumTemplateArgs);
break;
}
case EXPR_BINARY_OPERATOR:
S = BinaryOperator::CreateEmpty(Context,
Record[ASTStmtReader::NumExprFields]);
case EXPR_BINARY_OPERATOR: {
BitsUnpacker BinaryOperatorBits(Record[ASTStmtReader::NumExprFields]);
BinaryOperatorBits.advance(/*Size of opcode*/ 6);
bool HasFPFeatures = BinaryOperatorBits.getNextBit();
S = BinaryOperator::CreateEmpty(Context, HasFPFeatures);
break;
}
case EXPR_COMPOUND_ASSIGN_OPERATOR:
S = CompoundAssignOperator::CreateEmpty(
Context, Record[ASTStmtReader::NumExprFields]);
case EXPR_COMPOUND_ASSIGN_OPERATOR: {
BitsUnpacker BinaryOperatorBits(Record[ASTStmtReader::NumExprFields]);
BinaryOperatorBits.advance(/*Size of opcode*/ 6);
bool HasFPFeatures = BinaryOperatorBits.getNextBit();
S = CompoundAssignOperator::CreateEmpty(Context, HasFPFeatures);
break;
}
case EXPR_CONDITIONAL_OPERATOR:
S = new (Context) ConditionalOperator(Empty);
@ -3070,19 +3126,23 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) BinaryConditionalOperator(Empty);
break;
case EXPR_IMPLICIT_CAST:
S = ImplicitCastExpr::CreateEmpty(
Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields],
/*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]);
case EXPR_IMPLICIT_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CastExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CastExprBits.advance(7);
bool HasFPFeatures = CastExprBits.getNextBit();
S = ImplicitCastExpr::CreateEmpty(Context, PathSize, HasFPFeatures);
break;
}
case EXPR_CSTYLE_CAST:
S = CStyleCastExpr::CreateEmpty(
Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields],
/*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]);
case EXPR_CSTYLE_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CastExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CastExprBits.advance(7);
bool HasFPFeatures = CastExprBits.getNextBit();
S = CStyleCastExpr::CreateEmpty(Context, PathSize, HasFPFeatures);
break;
}
case EXPR_COMPOUND_LITERAL:
S = new (Context) CompoundLiteralExpr(Empty);
@ -3777,8 +3837,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
}
case EXPR_CXX_OPERATOR_CALL: {
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CallExprBits.advance(1);
auto HasFPFeatures = CallExprBits.getNextBit();
S = CXXOperatorCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
Empty);
@ -3786,8 +3847,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
}
case EXPR_CXX_MEMBER_CALL: {
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CallExprBits.advance(1);
auto HasFPFeatures = CallExprBits.getNextBit();
S = CXXMemberCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
Empty);
@ -3814,22 +3876,26 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
/* NumArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_STATIC_CAST:
S = CXXStaticCastExpr::CreateEmpty(
Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields],
/*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]);
case EXPR_CXX_STATIC_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CastExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CastExprBits.advance(7);
bool HasFPFeatures = CastExprBits.getNextBit();
S = CXXStaticCastExpr::CreateEmpty(Context, PathSize, HasFPFeatures);
break;
}
case EXPR_CXX_DYNAMIC_CAST:
S = CXXDynamicCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
case EXPR_CXX_DYNAMIC_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
S = CXXDynamicCastExpr::CreateEmpty(Context, PathSize);
break;
}
case EXPR_CXX_REINTERPRET_CAST:
S = CXXReinterpretCastExpr::CreateEmpty(Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields]);
case EXPR_CXX_REINTERPRET_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
S = CXXReinterpretCastExpr::CreateEmpty(Context, PathSize);
break;
}
case EXPR_CXX_CONST_CAST:
S = CXXConstCastExpr::CreateEmpty(Context);
@ -3839,21 +3905,28 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = CXXAddrspaceCastExpr::CreateEmpty(Context);
break;
case EXPR_CXX_FUNCTIONAL_CAST:
S = CXXFunctionalCastExpr::CreateEmpty(
Context,
/*PathSize*/ Record[ASTStmtReader::NumExprFields],
/*HasFPFeatures*/ Record[ASTStmtReader::NumExprFields + 1]);
case EXPR_CXX_FUNCTIONAL_CAST: {
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CastExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CastExprBits.advance(7);
bool HasFPFeatures = CastExprBits.getNextBit();
S = CXXFunctionalCastExpr::CreateEmpty(Context, PathSize, HasFPFeatures);
break;
}
case EXPR_BUILTIN_BIT_CAST:
assert(Record[ASTStmtReader::NumExprFields] == 0 && "Wrong PathSize!");
case EXPR_BUILTIN_BIT_CAST: {
#ifndef NDEBUG
unsigned PathSize = Record[ASTStmtReader::NumExprFields];
assert(PathSize == 0 && "Wrong PathSize!");
#endif
S = new (Context) BuiltinBitCastExpr(Empty);
break;
}
case EXPR_USER_DEFINED_LITERAL: {
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CallExprBits.advance(1);
auto HasFPFeatures = CallExprBits.getNextBit();
S = UserDefinedLiteral::CreateEmpty(Context, NumArgs, HasFPFeatures,
Empty);
@ -3944,47 +4017,62 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER:
S = CXXDependentScopeMemberExpr::CreateEmpty(
Context,
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1],
/*HasFirstQualifierFoundInScope=*/
Record[ASTStmtReader::NumExprFields + 2]);
break;
case EXPR_CXX_DEPENDENT_SCOPE_MEMBER: {
unsigned NumTemplateArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker DependentScopeMemberBits(
Record[ASTStmtReader::NumExprFields + 1]);
bool HasTemplateKWAndArgsInfo = DependentScopeMemberBits.getNextBit();
case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF:
S = DependentScopeDeclRefExpr::CreateEmpty(Context,
/*HasTemplateKWAndArgsInfo=*/Record[ASTStmtReader::NumExprFields],
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields]
? Record[ASTStmtReader::NumExprFields + 1]
: 0);
bool HasFirstQualifierFoundInScope =
DependentScopeMemberBits.getNextBit();
S = CXXDependentScopeMemberExpr::CreateEmpty(
Context, HasTemplateKWAndArgsInfo, NumTemplateArgs,
HasFirstQualifierFoundInScope);
break;
}
case EXPR_CXX_DEPENDENT_SCOPE_DECL_REF: {
BitsUnpacker DependentScopeDeclRefBits(
Record[ASTStmtReader::NumStmtFields]);
DependentScopeDeclRefBits.advance(ASTStmtReader::NumExprBits);
bool HasTemplateKWAndArgsInfo = DependentScopeDeclRefBits.getNextBit();
unsigned NumTemplateArgs =
HasTemplateKWAndArgsInfo
? DependentScopeDeclRefBits.getNextBits(/*Width=*/16)
: 0;
S = DependentScopeDeclRefExpr::CreateEmpty(
Context, HasTemplateKWAndArgsInfo, NumTemplateArgs);
break;
}
case EXPR_CXX_UNRESOLVED_CONSTRUCT:
S = CXXUnresolvedConstructExpr::CreateEmpty(Context,
/*NumArgs=*/Record[ASTStmtReader::NumExprFields]);
break;
case EXPR_CXX_UNRESOLVED_MEMBER:
case EXPR_CXX_UNRESOLVED_MEMBER: {
auto NumResults = Record[ASTStmtReader::NumExprFields];
BitsUnpacker OverloadExprBits(Record[ASTStmtReader::NumExprFields + 1]);
auto HasTemplateKWAndArgsInfo = OverloadExprBits.getNextBit();
auto NumTemplateArgs = HasTemplateKWAndArgsInfo
? Record[ASTStmtReader::NumExprFields + 2]
: 0;
S = UnresolvedMemberExpr::CreateEmpty(
Context,
/*NumResults=*/Record[ASTStmtReader::NumExprFields] & ((1 << 14) - 1),
/*HasTemplateKWAndArgsInfo=*/
(Record[ASTStmtReader::NumExprFields] >> 14) & (0x1),
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] >> 14 &
((1 << 14) - 1));
Context, NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
break;
}
case EXPR_CXX_UNRESOLVED_LOOKUP:
case EXPR_CXX_UNRESOLVED_LOOKUP: {
auto NumResults = Record[ASTStmtReader::NumExprFields];
BitsUnpacker OverloadExprBits(Record[ASTStmtReader::NumExprFields + 1]);
auto HasTemplateKWAndArgsInfo = OverloadExprBits.getNextBit();
auto NumTemplateArgs = HasTemplateKWAndArgsInfo
? Record[ASTStmtReader::NumExprFields + 2]
: 0;
S = UnresolvedLookupExpr::CreateEmpty(
Context,
/*NumResults=*/Record[ASTStmtReader::NumExprFields] & ((1 << 14) - 1),
/*HasTemplateKWAndArgsInfo=*/
(Record[ASTStmtReader::NumExprFields] >> 14) & (0x1),
/*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields] >> 14 &
((1 << 14) - 1));
Context, NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
break;
}
case EXPR_TYPE_TRAIT:
S = TypeTraitExpr::CreateDeserialized(Context,
@ -4044,8 +4132,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case EXPR_CUDA_KERNEL_CALL: {
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields]);
auto NumArgs = CallExprBits.getNextBits(/*Width=*/16);
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);
CallExprBits.advance(1);
auto HasFPFeatures = CallExprBits.getNextBit();
S = CUDAKernelCallExpr::CreateEmpty(Context, NumArgs, HasFPFeatures,
Empty);

View file

@ -6003,12 +6003,17 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
BitsPacker DefinitionBits;
#define FIELD(Name, Width, Merge) DefinitionBits.addBits(Data.Name, Width);
#define FIELD(Name, Width, Merge) \
if (!DefinitionBits.canWriteNextNBits(Width)) { \
Record->push_back(DefinitionBits); \
DefinitionBits.reset(0); \
} \
DefinitionBits.addBits(Data.Name, Width);
#include "clang/AST/CXXRecordDeclDefinitionBits.def"
#undef FIELD
while (DefinitionBits.hasUnconsumedValues())
Record->push_back(DefinitionBits.getNextValue());
Record->push_back(DefinitionBits);
// getODRHash will compute the ODRHash if it has not been previously computed.
Record->push_back(D->getODRHash());
@ -6047,7 +6052,7 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
LambdaBits.addBits(Lambda.CaptureDefault, /*Width=*/2);
LambdaBits.addBits(Lambda.NumCaptures, /*Width=*/15);
LambdaBits.addBit(Lambda.HasKnownInternalLinkage);
Record->push_back(LambdaBits.getNextValue());
Record->push_back(LambdaBits);
Record->push_back(Lambda.NumExplicitCaptures);
Record->push_back(Lambda.ManglingNumber);
@ -6058,10 +6063,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) {
const LambdaCapture &Capture = Lambda.Captures.front()[I];
AddSourceLocation(Capture.getLocation());
BitsPacker CaptureBits;
CaptureBits.addBit(Capture.isImplicit());
CaptureBits.addBits(Capture.getCaptureKind(), /*Width=*/3);
Record->push_back(CaptureBits);
switch (Capture.getCaptureKind()) {
case LCK_StarThis:
case LCK_This:

View file

@ -321,15 +321,25 @@ void ASTDeclWriter::Visit(Decl *D) {
void ASTDeclWriter::VisitDecl(Decl *D) {
BitsPacker DeclBits;
DeclBits.addBit(D->getDeclContext() != D->getLexicalDeclContext());
DeclBits.addBit(D->isInvalidDecl());
DeclBits.addBit(D->hasAttrs());
DeclBits.addBit(D->isImplicit());
DeclBits.addBit(D->isUsed(false));
DeclBits.addBit(D->isReferenced());
DeclBits.addBit(D->isTopLevelDeclInObjCContainer());
DeclBits.addBits(D->getAccess(), /*BitWidth=*/2);
// The order matters here. It will be better to put the bit with higher
// probability to be 0 in the end of the bits.
//
// Since we're using VBR6 format to store it.
// It will be pretty effient if all the higher bits are 0.
// For example, if we need to pack 8 bits into a value and the stored value
// is 0xf0, the actual stored value will be 0b000111'110000, which takes 12
// bits actually. However, if we changed the order to be 0x0f, then we can
// store it as 0b001111, which takes 6 bits only now.
DeclBits.addBits((uint64_t)D->getModuleOwnershipKind(), /*BitWidth=*/3);
DeclBits.addBit(D->isReferenced());
DeclBits.addBit(D->isUsed(false));
DeclBits.addBits(D->getAccess(), /*BitWidth=*/2);
DeclBits.addBit(D->isImplicit());
DeclBits.addBit(D->getDeclContext() != D->getLexicalDeclContext());
DeclBits.addBit(D->hasAttrs());
DeclBits.addBit(D->isTopLevelDeclInObjCContainer());
DeclBits.addBit(D->isInvalidDecl());
Record.push_back(DeclBits);
Record.AddDeclRef(cast_or_null<Decl>(D->getDeclContext()));
@ -493,21 +503,13 @@ void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) {
Record.AddDeclRef(nullptr);
}
if (D->getDeclContext() == D->getLexicalDeclContext() &&
!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
!D->isInvalidDecl() && !D->isImplicit() && !D->hasExtInfo() &&
!D->getTypedefNameForAnonDecl() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!D->getIntegerTypeSourceInfo() &&
!D->getMemberSpecializationInfo() &&
!D->getIntegerTypeSourceInfo() && !D->getMemberSpecializationInfo() &&
!needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclEnumAbbrev();
@ -542,18 +544,11 @@ void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) {
if (!isa<CXXRecordDecl>(D))
Record.push_back(D->getODRHash());
if (D->getDeclContext() == D->getLexicalDeclContext() &&
!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->hasExtInfo() &&
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
!D->isImplicit() && !D->isInvalidDecl() && !D->hasExtInfo() &&
!D->getTypedefNameForAnonDecl() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
!D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!CXXRecordDecl::classofKind(D->getKind()) &&
!needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
@ -674,11 +669,16 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.AddDeclarationNameLoc(D->DNLoc, D->getDeclName());
Record.push_back(D->getIdentifierNamespace());
// The order matters here. It will be better to put the bit with higher
// probability to be 0 in the end of the bits. See the comments in VisitDecl
// for details.
BitsPacker FunctionDeclBits;
// FIXME: stable encoding
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
FunctionDeclBits.addBits((uint32_t)D->getStorageClass(), /*BitWidth=*/3);
FunctionDeclBits.addBit(D->isInlineSpecified());
FunctionDeclBits.addBit(D->isInlined());
FunctionDeclBits.addBit(D->hasSkippedBody());
FunctionDeclBits.addBit(D->isVirtualAsWritten());
FunctionDeclBits.addBit(D->isPure());
FunctionDeclBits.addBit(D->hasInheritedPrototype());
@ -689,14 +689,12 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
FunctionDeclBits.addBit(D->isDefaulted());
FunctionDeclBits.addBit(D->isExplicitlyDefaulted());
FunctionDeclBits.addBit(D->isIneligibleOrNotSelected());
FunctionDeclBits.addBit(D->hasImplicitReturnZero());
FunctionDeclBits.addBits((uint64_t)(D->getConstexprKind()), /*BitWidth=*/2);
FunctionDeclBits.addBit(D->usesSEHTry());
FunctionDeclBits.addBit(D->hasSkippedBody());
FunctionDeclBits.addBit(D->hasImplicitReturnZero());
FunctionDeclBits.addBit(D->isMultiVersion());
FunctionDeclBits.addBit(D->isLateTemplateParsed());
FunctionDeclBits.addBit(D->FriendConstraintRefersToEnclosingTemplate());
FunctionDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), 3);
FunctionDeclBits.addBit(D->usesSEHTry());
Record.push_back(FunctionDeclBits);
Record.AddSourceLocation(D->getEndLoc());
@ -1060,37 +1058,12 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
VisitRedeclarable(D);
VisitDeclaratorDecl(D);
// The order matters here. It will be better to put the bit with higher
// probability to be 0 in the end of the bits. See the comments in VisitDecl
// for details.
BitsPacker VarDeclBits;
VarDeclBits.addBits(D->getStorageClass(), /*BitWidth=*/3);
VarDeclBits.addBits(D->getTSCSpec(), /*BitWidth=*/2);
VarDeclBits.addBits(D->getInitStyle(), /*BitWidth=*/2);
VarDeclBits.addBit(D->isARCPseudoStrong());
bool HasDeducedType = false;
if (!isa<ParmVarDecl>(D)) {
VarDeclBits.addBit(D->isThisDeclarationADemotedDefinition());
VarDeclBits.addBit(D->isExceptionVariable());
VarDeclBits.addBit(D->isNRVOVariable());
VarDeclBits.addBit(D->isCXXForRangeDecl());
VarDeclBits.addBit(D->isObjCForDecl());
VarDeclBits.addBit(D->isInline());
VarDeclBits.addBit(D->isInlineSpecified());
VarDeclBits.addBit(D->isConstexpr());
VarDeclBits.addBit(D->isInitCapture());
VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope());
if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D))
VarDeclBits.addBits(llvm::to_underlying(IPD->getParameterKind()),
/*Width=*/3);
else
VarDeclBits.addBits(0, /*Width=*/3);
VarDeclBits.addBit(D->isEscapingByref());
HasDeducedType = D->getType()->getContainedDeducedType();
VarDeclBits.addBit(HasDeducedType);
}
VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()), /*BitWidth=*/3);
VarDeclBits.addBits(llvm::to_underlying(D->getLinkageInternal()),
/*BitWidth=*/3);
bool ModulesCodegen = false;
if (Writer.WritingModule && D->getStorageDuration() == SD_Static &&
@ -1103,10 +1076,41 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
(Writer.WritingModule->isInterfaceOrPartition() ||
(D->hasAttr<DLLExportAttr>() &&
Writer.Context->getLangOpts().BuildingPCHWithObjectFile)) &&
Writer.Context->GetGVALinkageForVariable(D) >= GVA_StrongExternal;
Writer.Context->GetGVALinkageForVariable(D) >= GVA_StrongExternal;
}
VarDeclBits.addBit(ModulesCodegen);
VarDeclBits.addBits(D->getStorageClass(), /*BitWidth=*/3);
VarDeclBits.addBits(D->getTSCSpec(), /*BitWidth=*/2);
VarDeclBits.addBits(D->getInitStyle(), /*BitWidth=*/2);
VarDeclBits.addBit(D->isARCPseudoStrong());
bool HasDeducedType = false;
if (!isa<ParmVarDecl>(D)) {
VarDeclBits.addBit(D->isThisDeclarationADemotedDefinition());
VarDeclBits.addBit(D->isExceptionVariable());
VarDeclBits.addBit(D->isNRVOVariable());
VarDeclBits.addBit(D->isCXXForRangeDecl());
VarDeclBits.addBit(D->isInline());
VarDeclBits.addBit(D->isInlineSpecified());
VarDeclBits.addBit(D->isConstexpr());
VarDeclBits.addBit(D->isInitCapture());
VarDeclBits.addBit(D->isPreviousDeclInSameBlockScope());
VarDeclBits.addBit(D->isEscapingByref());
HasDeducedType = D->getType()->getContainedDeducedType();
VarDeclBits.addBit(HasDeducedType);
if (const auto *IPD = dyn_cast<ImplicitParamDecl>(D))
VarDeclBits.addBits(llvm::to_underlying(IPD->getParameterKind()),
/*Width=*/3);
else
VarDeclBits.addBits(0, /*Width=*/3);
VarDeclBits.addBit(D->isObjCForDecl());
}
VarDeclBits.addBit(ModulesCodegen);
Record.push_back(VarDeclBits);
if (ModulesCodegen)
@ -1135,29 +1139,17 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) {
Record.push_back(VarNotTemplate);
}
if (D->getDeclContext() == D->getLexicalDeclContext() &&
!D->hasAttrs() &&
!D->isImplicit() &&
!D->isUsed(false) &&
!D->isInvalidDecl() &&
!D->isReferenced() &&
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
!D->isTopLevelDeclInObjCContainer() &&
D->getAccess() == AS_none &&
!D->isModulePrivate() &&
!needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() &&
D->getFirstDecl() == D->getMostRecentDecl() &&
D->getKind() == Decl::Var &&
!D->isInline() &&
!D->isConstexpr() &&
!D->isInitCapture() &&
!D->isPreviousDeclInSameBlockScope() &&
!D->isEscapingByref() &&
!HasDeducedType &&
D->getStorageDuration() != SD_Static &&
!D->getDescribedVarTemplate() &&
!D->getMemberSpecializationInfo())
!D->hasExtInfo() && D->getFirstDecl() == D->getMostRecentDecl() &&
D->getKind() == Decl::Var && !D->isInline() && !D->isConstexpr() &&
!D->isInitCapture() && !D->isPreviousDeclInSameBlockScope() &&
!D->isEscapingByref() && !HasDeducedType &&
D->getStorageDuration() != SD_Static && !D->getDescribedVarTemplate() &&
!D->getMemberSpecializationInfo() && !D->isObjCForDecl() &&
!isa<ImplicitParamDecl>(D) && !D->isEscapingByref())
AbbrevToUse = Writer.getDeclVarAbbrev();
Code = serialization::DECL_VAR;
@ -1193,14 +1185,10 @@ void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
// we dynamically check for the properties that we optimize for, but don't
// know are true of all PARM_VAR_DECLs.
if (D->getDeclContext() == D->getLexicalDeclContext() && !D->hasAttrs() &&
!D->hasExtInfo() && !D->isImplicit() && !D->isUsed(false) &&
!D->isInvalidDecl() && !D->isReferenced() && D->getAccess() == AS_none &&
!D->isModulePrivate() && D->getStorageClass() == 0 &&
!D->hasExtInfo() && D->getStorageClass() == 0 && !D->isInvalidDecl() &&
!D->isTopLevelDeclInObjCContainer() &&
D->getInitStyle() == VarDecl::CInit && // Can params have anything else?
D->getFunctionScopeDepth() == 0 && D->getObjCDeclQualifier() == 0 &&
!D->isKNRPromoted() && !D->isExplicitObjectParameter() &&
!D->hasInheritedDefaultArg() && D->getInit() == nullptr &&
!D->hasUninstantiatedDefaultArg()) // No default expr.
D->getInit() == nullptr) // No default expr.
AbbrevToUse = Writer.getDeclParmVarAbbrev();
// Check things we know are true of *every* PARM_VAR_DECL, which is more than
@ -1403,6 +1391,13 @@ void ASTDeclWriter::VisitUsingShadowDecl(UsingShadowDecl *D) {
Record.push_back(D->getIdentifierNamespace());
Record.AddDeclRef(D->UsingOrNextShadow);
Record.AddDeclRef(Context.getInstantiatedFromUsingShadowDecl(D));
if (D->getDeclContext() == D->getLexicalDeclContext() &&
D->getFirstDecl() == D->getMostRecentDecl() && !D->hasAttrs() &&
!needsAnonymousDeclarationNumber(D) &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclUsingShadowAbbrev();
Code = serialization::DECL_USING_SHADOW;
}
@ -1507,10 +1502,32 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
D->getFirstDecl() == D->getMostRecentDecl() && !D->isInvalidDecl() &&
!D->hasAttrs() && !D->isTopLevelDeclInObjCContainer() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier &&
!D->hasExtInfo() && !D->hasInheritedPrototype() &&
D->hasWrittenPrototype() &&
D->getTemplatedKind() == FunctionDecl::TK_NonTemplate)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev();
!D->hasExtInfo() && !D->isExplicitlyDefaulted()) {
if (D->getTemplatedKind() == FunctionDecl::TK_NonTemplate ||
D->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate ||
D->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
D->getTemplatedKind() == FunctionDecl::TK_DependentNonTemplate)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
else if (D->getTemplatedKind() ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
FunctionTemplateSpecializationInfo *FTSInfo =
D->getTemplateSpecializationInfo();
if (FTSInfo->TemplateArguments->size() == 1) {
const TemplateArgument &TA = FTSInfo->TemplateArguments->get(0);
if (TA.getKind() == TemplateArgument::Type &&
!FTSInfo->TemplateArgumentsAsWritten &&
!FTSInfo->getMemberSpecializationInfo())
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
}
} else if (D->getTemplatedKind() ==
FunctionDecl::TK_DependentFunctionTemplateSpecialization) {
DependentFunctionTemplateSpecializationInfo *DFTSInfo =
D->getDependentSpecializationInfo();
if (!DFTSInfo->TemplateArgumentsAsWritten)
AbbrevToUse = Writer.getDeclCXXMethodAbbrev(D->getTemplatedKind());
}
}
Code = serialization::DECL_CXX_METHOD;
}
@ -1782,7 +1799,7 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
Record.push_back(D->wasDeclaredWithTypename());
const TypeConstraint *TC = D->getTypeConstraint();
Record.push_back(TC != nullptr);
assert((bool)TC == D->hasTypeConstraint());
if (TC) {
auto *CR = TC->getConceptReference();
Record.push_back(CR != nullptr);
@ -1800,6 +1817,13 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
if (OwnsDefaultArg)
Record.AddTypeSourceInfo(D->getDefaultArgumentInfo());
if (!TC && !OwnsDefaultArg &&
D->getDeclContext() == D->getLexicalDeclContext() &&
!D->isInvalidDecl() && !D->hasAttrs() &&
!D->isTopLevelDeclInObjCContainer() && !D->isImplicit() &&
D->getDeclName().getNameKind() == DeclarationName::Identifier)
AbbrevToUse = Writer.getDeclTemplateTypeParmAbbrev();
Code = serialization::DECL_TEMPLATE_TYPE_PARM;
}
@ -2031,6 +2055,106 @@ void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) {
// ASTWriter Implementation
//===----------------------------------------------------------------------===//
namespace {
template <FunctionDecl::TemplatedKind Kind>
std::shared_ptr<llvm::BitCodeAbbrev>
getFunctionDeclAbbrev(serialization::DeclCode Code) {
using namespace llvm;
auto Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(Code));
// RedeclarableDecl
Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
Abv->Add(BitCodeAbbrevOp(Kind));
if constexpr (Kind == FunctionDecl::TK_NonTemplate) {
} else if constexpr (Kind == FunctionDecl::TK_FunctionTemplate) {
// DescribedFunctionTemplate
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
} else if constexpr (Kind == FunctionDecl::TK_DependentNonTemplate) {
// Instantiated From Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
} else if constexpr (Kind == FunctionDecl::TK_MemberSpecialization) {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InstantiatedFrom
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
3)); // TemplateSpecializationKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Specialized Location
} else if constexpr (Kind ==
FunctionDecl::TK_FunctionTemplateSpecialization) {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
3)); // TemplateSpecializationKind
Abv->Add(BitCodeAbbrevOp(1)); // Template Argument Size
Abv->Add(BitCodeAbbrevOp(TemplateArgument::Type)); // Template Argument Kind
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Template Argument Type
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Is Defaulted
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SourceLocation
Abv->Add(BitCodeAbbrevOp(0));
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Canonical Decl of template
} else if constexpr (Kind == FunctionDecl::
TK_DependentFunctionTemplateSpecialization) {
// Candidates of specialization
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(0)); // TemplateArgumentsAsWritten
} else {
llvm_unreachable("Unknown templated kind?");
}
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
8)); // Packed DeclBits: ModuleOwnershipKind,
// isUsed, isReferenced, AccessSpecifier,
// isImplicit
//
// The following bits should be 0:
// HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer,
// isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
// FunctionDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
27)); // Packed Function Bits: StorageClass, Inline, InlineSpecified,
// VirtualAsWritten, Pure, HasInheritedProto, HasWrittenProto,
// Deleted, Trivial, TrivialForCall, Defaulted, ExplicitlyDefaulted,
// IsIneligibleOrNotSelected, ImplicitReturnZero, Constexpr,
// UsesSEHTry, SkippedBody, MultiVersion, LateParsed,
// FriendConstraintRefersToEnclosingTemplate, Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash
// This Array slurps the rest of the record. Fortunately we want to encode
// (nearly) all the remaining (variable number of) fields in the same way.
//
// This is:
// NumParams and Params[] from FunctionDecl, and
// NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
//
// Add an AbbrevOp for 'size then elements' and use it here.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
return Abv;
}
template <FunctionDecl::TemplatedKind Kind>
std::shared_ptr<llvm::BitCodeAbbrev> getCXXMethodAbbrev() {
return getFunctionDeclAbbrev<Kind>(serialization::DECL_CXX_METHOD);
}
} // namespace
void ASTWriter::WriteDeclAbbrevs() {
using namespace llvm;
@ -2041,10 +2165,13 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::DECL_FIELD));
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
7)); // Packed DeclBits: ModuleOwnershipKind,
// isUsed, isReferenced, AccessSpecifier,
//
// The following bits should be 0:
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer,
// isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@ -2104,10 +2231,13 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
7)); // Packed DeclBits: ModuleOwnershipKind,
// isUsed, isReferenced, AccessSpecifier,
//
// The following bits should be 0:
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer,
// isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@ -2145,10 +2275,13 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
7)); // Packed DeclBits: ModuleOwnershipKind,
// isUsed, isReferenced, AccessSpecifier,
//
// The following bits should be 0:
// isImplicit, HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer,
// isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@ -2193,10 +2326,11 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
8)); // Packed DeclBits: ModuleOwnershipKind, isUsed,
// isReferenced, AccessSpecifier,
// HasStandaloneLexicalDC, HasAttrs, isImplicit,
// TopLevelDeclInObjCContainer,
// isInvalidDecl,
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@ -2233,10 +2367,11 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
7)); // Packed DeclBits: ModuleOwnershipKind,
// isReferenced, isUsed, AccessSpecifier. Other
// higher bits should be 0: isImplicit,
// HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer, isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
@ -2277,12 +2412,13 @@ void ASTWriter::WriteDeclAbbrevs() {
// VarDecl
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
27)); // Packed Var Decl bits: SClass, TSCSpec, InitStyle,
21)); // Packed Var Decl bits: Linkage, ModulesCodegen,
// SClass, TSCSpec, InitStyle,
// isARCPseudoStrong, IsThisDeclarationADemotedDefinition,
// isExceptionVariable, isNRVOVariable, isCXXForRangeDecl,
// isObjCForDecl, isInline, isInlineSpecified, isConstexpr,
// isInitCapture, isPrevDeclInSameScope, ImplicitParamKind,
// EscapingByref, HasDeducedType, Linkage, ModulesCodegen
// isInline, isInlineSpecified, isConstexpr,
// isInitCapture, isPrevDeclInSameScope,
// EscapingByref, HasDeducedType, ImplicitParamKind, isObjCForDecl
Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
@ -2290,71 +2426,84 @@ void ASTWriter::WriteDeclAbbrevs() {
DeclVarAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for DECL_CXX_METHOD
DeclCXXMethodAbbrev =
Stream.EmitAbbrev(getCXXMethodAbbrev<FunctionDecl::TK_NonTemplate>());
DeclTemplateCXXMethodAbbrev = Stream.EmitAbbrev(
getCXXMethodAbbrev<FunctionDecl::TK_FunctionTemplate>());
DeclDependentNonTemplateCXXMethodAbbrev = Stream.EmitAbbrev(
getCXXMethodAbbrev<FunctionDecl::TK_DependentNonTemplate>());
DeclMemberSpecializedCXXMethodAbbrev = Stream.EmitAbbrev(
getCXXMethodAbbrev<FunctionDecl::TK_MemberSpecialization>());
DeclTemplateSpecializedCXXMethodAbbrev = Stream.EmitAbbrev(
getCXXMethodAbbrev<FunctionDecl::TK_FunctionTemplateSpecialization>());
DeclDependentSpecializationCXXMethodAbbrev = Stream.EmitAbbrev(
getCXXMethodAbbrev<
FunctionDecl::TK_DependentFunctionTemplateSpecialization>());
// Abbreviation for DECL_TEMPLATE_TYPE_PARM
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CXX_METHOD));
// RedeclarableDecl
Abv->Add(BitCodeAbbrevOp(0)); // CanonicalDecl
// FIXME: Implement abbreviation for other template kinds.
Abv->Add(BitCodeAbbrevOp(FunctionDecl::TK_NonTemplate)); // TemplateKind
Abv->Add(BitCodeAbbrevOp(serialization::DECL_TEMPLATE_TYPE_PARM));
Abv->Add(BitCodeAbbrevOp(0)); // hasTypeConstraint
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
7)); // Packed DeclBits: ModuleOwnershipKind,
// isReferenced, isUsed, AccessSpecifier. Other
// higher bits should be 0: isImplicit,
// HasStandaloneLexicalDC, HasAttrs,
// TopLevelDeclInObjCContainer, isInvalidDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0));
// TypeDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type Ref
// TemplateTypeParmDecl
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // wasDeclaredWithTypename
Abv->Add(BitCodeAbbrevOp(0)); // OwnsDefaultArg
DeclTemplateTypeParmAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for DECL_USING_SHADOW
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_USING_SHADOW));
// Redeclarable
Abv->Add(BitCodeAbbrevOp(0)); // No redeclaration
// Decl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed,
12)); // Packed DeclBits: HasStandaloneLexicalDC,
// isInvalidDecl, HasAttrs, isImplicit, isUsed,
// isReferenced, TopLevelDeclInObjCContainer,
// AccessSpecifier, ModuleOwnershipKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclContext
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // SubmoduleID
// NamedDecl
Abv->Add(BitCodeAbbrevOp(DeclarationName::Identifier)); // NameKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Identifier
Abv->Add(BitCodeAbbrevOp(0)); // AnonDeclNumber
// ValueDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DeclaratorDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // InnerLocStart
Abv->Add(BitCodeAbbrevOp(0)); // HasExtInfo
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TSIType
// FunctionDecl
Abv->Add(BitCodeAbbrevOp(0)); // NameKind = Identifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Name
Abv->Add(BitCodeAbbrevOp(0));
// UsingShadowDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // TargetDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 11)); // IDNS
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
27)); // Packed Function Bits: StorageClass, Inline, InlineSpecified,
// VirtualAsWritten, Pure, HasInheritedProto, HasWrittenProto,
// Deleted, Trivial, TrivialForCall, Defaulted, ExplicitlyDefaulted,
// IsIneligibleOrNotSelected, ImplicitReturnZero, Constexpr,
// UsesSEHTry, SkippedBody, MultiVersion, LateParsed,
// FriendConstraintRefersToEnclosingTemplate, Linkage
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LocEnd
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Default
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // ODRHash
// This Array slurps the rest of the record. Fortunately we want to encode
// (nearly) all the remaining (variable number of) fields in the same way.
//
// This is:
// NumParams and Params[] from FunctionDecl, and
// NumOverriddenMethods, OverriddenMethods[] from CXXMethodDecl.
//
// Add an AbbrevOp for 'size then elements' and use it here.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6));
DeclCXXMethodAbbrev = Stream.EmitAbbrev(std::move(Abv));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // UsingOrNextShadow
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR,
6)); // InstantiatedFromUsingShadowDecl
DeclUsingShadowAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_DECL_REF
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_DECL_REF));
//Stmt
// Expr
// Stmt
// Expr
// PackingBits: DependenceKind, ValueKind. ObjectKind should be 0.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 7));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DependenceKind, ValueKind, ObjectKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//DeclRefExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HasQualifier
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //GetDeclFound
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //ExplicitTemplateArgs
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //HadMultipleCandidates
Abv->Add(BitCodeAbbrevOp(0)); // RefersToEnclosingVariableOrCapture
Abv->Add(BitCodeAbbrevOp(0)); // NonOdrUseReason
Abv->Add(BitCodeAbbrevOp(0)); // IsImmediateEscalating
// DeclRefExpr
// Packing Bits: , HadMultipleCandidates, RefersToEnclosingVariableOrCapture,
// IsImmediateEscalating, NonOdrUseReason.
// GetDeclFound, HasQualifier and ExplicitTemplateArgs should be 0.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // DeclRef
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
DeclRefExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
@ -2364,10 +2513,10 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_INTEGER_LITERAL));
//Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DependenceKind, ValueKind, ObjectKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//Integer Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// Integer Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
Abv->Add(BitCodeAbbrevOp(32)); // Bit Width
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Value
@ -2378,10 +2527,10 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CHARACTER_LITERAL));
//Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DependenceKind, ValueKind, ObjectKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
//Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// Character Literal
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // getKind
@ -2392,17 +2541,108 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_IMPLICIT_CAST));
// Stmt
// Expr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// DependenceKind, ValueKind, ObjectKind
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// CastExpr
Abv->Add(BitCodeAbbrevOp(0)); // PathSize
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasFPFeatures
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 6)); // CastKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // PartOfExplicitCast
// Packing Bits: CastKind, StoredFPFeatures, isPartOfExplicitCast
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 9));
// ImplicitCastExpr
ExprImplicitCastAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_BINARY_OPERATOR
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_BINARY_OPERATOR));
// Stmt
// Expr
// Packing Bits: DependenceKind. ValueKind and ObjectKind should
// be 0 in this case.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// BinaryOperator
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpCode and HasFPFeatures
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
BinaryOperatorAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_COMPOUND_ASSIGN_OPERATOR
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_COMPOUND_ASSIGN_OPERATOR));
// Stmt
// Expr
// Packing Bits: DependenceKind. ValueKind and ObjectKind should
// be 0 in this case.
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 5));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// BinaryOperator
// Packing Bits: OpCode. The HasFPFeatures bit should be 0
Abv->Add(
BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // OpCode and HasFPFeatures
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
// CompoundAssignOperator
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // LHSType
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Result Type
CompoundAssignOperatorAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_CALL
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CALL));
// Stmt
// Expr
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// CallExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
CallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_CXX_OPERATOR_CALL
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CXX_OPERATOR_CALL));
// Stmt
// Expr
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// CallExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
// CXXOperatorCallExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Operator Kind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
CXXOperatorCallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for EXPR_CXX_MEMBER_CALL
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::EXPR_CXX_MEMBER_CALL));
// Stmt
// Expr
// Packing Bits: DependenceKind, ValueKind, ObjectKind,
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 10));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Type
// CallExpr
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // NumArgs
Abv->Add(BitCodeAbbrevOp(0)); // ADLCallKind
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
// CXXMemberCallExpr
CXXMemberCallExprAbbrev = Stream.EmitAbbrev(std::move(Abv));
// Abbreviation for STMT_COMPOUND
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::STMT_COMPOUND));
// Stmt
// CompoundStmt
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Num Stmts
Abv->Add(BitCodeAbbrevOp(0)); // hasStoredFPFeatures
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Source Location
CompoundStmtAbbrev = Stream.EmitAbbrev(std::move(Abv));
Abv = std::make_shared<BitCodeAbbrev>();
Abv->Add(BitCodeAbbrevOp(serialization::DECL_CONTEXT_LEXICAL));
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob));

View file

@ -37,15 +37,70 @@ namespace clang {
serialization::StmtCode Code;
unsigned AbbrevToUse;
/// A helper that can help us to write a packed bit across function
/// calls. For example, we may write seperate bits in seperate functions:
///
/// void VisitA(A* a) {
/// Record.push_back(a->isSomething());
/// }
///
/// void Visitb(B *b) {
/// VisitA(b);
/// Record.push_back(b->isAnother());
/// }
///
/// In such cases, it'll be better if we can pack these 2 bits. We achieve
/// this by writing a zero value in `VisitA` and recorded that first and add
/// the new bit to the recorded value.
class PakedBitsWriter {
public:
PakedBitsWriter(ASTRecordWriter &Record) : RecordRef(Record) {}
~PakedBitsWriter() { assert(!CurrentIndex); }
void addBit(bool Value) {
assert(CurrentIndex && "Writing Bits without recording first!");
PackingBits.addBit(Value);
}
void addBits(uint32_t Value, uint32_t BitsWidth) {
assert(CurrentIndex && "Writing Bits without recording first!");
PackingBits.addBits(Value, BitsWidth);
}
void writeBits() {
if (!CurrentIndex)
return;
RecordRef[*CurrentIndex] = (uint32_t)PackingBits;
CurrentIndex = std::nullopt;
PackingBits.reset(0);
}
void updateBits() {
writeBits();
CurrentIndex = RecordRef.size();
RecordRef.push_back(0);
}
private:
BitsPacker PackingBits;
ASTRecordWriter &RecordRef;
std::optional<unsigned> CurrentIndex;
};
PakedBitsWriter CurrentPackingBits;
public:
ASTStmtWriter(ASTWriter &Writer, ASTWriter::RecordData &Record)
: Writer(Writer), Record(Writer, Record),
Code(serialization::STMT_NULL_PTR), AbbrevToUse(0) {}
Code(serialization::STMT_NULL_PTR), AbbrevToUse(0),
CurrentPackingBits(this->Record) {}
ASTStmtWriter(const ASTStmtWriter&) = delete;
ASTStmtWriter &operator=(const ASTStmtWriter &) = delete;
uint64_t Emit() {
CurrentPackingBits.writeBits();
assert(Code != serialization::STMT_NULL_PTR &&
"unhandled sub-statement writing AST file");
return Record.EmitStmt(Code, AbbrevToUse);
@ -82,14 +137,20 @@ void ASTStmtWriter::VisitNullStmt(NullStmt *S) {
void ASTStmtWriter::VisitCompoundStmt(CompoundStmt *S) {
VisitStmt(S);
Record.push_back(S->size());
Record.push_back(S->hasStoredFPFeatures());
for (auto *CS : S->body())
Record.AddStmt(CS);
if (S->hasStoredFPFeatures())
Record.push_back(S->getStoredFPFeatures().getAsOpaqueInt());
Record.AddSourceLocation(S->getLBracLoc());
Record.AddSourceLocation(S->getRBracLoc());
if (!S->hasStoredFPFeatures())
AbbrevToUse = Writer.getCompoundStmtAbbrev();
Code = serialization::STMT_COMPOUND;
}
@ -143,9 +204,11 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) {
bool HasVar = S->getConditionVariableDeclStmt() != nullptr;
bool HasInit = S->getInit() != nullptr;
Record.push_back(HasElse);
Record.push_back(HasVar);
Record.push_back(HasInit);
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(HasElse);
CurrentPackingBits.addBit(HasVar);
CurrentPackingBits.addBit(HasInit);
Record.push_back(static_cast<uint64_t>(S->getStatementKind()));
Record.AddStmt(S->getCond());
Record.AddStmt(S->getThen());
@ -548,15 +611,13 @@ void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
void ASTStmtWriter::VisitExpr(Expr *E) {
VisitStmt(E);
CurrentPackingBits.updateBits();
CurrentPackingBits.addBits(E->getDependence(), /*BitsWidth=*/5);
CurrentPackingBits.addBits(E->getValueKind(), /*BitsWidth=*/2);
CurrentPackingBits.addBits(E->getObjectKind(), /*BitsWidth=*/3);
Record.AddTypeRef(E->getType());
BitsPacker ExprBits;
ExprBits.addBits(E->getDependence(), /*BitsWidth=*/5);
ExprBits.addBits(E->getValueKind(), /*BitsWidth=*/2);
ExprBits.addBits(E->getObjectKind(), /*BitsWidth=*/3);
Record.push_back(ExprBits);
}
void ASTStmtWriter::VisitConstantExpr(ConstantExpr *E) {
@ -612,13 +673,15 @@ void ASTStmtWriter::VisitPredefinedExpr(PredefinedExpr *E) {
void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
VisitExpr(E);
Record.push_back(E->hasQualifier());
Record.push_back(E->getDecl() != E->getFoundDecl());
Record.push_back(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->refersToEnclosingVariableOrCapture());
Record.push_back(E->isNonOdrUse());
Record.push_back(E->isImmediateEscalating());
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(E->hadMultipleCandidates());
CurrentPackingBits.addBit(E->refersToEnclosingVariableOrCapture());
CurrentPackingBits.addBits(E->isNonOdrUse(), /*Width=*/2);
CurrentPackingBits.addBit(E->isImmediateEscalating());
CurrentPackingBits.addBit(E->getDecl() != E->getFoundDecl());
CurrentPackingBits.addBit(E->hasQualifier());
CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo());
if (E->hasTemplateKWAndArgsInfo()) {
unsigned NumTemplateArgs = E->getNumTemplateArgs();
@ -629,9 +692,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
if ((!E->hasTemplateKWAndArgsInfo()) && (!E->hasQualifier()) &&
(E->getDecl() == E->getFoundDecl()) &&
nk == DeclarationName::Identifier &&
!E->refersToEnclosingVariableOrCapture() && !E->isNonOdrUse() &&
!E->isImmediateEscalating()) {
nk == DeclarationName::Identifier && E->getObjectKind() == OK_Ordinary) {
AbbrevToUse = Writer.getDeclRefExprAbbrev();
}
@ -742,11 +803,13 @@ void ASTStmtWriter::VisitUnaryOperator(UnaryOperator *E) {
bool HasFPFeatures = E->hasStoredFPFeatures();
// Write this first for easy access when deserializing, as they affect the
// size of the UnaryOperator.
Record.push_back(HasFPFeatures);
CurrentPackingBits.addBit(HasFPFeatures);
Record.AddStmt(E->getSubExpr());
Record.push_back(E->getOpcode()); // FIXME: stable encoding
CurrentPackingBits.addBits(E->getOpcode(),
/*Width=*/5); // FIXME: stable encoding
Record.AddSourceLocation(E->getOperatorLoc());
Record.push_back(E->canOverflow());
CurrentPackingBits.addBit(E->canOverflow());
if (HasFPFeatures)
Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
Code = serialization::EXPR_UNARY_OPERATOR;
@ -872,12 +935,10 @@ void ASTStmtWriter::VisitOMPIteratorExpr(OMPIteratorExpr *E) {
void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
VisitExpr(E);
BitsPacker CallExprBits;
// 16 bits should be sufficient to store the number args;
CallExprBits.addBits(E->getNumArgs(), /*BitsWidth=*/16);
CallExprBits.addBit(E->hasStoredFPFeatures());
CallExprBits.addBit(static_cast<bool>(E->getADLCallKind()));
Record.push_back(CallExprBits);
Record.push_back(E->getNumArgs());
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(static_cast<bool>(E->getADLCallKind()));
CurrentPackingBits.addBit(E->hasStoredFPFeatures());
Record.AddSourceLocation(E->getRParenLoc());
Record.AddStmt(E->getCallee());
@ -887,6 +948,11 @@ void ASTStmtWriter::VisitCallExpr(CallExpr *E) {
if (E->hasStoredFPFeatures())
Record.push_back(E->getFPFeatures().getAsOpaqueInt());
if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()) &&
E->getStmtClass() == Stmt::CallExprClass)
AbbrevToUse = Writer.getCallExprAbbrev();
Code = serialization::EXPR_CALL;
}
@ -913,9 +979,10 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
// Write these first for easy access when deserializing, as they affect the
// size of the MemberExpr.
Record.push_back(HasQualifier);
Record.push_back(HasFoundDecl);
Record.push_back(HasTemplateInfo);
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(HasQualifier);
CurrentPackingBits.addBit(HasFoundDecl);
CurrentPackingBits.addBit(HasTemplateInfo);
Record.push_back(NumTemplateArgs);
Record.AddStmt(E->getBase());
@ -923,15 +990,15 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
Record.AddDeclarationNameLoc(E->MemberDNLoc,
E->getMemberDecl()->getDeclName());
Record.AddSourceLocation(E->getMemberLoc());
Record.push_back(E->isArrow());
Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->isNonOdrUse());
CurrentPackingBits.addBit(E->isArrow());
CurrentPackingBits.addBit(E->hadMultipleCandidates());
CurrentPackingBits.addBits(E->isNonOdrUse(), /*Width=*/2);
Record.AddSourceLocation(E->getOperatorLoc());
if (HasFoundDecl) {
DeclAccessPair FoundDecl = E->getFoundDecl();
Record.AddDeclRef(FoundDecl.getDecl());
Record.push_back(FoundDecl.getAccess());
CurrentPackingBits.addBits(FoundDecl.getAccess(), /*BitWidth=*/2);
}
if (HasQualifier)
@ -971,10 +1038,13 @@ void ASTStmtWriter::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
void ASTStmtWriter::VisitCastExpr(CastExpr *E) {
VisitExpr(E);
Record.push_back(E->path_size());
Record.push_back(E->hasStoredFPFeatures());
CurrentPackingBits.updateBits();
// 7 bits should be enough to store the casting kinds.
CurrentPackingBits.addBits(E->getCastKind(), /*Width=*/7);
CurrentPackingBits.addBit(E->hasStoredFPFeatures());
Record.AddStmt(E->getSubExpr());
Record.push_back(E->getCastKind()); // FIXME: stable encoding
for (CastExpr::path_iterator
PI = E->path_begin(), PE = E->path_end(); PI != PE; ++PI)
@ -986,16 +1056,23 @@ void ASTStmtWriter::VisitCastExpr(CastExpr *E) {
void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) {
VisitExpr(E);
bool HasFPFeatures = E->hasStoredFPFeatures();
// Write this first for easy access when deserializing, as they affect the
// size of the UnaryOperator.
Record.push_back(HasFPFeatures);
Record.push_back(E->getOpcode()); // FIXME: stable encoding
CurrentPackingBits.updateBits();
CurrentPackingBits.addBits(E->getOpcode(), /*Width=*/6);
bool HasFPFeatures = E->hasStoredFPFeatures();
CurrentPackingBits.addBit(HasFPFeatures);
Record.AddStmt(E->getLHS());
Record.AddStmt(E->getRHS());
Record.AddSourceLocation(E->getOperatorLoc());
if (HasFPFeatures)
Record.push_back(E->getStoredFPFeatures().getAsOpaqueInt());
if (!HasFPFeatures && E->getValueKind() == VK_PRValue &&
E->getObjectKind() == OK_Ordinary)
AbbrevToUse = Writer.getBinaryOperatorAbbrev();
Code = serialization::EXPR_BINARY_OPERATOR;
}
@ -1003,6 +1080,11 @@ void ASTStmtWriter::VisitCompoundAssignOperator(CompoundAssignOperator *E) {
VisitBinaryOperator(E);
Record.AddTypeRef(E->getComputationLHSType());
Record.AddTypeRef(E->getComputationResultType());
if (!E->hasStoredFPFeatures() && E->getValueKind() == VK_PRValue &&
E->getObjectKind() == OK_Ordinary)
AbbrevToUse = Writer.getCompoundAssignOperatorAbbrev();
Code = serialization::EXPR_COMPOUND_ASSIGN_OPERATOR;
}
@ -1031,7 +1113,7 @@ ASTStmtWriter::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) {
void ASTStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
VisitCastExpr(E);
Record.push_back(E->isPartOfExplicitCast());
CurrentPackingBits.addBit(E->isPartOfExplicitCast());
if (E->path_size() == 0 && !E->hasStoredFPFeatures())
AbbrevToUse = Writer.getExprImplicitCastAbbrev();
@ -1588,11 +1670,19 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
VisitCallExpr(E);
Record.push_back(E->getOperator());
Record.AddSourceRange(E->Range);
if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()))
AbbrevToUse = Writer.getCXXOperatorCallExprAbbrev();
Code = serialization::EXPR_CXX_OPERATOR_CALL;
}
void ASTStmtWriter::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
VisitCallExpr(E);
if (!E->hasStoredFPFeatures() && !static_cast<bool>(E->getADLCallKind()))
AbbrevToUse = Writer.getCXXMemberCallExprAbbrev();
Code = serialization::EXPR_CXX_MEMBER_CALL;
}
@ -1673,7 +1763,9 @@ void ASTStmtWriter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E)
void ASTStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
VisitExplicitCastExpr(E);
Record.AddSourceRange(SourceRange(E->getOperatorLoc(), E->getRParenLoc()));
Record.AddSourceRange(E->getAngleBrackets());
CurrentPackingBits.addBit(E->getAngleBrackets().isValid());
if (E->getAngleBrackets().isValid())
Record.AddSourceRange(E->getAngleBrackets());
}
void ASTStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
@ -1750,6 +1842,7 @@ void ASTStmtWriter::VisitCXXThisExpr(CXXThisExpr *E) {
VisitExpr(E);
Record.AddSourceLocation(E->getLocation());
Record.push_back(E->isImplicit());
Code = serialization::EXPR_CXX_THIS;
}
@ -1883,10 +1976,10 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
// Don't emit anything here (or if you do you will have to update
// the corresponding deserialization function).
Record.push_back(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->getNumTemplateArgs());
Record.push_back(E->hasFirstQualifierFoundInScope());
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo());
CurrentPackingBits.addBit(E->hasFirstQualifierFoundInScope());
if (E->hasTemplateKWAndArgsInfo()) {
const ASTTemplateKWAndArgsInfo &ArgInfo =
@ -1895,14 +1988,15 @@ void ASTStmtWriter::VisitCXXDependentScopeMemberExpr(
E->getTrailingObjects<TemplateArgumentLoc>());
}
Record.push_back(E->isArrow());
Record.AddSourceLocation(E->getOperatorLoc());
CurrentPackingBits.addBit(E->isArrow());
Record.AddTypeRef(E->getBaseType());
Record.AddNestedNameSpecifierLoc(E->getQualifierLoc());
CurrentPackingBits.addBit(!E->isImplicitAccess());
if (!E->isImplicitAccess())
Record.AddStmt(E->getBase());
else
Record.AddStmt(nullptr);
Record.AddSourceLocation(E->getOperatorLoc());
if (E->hasFirstQualifierFoundInScope())
Record.AddDeclRef(E->getFirstQualifierFoundInScope());
@ -1917,12 +2011,14 @@ ASTStmtWriter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
// Don't emit anything here, HasTemplateKWAndArgsInfo must be
// emitted first.
CurrentPackingBits.addBit(
E->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo);
Record.push_back(E->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo);
if (E->DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo) {
const ASTTemplateKWAndArgsInfo &ArgInfo =
*E->getTrailingObjects<ASTTemplateKWAndArgsInfo>();
Record.push_back(ArgInfo.NumTemplateArgs);
// 16 bits should be enought to store the number of args
CurrentPackingBits.addBits(ArgInfo.NumTemplateArgs, /*Width=*/16);
AddTemplateKWAndArgsInfo(ArgInfo,
E->getTrailingObjects<TemplateArgumentLoc>());
}
@ -1949,19 +2045,16 @@ ASTStmtWriter::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) {
void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
VisitExpr(E);
BitsPacker OverloadExprBits;
// 14 Bits should enough to store the number of decls.
OverloadExprBits.addBits(E->getNumDecls(), /*BitWidth=*/14);
OverloadExprBits.addBit(E->hasTemplateKWAndArgsInfo());
Record.push_back(E->getNumDecls());
CurrentPackingBits.updateBits();
CurrentPackingBits.addBit(E->hasTemplateKWAndArgsInfo());
if (E->hasTemplateKWAndArgsInfo()) {
const ASTTemplateKWAndArgsInfo &ArgInfo =
*E->getTrailingASTTemplateKWAndArgsInfo();
// 14 Bits should enough to store the number of template args.
OverloadExprBits.addBits(ArgInfo.NumTemplateArgs, /*BitWidth=*/14);
Record.push_back(OverloadExprBits);
Record.push_back(ArgInfo.NumTemplateArgs);
AddTemplateKWAndArgsInfo(ArgInfo, E->getTrailingTemplateArgumentLoc());
} else
Record.push_back(OverloadExprBits);
}
for (OverloadExpr::decls_iterator OvI = E->decls_begin(),
OvE = E->decls_end();
@ -1976,18 +2069,22 @@ void ASTStmtWriter::VisitOverloadExpr(OverloadExpr *E) {
void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) {
VisitOverloadExpr(E);
Record.push_back(E->isArrow());
Record.push_back(E->hasUnresolvedUsing());
Record.AddStmt(!E->isImplicitAccess() ? E->getBase() : nullptr);
Record.AddTypeRef(E->getBaseType());
CurrentPackingBits.addBit(E->isArrow());
CurrentPackingBits.addBit(E->hasUnresolvedUsing());
CurrentPackingBits.addBit(!E->isImplicitAccess());
if (!E->isImplicitAccess())
Record.AddStmt(E->getBase());
Record.AddSourceLocation(E->getOperatorLoc());
Record.AddTypeRef(E->getBaseType());
Code = serialization::EXPR_CXX_UNRESOLVED_MEMBER;
}
void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
VisitOverloadExpr(E);
Record.push_back(E->requiresADL());
Record.push_back(E->isOverloaded());
CurrentPackingBits.addBit(E->requiresADL());
CurrentPackingBits.addBit(E->isOverloaded());
Record.AddDeclRef(E->getNamingClass());
Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP;
}
@ -2059,12 +2156,12 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmExpr(
SubstNonTypeTemplateParmExpr *E) {
VisitExpr(E);
Record.AddDeclRef(E->getAssociatedDecl());
Record.push_back(E->isReferenceParameter());
Record.push_back(E->getIndex());
CurrentPackingBits.addBit(E->isReferenceParameter());
CurrentPackingBits.addBits(E->getIndex(), /*Width=*/12);
CurrentPackingBits.addBit((bool)E->getPackIndex());
if (auto PackIndex = E->getPackIndex())
Record.push_back(*PackIndex + 1);
else
Record.push_back(0);
Record.AddSourceLocation(E->getNameLoc());
Record.AddStmt(E->getReplacement());
Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM;

View file

@ -266,6 +266,8 @@ private:
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"ftell"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
{{{"fflush"}, 1},
{&StreamChecker::preFflush, &StreamChecker::evalFflush, 0}},
{{{"rewind"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
{{{"fgetpos"}, 2},
@ -360,6 +362,12 @@ private:
CheckerContext &C,
const StreamErrorState &ErrorKind) const;
void preFflush(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
void evalFflush(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
/// Check that the stream (in StreamVal) is not NULL.
/// If it can only be NULL a fatal error is emitted and nullptr returned.
/// Otherwise the return value is a new state where the stream is constrained
@ -1191,6 +1199,84 @@ void StreamChecker::evalSetFeofFerror(const FnDescription *Desc,
C.addTransition(State);
}
void StreamChecker::preFflush(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
SVal StreamVal = getStreamArg(Desc, Call);
std::optional<DefinedSVal> Stream = StreamVal.getAs<DefinedSVal>();
if (!Stream)
return;
ProgramStateRef StateNotNull, StateNull;
std::tie(StateNotNull, StateNull) =
C.getConstraintManager().assumeDual(State, *Stream);
if (StateNotNull && !StateNull)
ensureStreamOpened(StreamVal, C, StateNotNull);
}
void StreamChecker::evalFflush(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
SVal StreamVal = getStreamArg(Desc, Call);
std::optional<DefinedSVal> Stream = StreamVal.getAs<DefinedSVal>();
if (!Stream)
return;
// Skip if the stream can be both NULL and non-NULL.
ProgramStateRef StateNotNull, StateNull;
std::tie(StateNotNull, StateNull) =
C.getConstraintManager().assumeDual(State, *Stream);
if (StateNotNull && StateNull)
return;
if (StateNotNull && !StateNull)
State = StateNotNull;
else
State = StateNull;
const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
if (!CE)
return;
// `fflush` returns EOF on failure, otherwise returns 0.
ProgramStateRef StateFailed = bindInt(*EofVal, State, C, CE);
ProgramStateRef StateNotFailed = bindInt(0, State, C, CE);
// Clear error states if `fflush` returns 0, but retain their EOF flags.
auto ClearErrorInNotFailed = [&StateNotFailed, Desc](SymbolRef Sym,
const StreamState *SS) {
if (SS->ErrorState & ErrorFError) {
StreamErrorState NewES =
(SS->ErrorState & ErrorFEof) ? ErrorFEof : ErrorNone;
StreamState NewSS = StreamState::getOpened(Desc, NewES, false);
StateNotFailed = StateNotFailed->set<StreamMap>(Sym, NewSS);
}
};
if (StateNotNull && !StateNull) {
// Skip if the input stream's state is unknown, open-failed or closed.
if (SymbolRef StreamSym = StreamVal.getAsSymbol()) {
const StreamState *SS = State->get<StreamMap>(StreamSym);
if (SS) {
assert(SS->isOpened() && "Stream is expected to be opened");
ClearErrorInNotFailed(StreamSym, SS);
} else
return;
}
} else {
// Clear error states for all streams.
const StreamMapTy &Map = StateNotFailed->get<StreamMap>();
for (const auto &I : Map) {
SymbolRef Sym = I.first;
const StreamState &SS = I.second;
if (SS.isOpened())
ClearErrorInNotFailed(Sym, &SS);
}
}
C.addTransition(StateNotFailed);
C.addTransition(StateFailed);
}
ProgramStateRef
StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
CheckerContext &C,

View file

@ -1217,7 +1217,7 @@ raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {
OS << (int)Record.PrototypeLength << ",";
OS << (int)Record.SuffixLength << ",";
OS << (int)Record.OverloadedSuffixSize << ",";
OS << (int)Record.RequiredExtensions << ",";
OS << Record.RequiredExtensions << ",";
OS << (int)Record.TypeRangeMask << ",";
OS << (int)Record.Log2LMULMask << ",";
OS << (int)Record.NF << ",";

View file

@ -15,6 +15,8 @@
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Interpreter/CodeCompletion.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/LineEditor/LineEditor.h"
@ -123,22 +125,14 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos,
return {};
}
codeComplete(
const_cast<clang::CompilerInstance *>((*Interp)->getCompilerInstance()),
Buffer, Lines, Pos + 1, MainInterp.getCompilerInstance(), Results);
size_t space_pos = Buffer.rfind(" ");
llvm::StringRef Prefix;
if (space_pos == llvm::StringRef::npos) {
Prefix = Buffer;
} else {
Prefix = Buffer.substr(space_pos + 1);
}
auto *MainCI = (*Interp)->getCompilerInstance();
auto CC = clang::ReplCodeCompleter();
CC.codeComplete(MainCI, Buffer, Lines, Pos + 1,
MainInterp.getCompilerInstance(), Results);
for (auto c : Results) {
if (c.find(Prefix) == 0)
Comps.push_back(llvm::LineEditor::Completion(c.substr(Prefix.size()), c));
if (c.find(CC.Prefix) == 0)
Comps.push_back(
llvm::LineEditor::Completion(c.substr(CC.Prefix.size()), c));
}
return Comps;
}

View file

@ -550,6 +550,8 @@ class NeonEmitter {
void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out);
void genBuiltinsDef(raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs);
void genStreamingSVECompatibleList(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs);
void genOverloadTypeCheckCode(raw_ostream &OS,
SmallVectorImpl<Intrinsic *> &Defs);
void genIntrinsicRangeCheckCode(raw_ostream &OS,
@ -2041,6 +2043,30 @@ void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
OS << "#endif\n\n";
}
void NeonEmitter::genStreamingSVECompatibleList(
raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs) {
OS << "#ifdef GET_NEON_STREAMING_COMPAT_FLAG\n";
std::set<std::string> Emitted;
for (auto *Def : Defs) {
// If the def has a body (that is, it has Operation DAGs), it won't call
// __builtin_neon_* so we don't need to generate a definition for it.
if (Def->hasBody())
continue;
std::string Name = Def->getMangledName();
if (Emitted.find(Name) != Emitted.end())
continue;
// FIXME: We should make exceptions here for some NEON builtins that are
// permitted in streaming mode.
OS << "case NEON::BI__builtin_neon_" << Name
<< ": BuiltinType = ArmNonStreaming; break;\n";
Emitted.insert(Name);
}
OS << "#endif\n\n";
}
/// Generate the ARM and AArch64 overloaded type checking code for
/// SemaChecking.cpp, checking for unique builtin declarations.
void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
@ -2224,6 +2250,8 @@ void NeonEmitter::runHeader(raw_ostream &OS) {
// Generate ARM overloaded type checking code for SemaChecking.cpp
genOverloadTypeCheckCode(OS, Defs);
genStreamingSVECompatibleList(OS, Defs);
// Generate ARM range checking code for shift/lane immediates.
genIntrinsicRangeCheckCode(OS, Defs);
}

View file

@ -46,7 +46,7 @@ struct SemaRecord {
unsigned Log2LMULMask;
// Required extensions for this intrinsic.
unsigned RequiredExtensions;
uint32_t RequiredExtensions;
// Prototype for this intrinsic.
SmallVector<PrototypeDescriptor> Prototype;
@ -653,24 +653,26 @@ void RVVEmitter::createRVVIntrinsics(
SR.RequiredExtensions = 0;
for (auto RequiredFeature : RequiredFeatures) {
RVVRequire RequireExt = StringSwitch<RVVRequire>(RequiredFeature)
.Case("RV64", RVV_REQ_RV64)
.Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh)
.Case("Xsfvcp", RVV_REQ_Xsfvcp)
.Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
.Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
.Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
.Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
.Case("Zvbb", RVV_REQ_Zvbb)
.Case("Zvbc", RVV_REQ_Zvbc)
.Case("Zvkb", RVV_REQ_Zvkb)
.Case("Zvkg", RVV_REQ_Zvkg)
.Case("Zvkned", RVV_REQ_Zvkned)
.Case("Zvknha", RVV_REQ_Zvknha)
.Case("Zvknhb", RVV_REQ_Zvknhb)
.Case("Zvksed", RVV_REQ_Zvksed)
.Case("Zvksh", RVV_REQ_Zvksh)
.Default(RVV_REQ_None);
RVVRequire RequireExt =
StringSwitch<RVVRequire>(RequiredFeature)
.Case("RV64", RVV_REQ_RV64)
.Case("ZvfhminOrZvfh", RVV_REQ_ZvfhminOrZvfh)
.Case("Xsfvcp", RVV_REQ_Xsfvcp)
.Case("Xsfvfnrclipxfqf", RVV_REQ_Xsfvfnrclipxfqf)
.Case("Xsfvfwmaccqqq", RVV_REQ_Xsfvfwmaccqqq)
.Case("Xsfvqmaccdod", RVV_REQ_Xsfvqmaccdod)
.Case("Xsfvqmaccqoq", RVV_REQ_Xsfvqmaccqoq)
.Case("Zvbb", RVV_REQ_Zvbb)
.Case("Zvbc", RVV_REQ_Zvbc)
.Case("Zvkb", RVV_REQ_Zvkb)
.Case("Zvkg", RVV_REQ_Zvkg)
.Case("Zvkned", RVV_REQ_Zvkned)
.Case("Zvknha", RVV_REQ_Zvknha)
.Case("Zvknhb", RVV_REQ_Zvknhb)
.Case("Zvksed", RVV_REQ_Zvksed)
.Case("Zvksh", RVV_REQ_Zvksh)
.Case("Experimental", RVV_REQ_Experimental)
.Default(RVV_REQ_None);
assert(RequireExt != RVV_REQ_None && "Unrecognized required feature?");
SR.RequiredExtensions |= RequireExt;
}

View file

@ -379,9 +379,15 @@ public:
/// Emit all the information needed to map builtin -> LLVM IR intrinsic.
void createSMECodeGenMap(raw_ostream &o);
/// Create a table for a builtin's requirement for PSTATE.SM.
void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
/// Emit all the range checks for the immediates.
void createSMERangeChecks(raw_ostream &o);
/// Create a table for a builtin's requirement for PSTATE.ZA.
void createBuiltinZAState(raw_ostream &OS);
/// Create intrinsic and add it to \p Out
void createIntrinsic(Record *R,
SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
@ -1702,6 +1708,76 @@ void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
OS << "#endif\n\n";
}
void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
for (auto *R : RV)
createIntrinsic(R, Defs);
std::map<bool, std::set<std::string>> DefsZAState;
uint64_t IsSharedZAFlag = getEnumValueForFlag("IsSharedZA");
for (auto &Def : Defs) {
bool HasZAState = Def->isFlagSet(IsSharedZAFlag);
DefsZAState[HasZAState].insert(Def->getMangledName());
}
OS << "#ifdef GET_SME_BUILTIN_HAS_ZA_STATE\n";
for (auto HasZA : {true, false}) {
auto Names = DefsZAState[HasZA];
for (auto Name : Names)
OS << "case SME::BI__builtin_sme_" << Name << ":\n";
OS << " return " << (HasZA ? "true" : "false") << ";\n";
}
OS << "#endif\n\n";
}
void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
for (auto *R : RV)
createIntrinsic(R, Defs);
StringRef ExtensionKind;
switch (Kind) {
case ACLEKind::SME:
ExtensionKind = "SME";
break;
case ACLEKind::SVE:
ExtensionKind = "SVE";
break;
}
OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
llvm::StringMap<std::set<std::string>> StreamingMap;
uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");
uint64_t IsStreamingCompatibleFlag =
getEnumValueForFlag("IsStreamingCompatible");
for (auto &Def : Defs) {
if (Def->isFlagSet(IsStreamingFlag))
StreamingMap["ArmStreaming"].insert(Def->getMangledName());
else if (Def->isFlagSet(IsStreamingCompatibleFlag))
StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());
else
StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());
}
for (auto BuiltinType : StreamingMap.keys()) {
for (auto Name : StreamingMap[BuiltinType]) {
OS << "case " << ExtensionKind << "::BI__builtin_"
<< ExtensionKind.lower() << "_";
OS << Name << ":\n";
}
OS << " BuiltinType = " << BuiltinType << ";\n";
OS << " break;\n";
}
OS << "#endif\n\n";
}
namespace clang {
void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createHeader(OS);
@ -1723,6 +1799,10 @@ void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createTypeFlags(OS);
}
void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);
}
void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createSMEHeader(OS);
}
@ -1739,4 +1819,11 @@ void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createSMERangeChecks(OS);
}
void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);
}
void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
SVEEmitter(Records).createBuiltinZAState(OS);
}
} // End namespace clang

View file

@ -86,10 +86,13 @@ enum ActionType {
GenArmSveBuiltinCG,
GenArmSveTypeFlags,
GenArmSveRangeChecks,
GenArmSveStreamingAttrs,
GenArmSmeHeader,
GenArmSmeBuiltins,
GenArmSmeBuiltinCG,
GenArmSmeRangeChecks,
GenArmSmeStreamingAttrs,
GenArmSmeBuiltinZAState,
GenArmCdeHeader,
GenArmCdeBuiltinDef,
GenArmCdeBuiltinSema,
@ -246,6 +249,8 @@ cl::opt<ActionType> Action(
"Generate arm_sve_typeflags.inc for clang"),
clEnumValN(GenArmSveRangeChecks, "gen-arm-sve-sema-rangechecks",
"Generate arm_sve_sema_rangechecks.inc for clang"),
clEnumValN(GenArmSveStreamingAttrs, "gen-arm-sve-streaming-attrs",
"Generate arm_sve_streaming_attrs.inc for clang"),
clEnumValN(GenArmSmeHeader, "gen-arm-sme-header",
"Generate arm_sme.h for clang"),
clEnumValN(GenArmSmeBuiltins, "gen-arm-sme-builtins",
@ -254,6 +259,10 @@ cl::opt<ActionType> Action(
"Generate arm_sme_builtin_cg_map.inc for clang"),
clEnumValN(GenArmSmeRangeChecks, "gen-arm-sme-sema-rangechecks",
"Generate arm_sme_sema_rangechecks.inc for clang"),
clEnumValN(GenArmSmeStreamingAttrs, "gen-arm-sme-streaming-attrs",
"Generate arm_sme_streaming_attrs.inc for clang"),
clEnumValN(GenArmSmeBuiltinZAState, "gen-arm-sme-builtin-za-state",
"Generate arm_sme_builtins_za_state.inc for clang"),
clEnumValN(GenArmMveHeader, "gen-arm-mve-header",
"Generate arm_mve.h for clang"),
clEnumValN(GenArmMveBuiltinDef, "gen-arm-mve-builtin-def",
@ -494,6 +503,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmSveRangeChecks:
EmitSveRangeChecks(Records, OS);
break;
case GenArmSveStreamingAttrs:
EmitSveStreamingAttrs(Records, OS);
break;
case GenArmSmeHeader:
EmitSmeHeader(Records, OS);
break;
@ -506,6 +518,12 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenArmSmeRangeChecks:
EmitSmeRangeChecks(Records, OS);
break;
case GenArmSmeStreamingAttrs:
EmitSmeStreamingAttrs(Records, OS);
break;
case GenArmSmeBuiltinZAState:
EmitSmeBuiltinZAState(Records, OS);
break;
case GenArmCdeHeader:
EmitCdeHeader(Records, OS);
break;

View file

@ -105,11 +105,14 @@ void EmitSveBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveTypeFlags(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveRangeChecks(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSveStreamingAttrs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeBuiltins(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeBuiltinCG(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeRangeChecks(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeStreamingAttrs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitSmeBuiltinZAState(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitMveHeader(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitMveBuiltinDef(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);

View file

@ -146,30 +146,37 @@ void PlatformTSDDtor(void *tsd) {
# endif
AsanThread::TSDDtor(tsd);
}
#endif
# endif
static void BeforeFork() {
if (CAN_SANITIZE_LEAKS) {
__lsan::LockGlobal();
}
// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
// stuff we need.
__lsan::LockThreads();
__lsan::LockAllocator();
StackDepotLockBeforeFork();
}
static void AfterFork(bool fork_child) {
StackDepotUnlockAfterFork(fork_child);
// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
// the stuff we need.
__lsan::UnlockAllocator();
__lsan::UnlockThreads();
if (CAN_SANITIZE_LEAKS) {
__lsan::UnlockGlobal();
}
}
void InstallAtForkHandler() {
auto before = []() {
if (CAN_SANITIZE_LEAKS) {
__lsan::LockGlobal();
}
// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
// stuff we need.
__lsan::LockThreads();
__lsan::LockAllocator();
StackDepotLockAll();
};
auto after = []() {
StackDepotUnlockAll();
// `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
// the stuff we need.
__lsan::UnlockAllocator();
__lsan::UnlockThreads();
if (CAN_SANITIZE_LEAKS) {
__lsan::UnlockGlobal();
}
};
pthread_atfork(before, after, after);
# if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE
return; // FIXME: Implement FutexWait.
# endif
pthread_atfork(
&BeforeFork, []() { AfterFork(/* fork_child= */ false); },
[]() { AfterFork(/* fork_child= */ true); });
}
void InstallAtExitCheckLeaks() {

View file

@ -27,7 +27,12 @@ FNAME(reg, op, s, i): ;\
#define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \
mov %##reg,%r10 ;\
shr $0x3,%r10 ;\
.if ASAN_SHADOW_OFFSET_CONST < 0x80000000 ;\
movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\
.else ;\
movabsq $ASAN_SHADOW_OFFSET_CONST,%r11 ;\
movsbl (%r10,%r11),%r10d ;\
.endif ;\
test %r10d,%r10d ;\
jne CLABEL(reg, op, s, add) ;\
RLABEL(reg, op, s, add): ;\
@ -84,7 +89,12 @@ ENDF
#define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \
mov %##reg,%r10 ;\
shr $0x3,%r10 ;\
.if ASAN_SHADOW_OFFSET_CONST < 0x80000000 ;\
##c $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\
.else ;\
movabsq $ASAN_SHADOW_OFFSET_CONST,%r11 ;\
##c $0x0,(%r10,%r11) ;\
.endif ;\
jne FLABEL(reg, op, s, add) ;\
retq ;\

View file

@ -0,0 +1,151 @@
//===-- cpu_model/aarch64.c - Support for __cpu_model builtin ----*- 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 is based on LLVM's lib/Support/Host.cpp.
// It implements __aarch64_have_lse_atomics, __aarch64_cpu_features for
// AArch64.
//
//===----------------------------------------------------------------------===//
#include "cpu_model.h"
#if !defined(__aarch64__)
#error This file is intended only for aarch64-based targets
#endif
#if __has_include(<sys/ifunc.h>)
#include <sys/ifunc.h>
#else
typedef struct __ifunc_arg_t {
unsigned long _size;
unsigned long _hwcap;
unsigned long _hwcap2;
} __ifunc_arg_t;
#endif // __has_include(<sys/ifunc.h>)
// LSE support detection for out-of-line atomics
// using HWCAP and Auxiliary vector
_Bool __aarch64_have_lse_atomics
__attribute__((visibility("hidden"), nocommon)) = false;
#if defined(__FreeBSD__)
// clang-format off: should not reorder sys/auxv.h alphabetically
#include <sys/auxv.h>
// clang-format on
#include "aarch64/hwcap.inc"
#include "aarch64/lse_atomics/freebsd.inc"
#elif defined(__Fuchsia__)
#include "aarch64/hwcap.inc"
#include "aarch64/lse_atomics/fuchsia.inc"
#elif defined(__ANDROID__)
#include "aarch64/hwcap.inc"
#include "aarch64/lse_atomics/android.inc"
#elif __has_include(<sys/auxv.h>)
#include "aarch64/hwcap.inc"
#include "aarch64/lse_atomics/sysauxv.inc"
#else
// When unimplemented, we leave __aarch64_have_lse_atomics initialized to false.
#endif
#if !defined(DISABLE_AARCH64_FMV)
// CPUFeatures must correspond to the same AArch64 features in
// AArch64TargetParser.h
enum CPUFeatures {
FEAT_RNG,
FEAT_FLAGM,
FEAT_FLAGM2,
FEAT_FP16FML,
FEAT_DOTPROD,
FEAT_SM4,
FEAT_RDM,
FEAT_LSE,
FEAT_FP,
FEAT_SIMD,
FEAT_CRC,
FEAT_SHA1,
FEAT_SHA2,
FEAT_SHA3,
FEAT_AES,
FEAT_PMULL,
FEAT_FP16,
FEAT_DIT,
FEAT_DPB,
FEAT_DPB2,
FEAT_JSCVT,
FEAT_FCMA,
FEAT_RCPC,
FEAT_RCPC2,
FEAT_FRINTTS,
FEAT_DGH,
FEAT_I8MM,
FEAT_BF16,
FEAT_EBF16,
FEAT_RPRES,
FEAT_SVE,
FEAT_SVE_BF16,
FEAT_SVE_EBF16,
FEAT_SVE_I8MM,
FEAT_SVE_F32MM,
FEAT_SVE_F64MM,
FEAT_SVE2,
FEAT_SVE_AES,
FEAT_SVE_PMULL128,
FEAT_SVE_BITPERM,
FEAT_SVE_SHA3,
FEAT_SVE_SM4,
FEAT_SME,
FEAT_MEMTAG,
FEAT_MEMTAG2,
FEAT_MEMTAG3,
FEAT_SB,
FEAT_PREDRES,
FEAT_SSBS,
FEAT_SSBS2,
FEAT_BTI,
FEAT_LS64,
FEAT_LS64_V,
FEAT_LS64_ACCDATA,
FEAT_WFXT,
FEAT_SME_F64,
FEAT_SME_I64,
FEAT_SME2,
FEAT_RCPC3,
FEAT_MAX,
FEAT_EXT = 62, // Reserved to indicate presence of additional features field
// in __aarch64_cpu_features
FEAT_INIT // Used as flag of features initialization completion
};
// Architecture features used
// in Function Multi Versioning
struct {
unsigned long long features;
// As features grows new fields could be added
} __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon));
// The formatter wants to re-order these includes, but doing so is incorrect:
// clang-format off
#if defined(__APPLE__)
#include "aarch64/fmv/apple.inc"
#elif defined(__FreeBSD__)
#include "aarch64/fmv/mrs.inc"
#include "aarch64/fmv/freebsd.inc"
#elif defined(__Fuchsia__)
#include "aarch64/fmv/fuchsia.inc"
#elif defined(__ANDROID__)
#include "aarch64/fmv/mrs.inc"
#include "aarch64/fmv/android.inc"
#elif __has_include(<sys/auxv.h>)
#include "aarch64/fmv/mrs.inc"
#include "aarch64/fmv/sysauxv.inc"
#else
#include "aarch64/fmv/unimplemented.inc"
#endif
// clang-format on
#endif // !defined(DISABLE_AARCH64_FMV)

Some files were not shown because too many files have changed in this diff Show more