diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 26844d1c74f..b0d7ef509c2 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2592,7 +2592,15 @@ enum CXCursorKind { */ CXCursor_OMPUnrollDirective = 293, - CXCursor_LastStmt = CXCursor_OMPUnrollDirective, + /** OpenMP metadirective directive. + */ + CXCursor_OMPMetaDirective = 294, + + /** OpenMP loop directive. + */ + CXCursor_OMPGenericLoopDirective = 295, + + CXCursor_LastStmt = CXCursor_OMPGenericLoopDirective, /** * Cursor that represents the translation unit itself. @@ -3298,8 +3306,9 @@ enum CXTypeKind { CXType_UAccum = 37, CXType_ULongAccum = 38, CXType_BFloat16 = 39, + CXType_Ibm128 = 40, CXType_FirstBuiltin = CXType_Void, - CXType_LastBuiltin = CXType_BFloat16, + CXType_LastBuiltin = CXType_Ibm128, CXType_Complex = 100, CXType_Pointer = 101, diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index d0526f4fa5c..aba18b060b0 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -1,9 +1,8 @@ //===--- ASTConcept.h - Concepts Related AST Data Structures ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 34299581d89..d336342e4cd 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -102,6 +102,7 @@ class ParentMapContext; class DynTypedNode; class DynTypedNodeList; class Expr; +enum class FloatModeKind; class GlobalDecl; class ItaniumMangleContext; class MangleContext; @@ -164,24 +165,46 @@ namespace serialization { template class AbstractTypeReader; } // namespace serialization +enum class AlignRequirementKind { + /// The alignment was not explicit in code. + None, + + /// The alignment comes from an alignment attribute on a typedef. + RequiredByTypedef, + + /// The alignment comes from an alignment attribute on a record type. + RequiredByRecord, + + /// The alignment comes from an alignment attribute on a enum type. + RequiredByEnum, +}; + struct TypeInfo { uint64_t Width = 0; unsigned Align = 0; - bool AlignIsRequired : 1; + AlignRequirementKind AlignRequirement; - TypeInfo() : AlignIsRequired(false) {} - TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) - : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + TypeInfo() : AlignRequirement(AlignRequirementKind::None) {} + TypeInfo(uint64_t Width, unsigned Align, + AlignRequirementKind AlignRequirement) + : Width(Width), Align(Align), AlignRequirement(AlignRequirement) {} + bool isAlignRequired() { + return AlignRequirement != AlignRequirementKind::None; + } }; struct TypeInfoChars { CharUnits Width; CharUnits Align; - bool AlignIsRequired : 1; + AlignRequirementKind AlignRequirement; - TypeInfoChars() : AlignIsRequired(false) {} - TypeInfoChars(CharUnits Width, CharUnits Align, bool AlignIsRequired) - : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + TypeInfoChars() : AlignRequirement(AlignRequirementKind::None) {} + TypeInfoChars(CharUnits Width, CharUnits Align, + AlignRequirementKind AlignRequirement) + : Width(Width), Align(Align), AlignRequirement(AlignRequirement) {} + bool isAlignRequired() { + return AlignRequirement != AlignRequirementKind::None; + } }; /// Holds long-lived AST nodes (such as types and decls) that can be @@ -672,6 +695,12 @@ public: SourceManager& getSourceManager() { return SourceMgr; } const SourceManager& getSourceManager() const { return SourceMgr; } + // Cleans up some of the data structures. This allows us to do cleanup + // normally done in the destructor earlier. Renders much of the ASTContext + // unusable, mostly the actual AST nodes, so should be called when we no + // longer need access to the AST. + void cleanup(); + llvm::BumpPtrAllocator &getAllocator() const { return BumpAlloc; } @@ -728,7 +757,8 @@ public: /// getRealTypeForBitwidth - /// sets floating point QualTy according to specified bitwidth. /// Returns empty type if there is no appropriate target types. - QualType getRealTypeForBitwidth(unsigned DestWidth, bool ExplicitIEEE) const; + QualType getRealTypeForBitwidth(unsigned DestWidth, + FloatModeKind ExplicitType) const; bool AtomicUsesUnsupportedLibcall(const AtomicExpr *E) const; @@ -1054,7 +1084,7 @@ public: CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; CanQualType UnsignedLongLongTy, UnsignedInt128Ty; - CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty; + CanQualType FloatTy, DoubleTy, LongDoubleTy, Float128Ty, Ibm128Ty; CanQualType ShortAccumTy, AccumTy, LongAccumTy; // ISO/IEC JTC1 SC22 WG14 N1169 Extension CanQualType UnsignedShortAccumTy, UnsignedAccumTy, UnsignedLongAccumTy; @@ -1069,8 +1099,6 @@ public: CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON CanQualType BFloat16Ty; CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 - CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; - CanQualType Float128ComplexTy; CanQualType VoidPtrTy, NullPtrTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; CanQualType BuiltinFnTy; @@ -1340,6 +1368,12 @@ public: /// Get address space for OpenCL type. LangAS getOpenCLTypeAddrSpace(const Type *T) const; + /// Returns default address space based on OpenCL version and enabled features + inline LangAS getDefaultOpenCLPointeeAddrSpace() { + return LangOpts.OpenCLGenericAddressSpace ? LangAS::opencl_generic + : LangAS::opencl_private; + } + void setcudaConfigureCallDecl(FunctionDecl *FD) { cudaConfigureCallDecl = FD; } @@ -1497,6 +1531,12 @@ private: QualType getFunctionTypeInternal(QualType ResultTy, ArrayRef Args, const FunctionProtoType::ExtProtoInfo &EPI, bool OnlyWantCanonical) const; + QualType + getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack = false, + ConceptDecl *TypeConstraintConcept = nullptr, + ArrayRef TypeConstraintArgs = {}, + bool IsCanon = false) const; public: /// Return the unique reference to the type for the specified type @@ -1631,6 +1671,8 @@ public: QualType getTypeOfExprType(Expr *e) const; QualType getTypeOfType(QualType t) const; + QualType getReferenceQualifiedType(const Expr *e) const; + /// C++11 decltype. QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; @@ -2505,8 +2547,10 @@ public: bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl, const ObjCMethodDecl *MethodImp); - bool UnwrapSimilarTypes(QualType &T1, QualType &T2); - void UnwrapSimilarArrayTypes(QualType &T1, QualType &T2); + bool UnwrapSimilarTypes(QualType &T1, QualType &T2, + bool AllowPiMismatch = true); + void UnwrapSimilarArrayTypes(QualType &T1, QualType &T2, + bool AllowPiMismatch = true); /// Determine if two types are similar, according to the C++ rules. That is, /// determine if they are the same other than qualifiers on the initial @@ -3209,31 +3253,10 @@ public: StringRef getCUIDHash() const; - void AddSYCLKernelNamingDecl(const CXXRecordDecl *RD); - bool IsSYCLKernelNamingDecl(const NamedDecl *RD) const; - unsigned GetSYCLKernelNamingIndex(const NamedDecl *RD); - /// A SourceLocation to store whether we have evaluated a kernel name already, - /// and where it happened. If so, we need to diagnose an illegal use of the - /// builtin. - llvm::MapVector - SYCLUniqueStableNameEvaluatedValues; - private: /// All OMPTraitInfo objects live in this collection, one per /// `pragma omp [begin] declare variant` directive. SmallVector, 4> OMPTraitInfoVector; - - /// A list of the (right now just lambda decls) declarations required to - /// name all the SYCL kernels in the translation unit, so that we can get the - /// correct kernel name, as well as implement - /// __builtin_sycl_unique_stable_name. - llvm::DenseMap> - SYCLKernelNamingTypes; - std::unique_ptr SYCLKernelFilterContext; - void FilterSYCLKernelNamingDecls( - const CXXRecordDecl *RD, - llvm::SmallVectorImpl &Decls); }; /// Insertion operator for diagnostics. diff --git a/clang/include/clang/AST/ASTFwd.h b/clang/include/clang/AST/ASTFwd.h index 649b5711342..fdbd603ce5d 100644 --- a/clang/include/clang/AST/ASTFwd.h +++ b/clang/include/clang/AST/ASTFwd.h @@ -30,6 +30,9 @@ class OMPClause; #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) class Class; #include "llvm/Frontend/OpenMP/OMP.inc" +class Attr; +#define ATTR(A) class A##Attr; +#include "clang/Basic/AttrList.inc" } // end namespace clang diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index 17e673a8471..c8bdae10a6e 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -379,6 +379,9 @@ class TypeSourceInfo; return Import(const_cast(FromD)); } + llvm::Expected + Import(const InheritedConstructor &From); + /// Return the copy of the given declaration in the "to" context if /// it has already been imported from the "from" context. Otherwise return /// nullptr. diff --git a/clang/include/clang/AST/ASTImporterSharedState.h b/clang/include/clang/AST/ASTImporterSharedState.h index 829eb1c611c..686a8e22b2f 100644 --- a/clang/include/clang/AST/ASTImporterSharedState.h +++ b/clang/include/clang/AST/ASTImporterSharedState.h @@ -1,9 +1,8 @@ //===- ASTImporterSharedState.h - ASTImporter specific state --*- C++ -*---===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h index c958a16aba2..0b9e9e4e605 100644 --- a/clang/include/clang/AST/ASTStructuralEquivalence.h +++ b/clang/include/clang/AST/ASTStructuralEquivalence.h @@ -117,7 +117,7 @@ struct StructuralEquivalenceContext { static llvm::Optional findUntaggedStructOrUnionIndex(RecordDecl *Anon); - // If ErrorOnTagTypeMismatch is set, return the the error, otherwise get the + // If ErrorOnTagTypeMismatch is set, return the error, otherwise get the // relevant warning for the input error diagnostic. unsigned getApplicableDiagnostic(unsigned ErrorDiagnostic); diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h index 57195a9d606..6d96146a4d4 100644 --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -17,6 +17,7 @@ #include "clang/AST/ASTFwd.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TypeLoc.h" @@ -25,10 +26,8 @@ #include "llvm/Support/AlignOf.h" namespace llvm { - class raw_ostream; - -} +} // namespace llvm namespace clang { @@ -65,7 +64,10 @@ public: static ASTNodeKind getFromNode(const Decl &D); static ASTNodeKind getFromNode(const Stmt &S); static ASTNodeKind getFromNode(const Type &T); + static ASTNodeKind getFromNode(const TypeLoc &T); + static ASTNodeKind getFromNode(const LambdaCapture &L); static ASTNodeKind getFromNode(const OMPClause &C); + static ASTNodeKind getFromNode(const Attr &A); /// \} /// Returns \c true if \c this and \c Other represent the same kind. @@ -131,9 +133,12 @@ private: NKI_None, NKI_TemplateArgument, NKI_TemplateArgumentLoc, + NKI_LambdaCapture, NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, +#define TYPELOC(CLASS, PARENT) NKI_##CLASS##TypeLoc, +#include "clang/AST/TypeLocNodes.def" NKI_TypeLoc, NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc, NKI_CXXBaseSpecifier, @@ -152,6 +157,9 @@ private: #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) NKI_##Class, #include "llvm/Frontend/OpenMP/OMP.inc" + NKI_Attr, +#define ATTR(A) NKI_##A##Attr, +#include "clang/Basic/AttrList.inc" NKI_NumberOfKinds }; @@ -192,15 +200,19 @@ private: KIND_TO_KIND_ID(CXXCtorInitializer) KIND_TO_KIND_ID(TemplateArgument) KIND_TO_KIND_ID(TemplateArgumentLoc) +KIND_TO_KIND_ID(LambdaCapture) KIND_TO_KIND_ID(TemplateName) KIND_TO_KIND_ID(NestedNameSpecifier) KIND_TO_KIND_ID(NestedNameSpecifierLoc) KIND_TO_KIND_ID(QualType) +#define TYPELOC(CLASS, PARENT) KIND_TO_KIND_ID(CLASS##TypeLoc) +#include "clang/AST/TypeLocNodes.def" KIND_TO_KIND_ID(TypeLoc) KIND_TO_KIND_ID(Decl) KIND_TO_KIND_ID(Stmt) KIND_TO_KIND_ID(Type) KIND_TO_KIND_ID(OMPClause) +KIND_TO_KIND_ID(Attr) KIND_TO_KIND_ID(CXXBaseSpecifier) #define DECL(DERIVED, BASE) KIND_TO_KIND_ID(DERIVED##Decl) #include "clang/AST/DeclNodes.inc" @@ -211,6 +223,8 @@ KIND_TO_KIND_ID(CXXBaseSpecifier) #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) KIND_TO_KIND_ID(Class) #include "llvm/Frontend/OpenMP/OMP.inc" +#define ATTR(A) KIND_TO_KIND_ID(A##Attr) +#include "clang/Basic/AttrList.inc" #undef KIND_TO_KIND_ID inline raw_ostream &operator<<(raw_ostream &OS, ASTNodeKind K) { @@ -299,7 +313,7 @@ public: return getUnchecked().getAsOpaquePtr() < Other.getUnchecked().getAsOpaquePtr(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) { auto TLA = getUnchecked(); auto TLB = Other.getUnchecked(); return std::make_pair(TLA.getType().getAsOpaquePtr(), @@ -331,7 +345,7 @@ public: if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) return getUnchecked() == Other.getUnchecked(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) return getUnchecked() == Other.getUnchecked(); if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) @@ -360,7 +374,7 @@ public: } static unsigned getHashValue(const DynTypedNode &Val) { // FIXME: Add hashing support for the remaining types. - if (ASTNodeKind::getFromNodeKind().isSame(Val.NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(Val.NodeKind)) { auto TL = Val.getUnchecked(); return llvm::hash_combine(TL.getType().getAsOpaquePtr(), TL.getOpaqueData()); @@ -450,6 +464,29 @@ private: } }; + /// Converter that stores nodes by value. It must be possible to dynamically + /// cast the stored node within a type hierarchy without breaking (especially + /// through slicing). + template > + struct DynCastValueConverter { + static const T *get(ASTNodeKind NodeKind, const void *Storage) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { + assert(ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)); + return *static_cast(reinterpret_cast(Storage)); + } + static DynTypedNode create(const T &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNode(Node); + new (&Result.Storage) T(Node); + return Result; + } + }; + ASTNodeKind NodeKind; /// Stores the data of the node. @@ -486,6 +523,11 @@ struct DynTypedNode::BaseConverter< T, std::enable_if_t::value>> : public DynCastPtrConverter {}; +template +struct DynTypedNode::BaseConverter< + T, std::enable_if_t::value>> + : public DynCastPtrConverter {}; + template <> struct DynTypedNode::BaseConverter< NestedNameSpecifier, void> : public PtrConverter {}; @@ -502,6 +544,10 @@ template <> struct DynTypedNode::BaseConverter : public ValueConverter {}; +template <> +struct DynTypedNode::BaseConverter + : public ValueConverter {}; + template <> struct DynTypedNode::BaseConverter< TemplateName, void> : public ValueConverter {}; @@ -515,9 +561,10 @@ template <> struct DynTypedNode::BaseConverter : public ValueConverter {}; -template <> +template struct DynTypedNode::BaseConverter< - TypeLoc, void> : public ValueConverter {}; + T, std::enable_if_t::value>> + : public DynCastValueConverter {}; template <> struct DynTypedNode::BaseConverter diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index dbfecc12504..6366d6e8837 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/include/clang/AST/Attr.h @@ -109,6 +109,8 @@ public: // Pretty print this attribute. void printPretty(raw_ostream &OS, const PrintingPolicy &Policy) const; + + static StringRef getDocumentation(attr::Kind); }; class TypeAttr : public Attr { @@ -372,8 +374,7 @@ struct ParsedTargetAttr { inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const Attr *At) { - DB.AddTaggedVal(reinterpret_cast(At), - DiagnosticsEngine::ak_attr); + DB.AddTaggedVal(reinterpret_cast(At), DiagnosticsEngine::ak_attr); return DB; } } // end namespace clang diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def index 039765dfdfe..c04f6f6f127 100644 --- a/clang/include/clang/AST/BuiltinTypes.def +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -218,6 +218,9 @@ FLOATING_TYPE(BFloat16, BFloat16Ty) // '__float128' FLOATING_TYPE(Float128, Float128Ty) +// '__ibm128' +FLOATING_TYPE(Ibm128, Ibm128Ty) + //===- Language-specific types --------------------------------------------===// // This is the type of C++0x 'nullptr'. diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h index 54a4b0a9cfe..4184e103206 100644 --- a/clang/include/clang/AST/Comment.h +++ b/clang/include/clang/AST/Comment.h @@ -1019,8 +1019,6 @@ struct DeclInfo { /// \li member function template, /// \li member function template specialization, /// \li ObjC method, - /// \li a typedef for a function pointer, member function pointer, - /// ObjC block. FunctionKind, /// Something that we consider a "class": @@ -1030,8 +1028,8 @@ struct DeclInfo { ClassKind, /// Something that we consider a "variable": - /// \li namespace scope variables; - /// \li static and non-static class data members; + /// \li namespace scope variables and variable templates; + /// \li static and non-static class data members and member templates; /// \li enumerators. VariableKind, @@ -1076,6 +1074,9 @@ struct DeclInfo { /// Can be true only if \c IsFunctionDecl is true. unsigned IsClassMethod : 1; + /// Is \c CommentDecl something we consider a "function" that's variadic. + unsigned IsVariadic : 1; + void fill(); DeclKind getKind() const LLVM_READONLY { @@ -1085,6 +1086,8 @@ struct DeclInfo { TemplateDeclKind getTemplateKind() const LLVM_READONLY { return static_cast(TemplateKind); } + + bool involvesFunctionType() const { return !ReturnType.isNull(); } }; /// A full comment attached to a declaration, contains block content. diff --git a/clang/include/clang/AST/CommentCommands.td b/clang/include/clang/AST/CommentCommands.td index fbbfc9f7e0b..7e962a4b417 100644 --- a/clang/include/clang/AST/CommentCommands.td +++ b/clang/include/clang/AST/CommentCommands.td @@ -87,8 +87,21 @@ def P : InlineCommand<"p">; def A : InlineCommand<"a">; def E : InlineCommand<"e">; def Em : InlineCommand<"em">; -def Ref : InlineCommand<"ref">; -def Anchor : InlineCommand<"anchor">; +def Emoji : InlineCommand<"emoji">; + +def Anchor : InlineCommand<"anchor">; +def Ref : InlineCommand<"ref">; +def RefItem : InlineCommand<"refitem">; +def Cite : InlineCommand<"cite">; + +def CopyBrief : InlineCommand<"copybrief">; +def CopyDetails : InlineCommand<"copydetails">; +def CopyDoc : InlineCommand<"copydoc">; + +// Typically not used inline, but they take a single word. +def Extends : InlineCommand<"extends">; +def Implements : InlineCommand<"implements">; +def MemberOf : InlineCommand<"memberof">; //===----------------------------------------------------------------------===// // BlockCommand @@ -145,9 +158,11 @@ def Retval : BlockCommand<"retval">; def Sa : BlockCommand<"sa">; def See : BlockCommand<"see">; def Since : BlockCommand<"since">; +def Test : BlockCommand<"test">; def Todo : BlockCommand<"todo">; def Version : BlockCommand<"version">; def Warning : BlockCommand<"warning">; +def XRefItem : BlockCommand<"xrefitem">; // HeaderDoc commands def Abstract : BlockCommand<"abstract"> { let IsBriefCommand = 1; } def ClassDesign : RecordLikeDetailCommand<"classdesign">; @@ -170,6 +185,8 @@ def SuperClass : RecordLikeDetailCommand<"superclass">; defm Code : VerbatimBlockCommand<"code", "endcode">; defm Verbatim : VerbatimBlockCommand<"verbatim", "endverbatim">; + +defm DocbookOnly : VerbatimBlockCommand<"docbookonly", "enddocbookonly">; defm Htmlonly : VerbatimBlockCommand<"htmlonly", "endhtmlonly">; defm Latexonly : VerbatimBlockCommand<"latexonly", "endlatexonly">; defm Xmlonly : VerbatimBlockCommand<"xmlonly", "endxmlonly">; @@ -178,10 +195,19 @@ defm Rtfonly : VerbatimBlockCommand<"rtfonly", "endrtfonly">; defm Dot : VerbatimBlockCommand<"dot", "enddot">; defm Msc : VerbatimBlockCommand<"msc", "endmsc">; +defm Uml : VerbatimBlockCommand<"startuml", "enduml">; + +// Actually not verbatim blocks, we should also parse commands within them. +defm Internal : VerbatimBlockCommand<"internal", "endinternal">; +// TODO: conflicts with HeaderDoc link, /link. +//defm Link : VerbatimBlockCommand<"link", "endlink">; +defm ParBlock : VerbatimBlockCommand<"parblock", "endparblock">; +defm SecRefList : VerbatimBlockCommand<"secreflist", "endsecreflist">; // These three commands have special support in CommentLexer to recognize their // names. def FDollar : VerbatimBlockCommand<"f$">; // Inline LaTeX formula +defm FParen : VerbatimBlockCommand<"f(", "f)">; // Inline LaTeX text defm FBracket : VerbatimBlockCommand<"f[", "f]">; // Displayed LaTeX formula defm FBrace : VerbatimBlockCommand<"f{", "f}">; // LaTeX environment @@ -199,11 +225,18 @@ def Addtogroup : VerbatimLineCommand<"addtogroup">; def Weakgroup : VerbatimLineCommand<"weakgroup">; def Name : VerbatimLineCommand<"name">; +// These actually take a single word, but it's optional. +// And they're used on a separate line typically, not inline. +def Dir : VerbatimLineCommand<"dir">; +def File : VerbatimLineCommand<"file">; + def Section : VerbatimLineCommand<"section">; def Subsection : VerbatimLineCommand<"subsection">; def Subsubsection : VerbatimLineCommand<"subsubsection">; def Paragraph : VerbatimLineCommand<"paragraph">; +def TableOfContents : VerbatimLineCommand<"tableofcontents">; +def Page : VerbatimLineCommand<"page">; def Mainpage : VerbatimLineCommand<"mainpage">; def Subpage : VerbatimLineCommand<"subpage">; @@ -212,13 +245,79 @@ def Related : VerbatimLineCommand<"related">; def RelatesAlso : VerbatimLineCommand<"relatesalso">; def RelatedAlso : VerbatimLineCommand<"relatedalso">; +def AddIndex : VerbatimLineCommand<"addindex">; + +// These take a single argument mostly, but since they include a file they'll +// typically be on their own line. +def DocbookInclude : VerbatimLineCommand<"docbookinclude">; +def DontInclude : VerbatimLineCommand<"dontinclude">; +def Example : VerbatimLineCommand<"example">; +def HtmlInclude : VerbatimLineCommand<"htmlinclude">; +def Include : VerbatimLineCommand<"include">; +def ManInclude : VerbatimLineCommand<"maninclude">; +def LatexInclude : VerbatimLineCommand<"latexinclude">; +def RtfInclude : VerbatimLineCommand<"rtfinclude">; +def Snippet : VerbatimLineCommand<"snippet">; +def VerbInclude : VerbatimLineCommand<"verbinclude">; +def XmlInclude : VerbatimLineCommand<"xmlinclude">; + +def Image : VerbatimLineCommand<"image">; +def DotFile : VerbatimLineCommand<"dotfile">; +def MscFile : VerbatimLineCommand<"mscfile">; +def DiaFile : VerbatimLineCommand<"diafile">; + +def Line : VerbatimLineCommand<"line">; +def Skip : VerbatimLineCommand<"skip">; +def SkipLine : VerbatimLineCommand<"skipline">; +def Until : VerbatimLineCommand<"until">; + +def NoOp : VerbatimLineCommand<"noop">; + +// These have actually no arguments, but we can treat them as line commands. +def CallGraph : VerbatimLineCommand<"callgraph">; +def HideCallGraph : VerbatimLineCommand<"hidecallgraph">; +def CallerGraph : VerbatimLineCommand<"callergraph">; +def HideCallerGraph : VerbatimLineCommand<"hidecallergraph">; +def ShowInitializer : VerbatimLineCommand<"showinitializer">; +def HideInitializer : VerbatimLineCommand<"hideinitializer">; +def ShowRefBy : VerbatimLineCommand<"showrefby">; +def HideRefBy : VerbatimLineCommand<"hiderefby">; +def ShowRefs : VerbatimLineCommand<"showrefs">; +def HideRefs : VerbatimLineCommand<"hiderefs">; + +// These also have no argument. +def Private : VerbatimLineCommand<"private">; +def Protected : VerbatimLineCommand<"protected">; +def Public : VerbatimLineCommand<"public">; +def Pure : VerbatimLineCommand<"pure">; +def Static : VerbatimLineCommand<"static">; + +// These also have no argument. +def NoSubgrouping : VerbatimLineCommand<"nosubgrouping">; +def PrivateSection : VerbatimLineCommand<"privatesection">; +def ProtectedSection : VerbatimLineCommand<"protectedsection">; +def PublicSection : VerbatimLineCommand<"publicsection">; + +// We might also build proper support for if/ifnot/else/elseif/endif. +def If : VerbatimLineCommand<"if">; +def IfNot : VerbatimLineCommand<"ifnot">; +def Else : VerbatimLineCommand<"else">; +def ElseIf : VerbatimLineCommand<"elseif">; +def Endif : VerbatimLineCommand<"endif">; + +// Not treated as VerbatimBlockCommand because it spans multiple comments. +def Cond : VerbatimLineCommand<"cond">; +def EndCond : VerbatimLineCommand<"endcond">; + //===----------------------------------------------------------------------===// // DeclarationVerbatimLineCommand //===----------------------------------------------------------------------===// // Doxygen commands. +def Concept : DeclarationVerbatimLineCommand<"concept">; def Def : DeclarationVerbatimLineCommand<"def">; def Fn : DeclarationVerbatimLineCommand<"fn">; +def IDLExcept : DeclarationVerbatimLineCommand<"idlexcept">; def Namespace : DeclarationVerbatimLineCommand<"namespace">; def Overload : DeclarationVerbatimLineCommand<"overload">; def Property : DeclarationVerbatimLineCommand<"property">; diff --git a/clang/include/clang/AST/CommentHTMLTags.td b/clang/include/clang/AST/CommentHTMLTags.td index 25149009494..a1ce8c6da96 100644 --- a/clang/include/clang/AST/CommentHTMLTags.td +++ b/clang/include/clang/AST/CommentHTMLTags.td @@ -52,11 +52,11 @@ def Tr : Tag<"tr"> { let EndTagOptional = 1; } def Th : Tag<"th"> { let EndTagOptional = 1; } def Td : Tag<"td"> { let EndTagOptional = 1; } -// Define a blacklist of attributes that are not safe to pass through to HTML +// Define a list of attributes that are not safe to pass through to HTML // output if the input is untrusted. // -// FIXME: this should be a whitelist. When changing this to a whitelist, don't -// forget to change the default in the TableGen backend. +// FIXME: This should be a list of attributes that _are_ safe. When changing +// this change, don't forget to change the default in the TableGen backend. class Attribute { string Spelling = spelling; bit IsSafeToPassThrough = 1; diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h index 6dfe0f4920d..015ce8f8652 100644 --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -181,6 +181,7 @@ public: FullComment *actOnFullComment(ArrayRef Blocks); +private: void checkBlockCommandEmptyParagraph(BlockCommandComment *Command); void checkReturnsCommand(const BlockCommandComment *Command); @@ -201,16 +202,16 @@ public: /// Emit diagnostics about unknown parametrs. void resolveParamCommandIndexes(const FullComment *FC); + /// \returns \c true if the declaration that this comment is attached to + /// is a pointer to function/method/block type or has such a type. + bool involvesFunctionType(); + bool isFunctionDecl(); bool isAnyFunctionDecl(); /// \returns \c true if declaration that this comment is attached to declares /// a function pointer. bool isFunctionPointerVarDecl(); - /// \returns \c true if the declaration that this comment is attached to - /// declares a variable or a field whose type is a function or a block - /// pointer. - bool isFunctionOrBlockPointerVarLikeDecl(); bool isFunctionOrMethodVariadic(); bool isObjCMethodDecl(); bool isObjCPropertyDecl(); diff --git a/clang/include/clang/AST/ComparisonCategories.h b/clang/include/clang/AST/ComparisonCategories.h index b41e934142e..7b73b582fe2 100644 --- a/clang/include/clang/AST/ComparisonCategories.h +++ b/clang/include/clang/AST/ComparisonCategories.h @@ -115,8 +115,7 @@ private: public: /// The declaration for the comparison category type from the /// standard library. - // FIXME: Make this const - CXXRecordDecl *Record = nullptr; + const CXXRecordDecl *Record = nullptr; /// The Kind of the comparison category type ComparisonCategoryType Kind; @@ -146,7 +145,7 @@ public: return Kind == CCK::PartialOrdering; } - /// Converts the specified result kind into the the correct result kind + /// Converts the specified result kind into the correct result kind /// for this category. Specifically it lowers strong equality results to /// weak equivalence if needed. ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const { diff --git a/clang/include/clang/AST/CurrentSourceLocExprScope.h b/clang/include/clang/AST/CurrentSourceLocExprScope.h index 4ebbdf63abb..34df8ce1309 100644 --- a/clang/include/clang/AST/CurrentSourceLocExprScope.h +++ b/clang/include/clang/AST/CurrentSourceLocExprScope.h @@ -1,9 +1,8 @@ //===--- CurrentSourceLocExprScope.h ----------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 510bf897898..85a3a8ab697 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -614,7 +614,9 @@ public: if (!isInline()) return false; auto X = lookup(Name); - auto Y = getParent()->lookup(Name); + // We should not perform a lookup within a transparent context, so find a + // non-transparent parent context. + auto Y = getParent()->getNonTransparentContext()->lookup(Name); return std::distance(X.begin(), X.end()) == std::distance(Y.begin(), Y.end()); } @@ -1990,8 +1992,8 @@ private: protected: FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, - ConstexprSpecKind ConstexprKind, + TypeSourceInfo *TInfo, StorageClass S, bool UsesFPIntrin, + bool isInlineSpecified, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause = nullptr); using redeclarable_base = Redeclarable; @@ -2025,23 +2027,23 @@ public: static FunctionDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation NLoc, DeclarationName N, QualType T, - TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified = false, - bool hasWrittenPrototype = true, + TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin = false, + bool isInlineSpecified = false, bool hasWrittenPrototype = true, ConstexprSpecKind ConstexprKind = ConstexprSpecKind::Unspecified, Expr *TrailingRequiresClause = nullptr) { DeclarationNameInfo NameInfo(N, NLoc); return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, SC, - isInlineSpecified, hasWrittenPrototype, - ConstexprKind, TrailingRequiresClause); + UsesFPIntrin, isInlineSpecified, + hasWrittenPrototype, ConstexprKind, + TrailingRequiresClause); } - static FunctionDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, StorageClass SC, - bool isInlineSpecified, bool hasWrittenPrototype, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause); + static FunctionDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool UsesFPIntrin, bool isInlineSpecified, + bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause); static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2594,6 +2596,14 @@ public: FunctionDeclBits.IsInline = I; } + /// Determine whether the function was declared in source context + /// that requires constrained FP intrinsics + bool UsesFPIntrin() const { return FunctionDeclBits.UsesFPIntrin; } + + /// Set whether the function was declared in source context + /// that requires constrained FP intrinsics + void setUsesFPIntrin(bool I) { FunctionDeclBits.UsesFPIntrin = I; } + /// Flag that this function is implicitly inline. void setImplicitlyInline(bool I = true) { FunctionDeclBits.IsInline = I; } @@ -3691,6 +3701,10 @@ public: bool IsFixed); static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID); + /// Overrides to provide correct range when there's an enum-base specifier + /// with forward declarations. + SourceRange getSourceRange() const override LLVM_READONLY; + /// When created, the EnumDecl corresponds to a /// forward-declared enum. This method is used to mark the /// declaration as being defined; its enumerators have already been @@ -4579,7 +4593,7 @@ public: /// into a diagnostic with <<. inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, const NamedDecl *ND) { - PD.AddTaggedVal(reinterpret_cast(ND), + PD.AddTaggedVal(reinterpret_cast(ND), DiagnosticsEngine::ak_nameddecl); return PD; } diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 482d2889a25..18468c8ca1c 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1997,6 +1997,12 @@ public: return const_cast(this)->getNonClosureAncestor(); } + // Retrieve the nearest context that is not a transparent context. + DeclContext *getNonTransparentContext(); + const DeclContext *getNonTransparentContext() const { + return const_cast(this)->getNonTransparentContext(); + } + /// getPrimaryContext - There may be many different /// declarations of the same entity (including forward declarations /// of classes, multiple definitions of namespaces, etc.), each with diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 0d5ad40fc19..cc7bfc86a52 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1857,7 +1857,7 @@ private: TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor) : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo, - SC_None, false, ConstexprSpecKind::Unspecified), + SC_None, false, false, ConstexprSpecKind::Unspecified), Ctor(Ctor), ExplicitSpec(ES) { if (EndLocation.isValid()) setRangeEnd(EndLocation); @@ -1952,23 +1952,22 @@ protected: CXXMethodDecl(Kind DK, ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass SC, - bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, + bool UsesFPIntrin, bool isInline, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr) - : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, isInline, - ConstexprKind, TrailingRequiresClause) { + : FunctionDecl(DK, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, + isInline, ConstexprKind, TrailingRequiresClause) { if (EndLocation.isValid()) setRangeEnd(EndLocation); } public: - static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, StorageClass SC, - bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, - Expr *TrailingRequiresClause = nullptr); + static CXXMethodDecl * + Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + StorageClass SC, bool UsesFPIntrin, bool isInline, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause = nullptr); static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2413,7 +2412,8 @@ class CXXConstructorDecl final CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline, + TypeSourceInfo *TInfo, ExplicitSpecifier ES, + bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited, Expr *TrailingRequiresClause); @@ -2456,8 +2456,8 @@ public: static CXXConstructorDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, + ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, + bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited = InheritedConstructor(), Expr *TrailingRequiresClause = nullptr); @@ -2676,25 +2676,24 @@ class CXXDestructorDecl : public CXXMethodDecl { CXXDestructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, bool isInline, + TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause = nullptr) : CXXMethodDecl(CXXDestructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, ConstexprKind, SourceLocation(), - TrailingRequiresClause) { + SC_None, UsesFPIntrin, isInline, ConstexprKind, + SourceLocation(), TrailingRequiresClause) { setImplicit(isImplicitlyDeclared); } void anchor() override; public: - static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause = nullptr); + static CXXDestructorDecl * + Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause = nullptr); static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg); @@ -2732,12 +2731,13 @@ public: class CXXConversionDecl : public CXXMethodDecl { CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES, - ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + TypeSourceInfo *TInfo, bool UsesFPIntrin, bool isInline, + ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr) : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, ConstexprKind, EndLocation, - TrailingRequiresClause), + SC_None, UsesFPIntrin, isInline, ConstexprKind, + EndLocation, TrailingRequiresClause), ExplicitSpec(ES) {} void anchor() override; @@ -2750,8 +2750,9 @@ public: static CXXConversionDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, Expr *TrailingRequiresClause = nullptr); + bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause = nullptr); static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); ExplicitSpecifier getExplicitSpecifier() { diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index 2eef2343b75..9899fc29b82 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -78,8 +78,7 @@ class StoredDeclsList { } Data.setPointer(NewHead); - assert(llvm::find_if(getLookupResult(), ShouldErase) == - getLookupResult().end() && "Still exists!"); + assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!"); } void erase(NamedDecl *ND) { diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 6bb9cdf6703..79ec1d6e5c3 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -487,6 +487,9 @@ public: /// True if the method is tagged as objc_direct bool isDirectMethod() const; + /// True if the method has a parameter that's destroyed in the callee. + bool hasParamDestroyedInCallee() const; + /// Returns the property associated with this method's selector. /// /// Note that even if this particular method is not marked as a property @@ -1955,6 +1958,13 @@ public: const ObjCIvarDecl *getNextIvar() const { return NextIvar; } void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; } + ObjCIvarDecl *getCanonicalDecl() override { + return cast(FieldDecl::getCanonicalDecl()); + } + const ObjCIvarDecl *getCanonicalDecl() const { + return const_cast(this)->getCanonicalDecl(); + } + void setAccessControl(AccessControl ac) { DeclAccess = ac; } AccessControl getAccessControl() const { return AccessControl(DeclAccess); } diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index cbaa287f225..d33babef958 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -203,7 +203,8 @@ public: void print(raw_ostream &Out, const ASTContext &Context, const PrintingPolicy &Policy, bool OmitTemplateKW = false) const; - static bool shouldIncludeTypeForArgument(const TemplateParameterList *TPL, + static bool shouldIncludeTypeForArgument(const PrintingPolicy &Policy, + const TemplateParameterList *TPL, unsigned Idx); }; @@ -729,6 +730,10 @@ public: /// Returns the number of explicit template arguments that were given. unsigned getNumTemplateArgs() const { return NumArgs; } + llvm::ArrayRef arguments() const { + return llvm::makeArrayRef(getTemplateArgs(), getNumTemplateArgs()); + } + /// Returns the nth template argument. const TemplateArgumentLoc &getTemplateArg(unsigned I) const { assert(I < getNumTemplateArgs() && "template arg index out of range"); @@ -1189,7 +1194,7 @@ class TemplateTypeParmDecl final : public TypeDecl, /// Whether the type constraint has been initialized. This can be false if the /// constraint was not initialized yet or if there was an error forming the - /// type constriant. + /// type constraint. bool TypeConstraintInitialized : 1; /// Whether this non-type template parameter is an "expanded" diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 06164411cc2..991abef7336 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -740,6 +740,12 @@ public: bool tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, unsigned Type) const; + /// If the current Expr is a pointer, this will try to statically + /// determine the strlen of the string pointed to. + /// Returns true if all of the above holds and we were able to figure out the + /// strlen, false otherwise. + bool tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const; + /// Enumeration used to describe the kind of Null pointer constant /// returned from \c isNullPointerConstant(). enum NullPointerConstantKind { diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index a96e21993e2..5638df42a1c 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -1,9 +1,8 @@ //===--- JSONNodeDumper.h - Printing of AST nodes to JSON -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/clang/include/clang/AST/LambdaCapture.h b/clang/include/clang/AST/LambdaCapture.h index 8e2806545dd..7ad1e2361e4 100644 --- a/clang/include/clang/AST/LambdaCapture.h +++ b/clang/include/clang/AST/LambdaCapture.h @@ -86,7 +86,7 @@ public: /// Determine whether this capture handles a variable. bool capturesVariable() const { - return dyn_cast_or_null(DeclAndBits.getPointer()); + return isa_and_nonnull(DeclAndBits.getPointer()); } /// Determine whether this captures a variable length array bound diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 8bc3e25c0f4..eb01780598a 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -521,7 +521,7 @@ public: /// NestedNameSpecifiers into a diagnostic with <<. inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, NestedNameSpecifier *NNS) { - DB.AddTaggedVal(reinterpret_cast(NNS), + DB.AddTaggedVal(reinterpret_cast(NNS), DiagnosticsEngine::ak_nestednamespec); return DB; } diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index aaddcfa307d..565eb0c9cf9 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -322,6 +322,81 @@ public: } }; +/// This represents the 'align' clause in the '#pragma omp allocate' +/// directive. +/// +/// \code +/// #pragma omp allocate(a) allocator(omp_default_mem_alloc) align(8) +/// \endcode +/// In this example directive '#pragma omp allocate' has simple 'allocator' +/// clause with the allocator 'omp_default_mem_alloc' and align clause with +/// value of 8. +class OMPAlignClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// Alignment specified with align clause. + Stmt *Alignment = nullptr; + + /// Set alignment value. + void setAlignment(Expr *A) { Alignment = A; } + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + /// Build 'align' clause with the given alignment + /// + /// \param A Alignment value. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPAlignClause(Expr *A, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_align, StartLoc, EndLoc), + LParenLoc(LParenLoc), Alignment(A) {} + + /// Build an empty clause. + OMPAlignClause() + : OMPClause(llvm::omp::OMPC_align, SourceLocation(), SourceLocation()) {} + +public: + /// Build 'align' clause with the given alignment + /// + /// \param A Alignment value. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + static OMPAlignClause *Create(const ASTContext &C, Expr *A, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns alignment + Expr *getAlignment() const { return cast_or_null(Alignment); } + + child_range children() { return child_range(&Alignment, &Alignment + 1); } + + const_child_range children() const { + return const_child_range(&Alignment, &Alignment + 1); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_align; + } +}; + /// This represents clause 'allocate' in the '#pragma omp ...' directives. /// /// \code @@ -2005,13 +2080,13 @@ class OMPUpdateClause final return IsExtended ? 2 : 0; } - /// Sets the the location of '(' in clause for 'depobj' directive. + /// Sets the location of '(' in clause for 'depobj' directive. void setLParenLoc(SourceLocation Loc) { assert(IsExtended && "Expected extended clause."); *getTrailingObjects() = Loc; } - /// Sets the the location of '(' in clause for 'depobj' directive. + /// Sets the location of '(' in clause for 'depobj' directive. void setArgumentLoc(SourceLocation Loc) { assert(IsExtended && "Expected extended clause."); *std::next(getTrailingObjects(), 1) = Loc; @@ -2085,13 +2160,13 @@ public: return const_child_range(const_child_iterator(), const_child_iterator()); } - /// Gets the the location of '(' in clause for 'depobj' directive. + /// Gets the location of '(' in clause for 'depobj' directive. SourceLocation getLParenLoc() const { assert(IsExtended && "Expected extended clause."); return *getTrailingObjects(); } - /// Gets the the location of argument in clause for 'depobj' directive. + /// Gets the location of argument in clause for 'depobj' directive. SourceLocation getArgumentLoc() const { assert(IsExtended && "Expected extended clause."); return *std::next(getTrailingObjects(), 1); @@ -5606,7 +5681,8 @@ private: /// Map-type-modifiers for the 'map' clause. OpenMPMapModifierKind MapTypeModifiers[NumberOfOMPMapClauseModifiers] = { OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, - OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; + OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown}; /// Location of map-type-modifiers for the 'map' clause. SourceLocation MapTypeModifiersLoc[NumberOfOMPMapClauseModifiers]; @@ -8404,6 +8480,96 @@ public: } }; +/// This represents 'bind' clause in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp loop bind(parallel) +/// \endcode +class OMPBindClause final : public OMPClause { + friend class OMPClauseReader; + + /// Location of '('. + SourceLocation LParenLoc; + + /// The binding kind of 'bind' clause. + OpenMPBindClauseKind Kind = OMPC_BIND_unknown; + + /// Start location of the kind in source code. + SourceLocation KindLoc; + + /// Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + + /// Set the binding kind. + void setBindKind(OpenMPBindClauseKind K) { Kind = K; } + + /// Set the binding kind location. + void setBindKindLoc(SourceLocation KLoc) { KindLoc = KLoc; } + + /// Build 'bind' clause with kind \a K ('teams', 'parallel', or 'thread'). + /// + /// \param K Binding kind of the clause ('teams', 'parallel' or 'thread'). + /// \param KLoc Starting location of the binding kind. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + OMPBindClause(OpenMPBindClauseKind K, SourceLocation KLoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(llvm::omp::OMPC_bind, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(K), KindLoc(KLoc) {} + + /// Build an empty clause. + OMPBindClause() + : OMPClause(llvm::omp::OMPC_bind, SourceLocation(), SourceLocation()) {} + +public: + /// Build 'bind' clause with kind \a K ('teams', 'parallel', or 'thread'). + /// + /// \param C AST context + /// \param K Binding kind of the clause ('teams', 'parallel' or 'thread'). + /// \param KLoc Starting location of the binding kind. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + static OMPBindClause *Create(const ASTContext &C, OpenMPBindClauseKind K, + SourceLocation KLoc, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc); + + /// Build an empty 'bind' clause. + /// + /// \param C AST context + static OMPBindClause *CreateEmpty(const ASTContext &C); + + /// Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// Returns kind of the clause. + OpenMPBindClauseKind getBindKind() const { return Kind; } + + /// Returns location of clause kind. + SourceLocation getBindKindLoc() const { return KindLoc; } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_bind; + } +}; + /// This class implements a simple visitor for OMPClause /// subclasses. template class Ptr, typename RetTy> @@ -8546,10 +8712,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI); /// Clang specific specialization of the OMPContext to lookup target features. struct TargetOMPContext final : public llvm::omp::OMPContext { - TargetOMPContext(ASTContext &ASTCtx, std::function &&DiagUnknownTrait, - const FunctionDecl *CurrentFunctionDecl); + const FunctionDecl *CurrentFunctionDecl, + ArrayRef ConstructTraits); + virtual ~TargetOMPContext() = default; /// See llvm::omp::OMPContext::matchesISATrait diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h index 3baf2b2ba94..f6816e938f2 100644 --- a/clang/include/clang/AST/PrettyPrinter.h +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -74,7 +74,8 @@ struct PrintingPolicy { MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true), MSVCFormatting(false), ConstantsAsWritten(false), SuppressImplicitBase(false), FullyQualifiedName(false), - PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true) {} + PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true), + UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false) {} /// Adjust this printing policy for cases where it's known that we're /// printing C++ code (for instance, if AST dumping reaches a C++-only @@ -273,6 +274,14 @@ struct PrintingPolicy { /// invalid C++ code. unsigned PrintInjectedClassNameWithArguments : 1; + /// Whether to use C++ template preferred_name attributes when printing + /// templates. + unsigned UsePreferredNames : 1; + + /// Whether to use type suffixes (eg: 1U) on integral non-type template + /// parameters. + unsigned AlwaysIncludeTypeForTemplateArgument : 1; + /// Callbacks to use to allow the behavior of printing to be customized. const PrintingCallbacks *Callbacks = nullptr; }; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 9bfa5b9c232..9797eac53dd 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1681,10 +1681,7 @@ bool RecursiveASTVisitor::TraverseTemplateInstantiations( ClassTemplateDecl *D) { for (auto *SD : D->specializations()) { for (auto *RD : SD->redecls()) { - // We don't want to visit injected-class-names in this traversal. - if (cast(RD)->isInjectedClassName()) - continue; - + assert(!cast(RD)->isInjectedClassName()); switch ( cast(RD)->getSpecializationKind()) { // Visit the implicit instantiations with the requested pattern. @@ -1863,10 +1860,9 @@ DEF_TRAVERSE_DECL(UnresolvedUsingIfExistsDecl, {}) DEF_TRAVERSE_DECL(EnumDecl, { TRY_TO(TraverseDeclTemplateParameterLists(D)); - if (D->getTypeForDecl()) - TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); - TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + if (auto *TSI = D->getIntegerTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); // The enumerators are already traversed by // decls_begin()/decls_end(). }) @@ -2842,6 +2838,9 @@ RecursiveASTVisitor::TraverseOMPLoopDirective(OMPLoopDirective *S) { return TraverseOMPExecutableDirective(S); } +DEF_TRAVERSE_STMT(OMPMetaDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + DEF_TRAVERSE_STMT(OMPParallelDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) @@ -3021,6 +3020,9 @@ DEF_TRAVERSE_STMT(OMPDispatchDirective, DEF_TRAVERSE_STMT(OMPMaskedDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); }) +DEF_TRAVERSE_STMT(OMPGenericLoopDirective, + { TRY_TO(TraverseOMPExecutableDirective(S)); }) + // OpenMP clauses. template bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { @@ -3091,6 +3093,12 @@ RecursiveASTVisitor::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPAlignClause(OMPAlignClause *C) { + TRY_TO(TraverseStmt(C->getAlignment())); + return true; +} + template bool RecursiveASTVisitor::VisitOMPSafelenClause(OMPSafelenClause *C) { TRY_TO(TraverseStmt(C->getSafelen())); @@ -3674,6 +3682,11 @@ bool RecursiveASTVisitor::VisitOMPFilterClause(OMPFilterClause *C) { return true; } +template +bool RecursiveASTVisitor::VisitOMPBindClause(OMPBindClause *C) { + return true; +} + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 8e1d7df9709..a32126d23d3 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -20,6 +20,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" +#include "clang/Basic/Specifiers.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/ADT/PointerIntPair.h" @@ -160,8 +161,8 @@ protected: unsigned : NumStmtBits; - /// True if this if statement is a constexpr if. - unsigned IsConstexpr : 1; + /// Whether this is a constexpr if, or a consteval if, or neither. + unsigned Kind : 3; /// True if this if statement has storage for an else statement. unsigned HasElse : 1; @@ -1215,6 +1216,11 @@ public: const PrintingPolicy &Policy, unsigned Indentation = 0, StringRef NewlineSymbol = "\n", const ASTContext *Context = nullptr) const; + void printPrettyControlled(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0, + StringRef NewlineSymbol = "\n", + const ASTContext *Context = nullptr) const; /// Pretty-prints in JSON format. void printJson(raw_ostream &Out, PrinterHelper *Helper, @@ -1950,8 +1956,8 @@ class IfStmt final unsigned elseOffset() const { return condOffset() + ElseOffsetFromCond; } /// Build an if/then/else statement. - IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, Stmt *Init, - VarDecl *Var, Expr *Cond, SourceLocation LParenLoc, + IfStmt(const ASTContext &Ctx, SourceLocation IL, IfStatementKind Kind, + Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LParenLoc, SourceLocation RParenLoc, Stmt *Then, SourceLocation EL, Stmt *Else); /// Build an empty if/then/else statement. @@ -1960,9 +1966,9 @@ class IfStmt final public: /// Create an IfStmt. static IfStmt *Create(const ASTContext &Ctx, SourceLocation IL, - bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, - SourceLocation LPL, SourceLocation RPL, Stmt *Then, - SourceLocation EL = SourceLocation(), + IfStatementKind Kind, Stmt *Init, VarDecl *Var, + Expr *Cond, SourceLocation LPL, SourceLocation RPL, + Stmt *Then, SourceLocation EL = SourceLocation(), Stmt *Else = nullptr); /// Create an empty IfStmt optionally with storage for an else statement, @@ -2077,8 +2083,30 @@ public: *getTrailingObjects() = ElseLoc; } - bool isConstexpr() const { return IfStmtBits.IsConstexpr; } - void setConstexpr(bool C) { IfStmtBits.IsConstexpr = C; } + bool isConsteval() const { + return getStatementKind() == IfStatementKind::ConstevalNonNegated || + getStatementKind() == IfStatementKind::ConstevalNegated; + } + + bool isNonNegatedConsteval() const { + return getStatementKind() == IfStatementKind::ConstevalNonNegated; + } + + bool isNegatedConsteval() const { + return getStatementKind() == IfStatementKind::ConstevalNegated; + } + + bool isConstexpr() const { + return getStatementKind() == IfStatementKind::Constexpr; + } + + void setStatementKind(IfStatementKind Kind) { + IfStmtBits.Kind = static_cast(Kind); + } + + IfStatementKind getStatementKind() const { + return static_cast(IfStmtBits.Kind); + } /// If this is an 'if constexpr', determine which substatement will be taken. /// Otherwise, or if the condition is value-dependent, returns None. @@ -2101,13 +2129,19 @@ public: // Iterators over subexpressions. The iterators will include iterating // over the initialization expression referenced by the condition variable. child_range children() { - return child_range(getTrailingObjects(), + // We always store a condition, but there is none for consteval if + // statements, so skip it. + return child_range(getTrailingObjects() + + (isConsteval() ? thenOffset() : 0), getTrailingObjects() + numTrailingObjects(OverloadToken())); } const_child_range children() const { - return const_child_range(getTrailingObjects(), + // We always store a condition, but there is none for consteval if + // statements, so skip it. + return const_child_range(getTrailingObjects() + + (isConsteval() ? thenOffset() : 0), getTrailingObjects() + numTrailingObjects(OverloadToken())); } diff --git a/clang/include/clang/AST/StmtObjC.h b/clang/include/clang/AST/StmtObjC.h index 948ef2421cb..c46ff4634c8 100644 --- a/clang/include/clang/AST/StmtObjC.h +++ b/clang/include/clang/AST/StmtObjC.h @@ -162,8 +162,14 @@ public: }; /// Represents Objective-C's \@try ... \@catch ... \@finally statement. -class ObjCAtTryStmt : public Stmt { -private: +class ObjCAtTryStmt final + : public Stmt, + private llvm::TrailingObjects { + friend TrailingObjects; + size_t numTrailingObjects(OverloadToken) const { + return 1 + NumCatchStmts + HasFinally; + } + // The location of the @ in the \@try. SourceLocation AtTryLoc; @@ -178,10 +184,8 @@ private: /// The order of the statements in memory follows the order in the source, /// with the \@try body first, followed by the \@catch statements (if any) /// and, finally, the \@finally (if it exists). - Stmt **getStmts() { return reinterpret_cast (this + 1); } - const Stmt* const *getStmts() const { - return reinterpret_cast (this + 1); - } + Stmt **getStmts() { return getTrailingObjects(); } + Stmt *const *getStmts() const { return getTrailingObjects(); } ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, Stmt **CatchStmts, unsigned NumCatchStmts, @@ -257,13 +261,34 @@ public: } child_range children() { - return child_range(getStmts(), - getStmts() + 1 + NumCatchStmts + HasFinally); + return child_range( + getStmts(), getStmts() + numTrailingObjects(OverloadToken())); } const_child_range children() const { return const_child_range(const_cast(this)->children()); } + + using catch_stmt_iterator = CastIterator; + using const_catch_stmt_iterator = ConstCastIterator; + using catch_range = llvm::iterator_range; + using catch_const_range = llvm::iterator_range; + + catch_stmt_iterator catch_stmts_begin() { return getStmts() + 1; } + catch_stmt_iterator catch_stmts_end() { + return catch_stmts_begin() + NumCatchStmts; + } + catch_range catch_stmts() { + return catch_range(catch_stmts_begin(), catch_stmts_end()); + } + + const_catch_stmt_iterator catch_stmts_begin() const { return getStmts() + 1; } + const_catch_stmt_iterator catch_stmts_end() const { + return catch_stmts_begin() + NumCatchStmts; + } + catch_const_range catch_stmts() const { + return catch_const_range(catch_stmts_begin(), catch_stmts_end()); + } }; /// Represents Objective-C's \@synchronized statement. diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 9c85df741f4..d5b5c9580da 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -889,22 +889,23 @@ public: /// Calls the specified callback function for all the loops in \p CurStmt, /// from the outermost to the innermost. - static bool doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops, - unsigned NumLoops, - llvm::function_ref Callback, - llvm::function_ref - OnTransformationCallback); + static bool + doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops, + unsigned NumLoops, + llvm::function_ref Callback, + llvm::function_ref + OnTransformationCallback); static bool doForAllLoops(const Stmt *CurStmt, bool TryImperfectlyNestedLoops, unsigned NumLoops, llvm::function_ref Callback, - llvm::function_ref + llvm::function_ref OnTransformationCallback) { auto &&NewCallback = [Callback](unsigned Cnt, Stmt *CurStmt) { return Callback(Cnt, CurStmt); }; auto &&NewTransformCb = - [OnTransformationCallback](OMPLoopBasedDirective *A) { + [OnTransformationCallback](OMPLoopTransformationDirective *A) { OnTransformationCallback(A); }; return doForAllLoops(const_cast(CurStmt), TryImperfectlyNestedLoops, @@ -917,7 +918,7 @@ public: doForAllLoops(Stmt *CurStmt, bool TryImperfectlyNestedLoops, unsigned NumLoops, llvm::function_ref Callback) { - auto &&TransformCb = [](OMPLoopBasedDirective *) {}; + auto &&TransformCb = [](OMPLoopTransformationDirective *) {}; return doForAllLoops(CurStmt, TryImperfectlyNestedLoops, NumLoops, Callback, TransformCb); } @@ -954,6 +955,47 @@ public: } }; +/// The base class for all loop transformation directives. +class OMPLoopTransformationDirective : public OMPLoopBasedDirective { + friend class ASTStmtReader; + + /// Number of loops generated by this loop transformation. + unsigned NumGeneratedLoops = 0; + +protected: + explicit OMPLoopTransformationDirective(StmtClass SC, + OpenMPDirectiveKind Kind, + SourceLocation StartLoc, + SourceLocation EndLoc, + unsigned NumAssociatedLoops) + : OMPLoopBasedDirective(SC, Kind, StartLoc, EndLoc, NumAssociatedLoops) {} + + /// Set the number of loops generated by this loop transformation. + void setNumGeneratedLoops(unsigned Num) { NumGeneratedLoops = Num; } + +public: + /// Return the number of associated (consumed) loops. + unsigned getNumAssociatedLoops() const { return getLoopsNumber(); } + + /// Return the number of loops generated by this loop transformation. + unsigned getNumGeneratedLoops() { return NumGeneratedLoops; } + + /// Get the de-sugared statements after after the loop transformation. + /// + /// Might be nullptr if either the directive generates no loops and is handled + /// directly in CodeGen, or resolving a template-dependence context is + /// required. + Stmt *getTransformedStmt() const; + + /// Return preinits statement. + Stmt *getPreInits() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPTileDirectiveClass || + T->getStmtClass() == OMPUnrollDirectiveClass; + } +}; + /// This is a common base class for loop directives ('omp simd', 'omp /// for', 'omp for simd' etc.). It is responsible for the loop code generation. /// @@ -1102,7 +1144,7 @@ protected: if (isOpenMPLoopBoundSharingDirective(Kind)) return CombinedDistributeEnd; if (isOpenMPWorksharingDirective(Kind) || isOpenMPTaskLoopDirective(Kind) || - isOpenMPDistributeDirective(Kind)) + isOpenMPGenericLoopDirective(Kind) || isOpenMPDistributeDirective(Kind)) return WorksharingEnd; return DefaultEnd; } @@ -1134,6 +1176,7 @@ protected: } void setIsLastIterVariable(Expr *IL) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1141,6 +1184,7 @@ protected: } void setLowerBoundVariable(Expr *LB) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1148,6 +1192,7 @@ protected: } void setUpperBoundVariable(Expr *UB) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1155,6 +1200,7 @@ protected: } void setStrideVariable(Expr *ST) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1162,6 +1208,7 @@ protected: } void setEnsureUpperBound(Expr *EUB) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1169,6 +1216,7 @@ protected: } void setNextLowerBound(Expr *NLB) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1176,6 +1224,7 @@ protected: } void setNextUpperBound(Expr *NUB) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1183,6 +1232,7 @@ protected: } void setNumIterations(Expr *NI) { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1285,6 +1335,7 @@ public: Stmt *getPreInits() { return Data->getChildren()[PreInitsOffset]; } Expr *getIsLastIterVariable() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1292,6 +1343,7 @@ public: } Expr *getLowerBoundVariable() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1299,6 +1351,7 @@ public: } Expr *getUpperBoundVariable() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1306,6 +1359,7 @@ public: } Expr *getStrideVariable() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1313,6 +1367,7 @@ public: } Expr *getEnsureUpperBound() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1320,6 +1375,7 @@ public: } Expr *getNextLowerBound() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1327,6 +1383,7 @@ public: } Expr *getNextUpperBound() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1334,6 +1391,7 @@ public: } Expr *getNumIterations() const { assert((isOpenMPWorksharingDirective(getDirectiveKind()) || + isOpenMPGenericLoopDirective(getDirectiveKind()) || isOpenMPTaskLoopDirective(getDirectiveKind()) || isOpenMPDistributeDirective(getDirectiveKind())) && "expected worksharing loop directive"); @@ -1467,6 +1525,7 @@ public: T->getStmtClass() == OMPTaskLoopSimdDirectiveClass || T->getStmtClass() == OMPMasterTaskLoopDirectiveClass || T->getStmtClass() == OMPMasterTaskLoopSimdDirectiveClass || + T->getStmtClass() == OMPGenericLoopDirectiveClass || T->getStmtClass() == OMPParallelMasterTaskLoopDirectiveClass || T->getStmtClass() == OMPParallelMasterTaskLoopSimdDirectiveClass || T->getStmtClass() == OMPDistributeDirectiveClass || @@ -2510,15 +2569,20 @@ public: /// \param C AST context. /// \param StartLoc Starting location of the directive kind. /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. /// - static OMPTaskwaitDirective * - Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc); + static OMPTaskwaitDirective *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses); /// Creates an empty directive. /// /// \param C AST context. + /// \param NumClauses Number of clauses. /// - static OMPTaskwaitDirective *CreateEmpty(const ASTContext &C, EmptyShell); + static OMPTaskwaitDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell); static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTaskwaitDirectiveClass; @@ -2794,16 +2858,25 @@ class OMPAtomicDirective : public OMPExecutableDirective { : OMPExecutableDirective(OMPAtomicDirectiveClass, llvm::omp::OMPD_atomic, SourceLocation(), SourceLocation()) {} + enum DataPositionTy : size_t { + POS_X = 0, + POS_V, + POS_E, + POS_UpdateExpr, + }; + /// Set 'x' part of the associated expression/statement. - void setX(Expr *X) { Data->getChildren()[0] = X; } + void setX(Expr *X) { Data->getChildren()[DataPositionTy::POS_X] = X; } /// Set helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. - void setUpdateExpr(Expr *UE) { Data->getChildren()[1] = UE; } + void setUpdateExpr(Expr *UE) { + Data->getChildren()[DataPositionTy::POS_UpdateExpr] = UE; + } /// Set 'v' part of the associated expression/statement. - void setV(Expr *V) { Data->getChildren()[2] = V; } + void setV(Expr *V) { Data->getChildren()[DataPositionTy::POS_V] = V; } /// Set 'expr' part of the associated expression/statement. - void setExpr(Expr *E) { Data->getChildren()[3] = E; } + void setExpr(Expr *E) { Data->getChildren()[DataPositionTy::POS_E] = E; } public: /// Creates directive with a list of \a Clauses and 'x', 'v' and 'expr' @@ -2840,16 +2913,22 @@ public: unsigned NumClauses, EmptyShell); /// Get 'x' part of the associated expression/statement. - Expr *getX() { return cast_or_null(Data->getChildren()[0]); } + Expr *getX() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_X]); + } const Expr *getX() const { - return cast_or_null(Data->getChildren()[0]); + return cast_or_null(Data->getChildren()[DataPositionTy::POS_X]); } /// Get helper expression of the form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. - Expr *getUpdateExpr() { return cast_or_null(Data->getChildren()[1]); } + Expr *getUpdateExpr() { + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_UpdateExpr]); + } const Expr *getUpdateExpr() const { - return cast_or_null(Data->getChildren()[1]); + return cast_or_null( + Data->getChildren()[DataPositionTy::POS_UpdateExpr]); } /// Return true if helper update expression has form /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' and false if it has form @@ -2859,14 +2938,18 @@ public: /// 'x', false if 'v' must be updated to the new value of 'x'. bool isPostfixUpdate() const { return IsPostfixUpdate; } /// Get 'v' part of the associated expression/statement. - Expr *getV() { return cast_or_null(Data->getChildren()[2]); } + Expr *getV() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_V]); + } const Expr *getV() const { - return cast_or_null(Data->getChildren()[2]); + return cast_or_null(Data->getChildren()[DataPositionTy::POS_V]); } /// Get 'expr' part of the associated expression/statement. - Expr *getExpr() { return cast_or_null(Data->getChildren()[3]); } + Expr *getExpr() { + return cast_or_null(Data->getChildren()[DataPositionTy::POS_E]); + } const Expr *getExpr() const { - return cast_or_null(Data->getChildren()[3]); + return cast_or_null(Data->getChildren()[DataPositionTy::POS_E]); } static bool classof(const Stmt *T) { @@ -4992,7 +5075,7 @@ public: }; /// This represents the '#pragma omp tile' loop transformation directive. -class OMPTileDirective final : public OMPLoopBasedDirective { +class OMPTileDirective final : public OMPLoopTransformationDirective { friend class ASTStmtReader; friend class OMPExecutableDirective; @@ -5004,8 +5087,11 @@ class OMPTileDirective final : public OMPLoopBasedDirective { explicit OMPTileDirective(SourceLocation StartLoc, SourceLocation EndLoc, unsigned NumLoops) - : OMPLoopBasedDirective(OMPTileDirectiveClass, llvm::omp::OMPD_tile, - StartLoc, EndLoc, NumLoops) {} + : OMPLoopTransformationDirective(OMPTileDirectiveClass, + llvm::omp::OMPD_tile, StartLoc, EndLoc, + NumLoops) { + setNumGeneratedLoops(3 * NumLoops); + } void setPreInits(Stmt *PreInits) { Data->getChildren()[PreInitsOffset] = PreInits; @@ -5042,8 +5128,6 @@ public: static OMPTileDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned NumLoops); - unsigned getNumAssociatedLoops() const { return getLoopsNumber(); } - /// Gets/sets the associated loops after tiling. /// /// This is in de-sugared format stored as a CompoundStmt. @@ -5073,7 +5157,7 @@ public: /// #pragma omp unroll /// for (int i = 0; i < 64; ++i) /// \endcode -class OMPUnrollDirective final : public OMPLoopBasedDirective { +class OMPUnrollDirective final : public OMPLoopTransformationDirective { friend class ASTStmtReader; friend class OMPExecutableDirective; @@ -5084,8 +5168,9 @@ class OMPUnrollDirective final : public OMPLoopBasedDirective { }; explicit OMPUnrollDirective(SourceLocation StartLoc, SourceLocation EndLoc) - : OMPLoopBasedDirective(OMPUnrollDirectiveClass, llvm::omp::OMPD_unroll, - StartLoc, EndLoc, 1) {} + : OMPLoopTransformationDirective(OMPUnrollDirectiveClass, + llvm::omp::OMPD_unroll, StartLoc, EndLoc, + 1) {} /// Set the pre-init statements. void setPreInits(Stmt *PreInits) { @@ -5111,7 +5196,7 @@ public: static OMPUnrollDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *AssociatedStmt, - Stmt *TransformedStmt, Stmt *PreInits); + unsigned NumGeneratedLoops, Stmt *TransformedStmt, Stmt *PreInits); /// Build an empty '#pragma omp unroll' AST node for deserialization. /// @@ -5360,6 +5445,107 @@ public: } }; +/// This represents '#pragma omp metadirective' directive. +/// +/// \code +/// #pragma omp metadirective when(user={condition(N>10)}: parallel for) +/// \endcode +/// In this example directive '#pragma omp metadirective' has clauses 'when' +/// with a dynamic user condition to check if a variable 'N > 10' +/// +class OMPMetaDirective final : public OMPExecutableDirective { + friend class ASTStmtReader; + friend class OMPExecutableDirective; + Stmt *IfStmt; + + OMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc) + : OMPExecutableDirective(OMPMetaDirectiveClass, + llvm::omp::OMPD_metadirective, StartLoc, + EndLoc) {} + explicit OMPMetaDirective() + : OMPExecutableDirective(OMPMetaDirectiveClass, + llvm::omp::OMPD_metadirective, SourceLocation(), + SourceLocation()) {} + + void setIfStmt(Stmt *S) { IfStmt = S; } + +public: + static OMPMetaDirective *Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt, Stmt *IfStmt); + static OMPMetaDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses, + EmptyShell); + Stmt *getIfStmt() const { return IfStmt; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPMetaDirectiveClass; + } +}; + +/// This represents '#pragma omp loop' directive. +/// +/// \code +/// #pragma omp loop private(a,b) binding(parallel) order(concurrent) +/// \endcode +/// In this example directive '#pragma omp loop' has +/// clauses 'private' with the variables 'a' and 'b', 'binding' with +/// modifier 'parallel' and 'order(concurrent). +/// +class OMPGenericLoopDirective final : public OMPLoopDirective { + friend class ASTStmtReader; + friend class OMPExecutableDirective; + /// Build directive with the given start and end location. + /// + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending location of the directive. + /// \param CollapsedNum Number of collapsed nested loops. + /// + OMPGenericLoopDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum) + : OMPLoopDirective(OMPGenericLoopDirectiveClass, llvm::omp::OMPD_loop, + StartLoc, EndLoc, CollapsedNum) {} + + /// Build an empty directive. + /// + /// \param CollapsedNum Number of collapsed nested loops. + /// + explicit OMPGenericLoopDirective(unsigned CollapsedNum) + : OMPLoopDirective(OMPGenericLoopDirectiveClass, llvm::omp::OMPD_loop, + SourceLocation(), SourceLocation(), CollapsedNum) {} + +public: + /// Creates directive with a list of \p Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param CollapsedNum Number of collapsed loops. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement, associated with the directive. + /// \param Exprs Helper expressions for CodeGen. + /// + static OMPGenericLoopDirective * + Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef Clauses, + Stmt *AssociatedStmt, const HelperExprs &Exprs); + + /// Creates an empty directive with a place for \a NumClauses clauses. + /// + /// \param C AST context. + /// \param NumClauses Number of clauses. + /// \param CollapsedNum Number of collapsed nested loops. + /// + static OMPGenericLoopDirective *CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPGenericLoopDirectiveClass; + } +}; + } // end namespace clang #endif diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 010b813dc52..2befb5c1b45 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -309,16 +309,17 @@ public: /// unexpanded parameter pack (for C++0x variadic templates). bool containsUnexpandedParameterPack() const; + enum class Qualified { None, AsWritten, Fully }; /// Print the template name. /// /// \param OS the output stream to which the template name will be /// printed. /// - /// \param SuppressNNS if true, don't print the - /// nested-name-specifier that precedes the template name (if it has - /// one). + /// \param Qual print the (Qualified::None) simple name, + /// (Qualified::AsWritten) any written (possibly partial) qualifier, or + /// (Qualified::Fully) the fully qualified name. void print(raw_ostream &OS, const PrintingPolicy &Policy, - bool SuppressNNS = false) const; + Qualified Qual = Qualified::AsWritten) const; /// Debugging aid that dumps the template name. void dump(raw_ostream &OS) const; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 9f46d533789..fd25ec25d4f 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -495,7 +495,12 @@ public: (A == LangAS::Default && (B == LangAS::sycl_private || B == LangAS::sycl_local || B == LangAS::sycl_global || B == LangAS::sycl_global_device || - B == LangAS::sycl_global_host)); + B == LangAS::sycl_global_host)) || + // In HIP device compilation, any cuda address space is allowed + // to implicitly cast into the default address space. + (A == LangAS::Default && + (B == LangAS::cuda_constant || B == LangAS::cuda_device || + B == LangAS::cuda_shared)); } /// Returns true if the address space in these qualifiers is equal to or @@ -1998,6 +2003,7 @@ public: bool isFloat16Type() const; // C11 extension ISO/IEC TS 18661 bool isBFloat16Type() const; bool isFloat128Type() const; + bool isIbm128Type() const; bool isRealType() const; // C99 6.2.5p17 (real floating + integer) bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) bool isVoidType() const; // C99 6.2.5p19 @@ -2545,7 +2551,7 @@ public: } bool isFloatingPoint() const { - return getKind() >= Half && getKind() <= Float128; + return getKind() >= Half && getKind() <= Ibm128; } /// Determines whether the given kind corresponds to a placeholder type. @@ -3450,10 +3456,6 @@ class ConstantMatrixType final : public MatrixType { protected: friend class ASTContext; - /// The element type of the matrix. - // FIXME: Appears to be unused? There is also MatrixType::ElementType... - QualType ElementType; - /// Number of rows and columns. unsigned NumRows; unsigned NumColumns; @@ -3523,14 +3525,10 @@ class DependentSizedMatrixType final : public MatrixType { Expr *ColumnExpr, SourceLocation loc); public: - QualType getElementType() const { return ElementType; } Expr *getRowExpr() const { return RowExpr; } Expr *getColumnExpr() const { return ColumnExpr; } SourceLocation getAttributeLoc() const { return loc; } - bool isSugared() const { return false; } - QualType desugar() const { return QualType(this, 0); } - static bool classof(const Type *T) { return T->getTypeClass() == DependentSizedMatrix; } @@ -4946,29 +4944,29 @@ public: /// type-dependent, there is no deduced type and the type is canonical. In /// the latter case, it is also a dependent type. class DeducedType : public Type { + QualType DeducedAsType; + protected: DeducedType(TypeClass TC, QualType DeducedAsType, - TypeDependence ExtraDependence) - : Type(TC, - // FIXME: Retain the sugared deduced type? - DeducedAsType.isNull() ? QualType(this, 0) - : DeducedAsType.getCanonicalType(), + TypeDependence ExtraDependence, QualType Canon) + : Type(TC, Canon, ExtraDependence | (DeducedAsType.isNull() ? TypeDependence::None : DeducedAsType->getDependence() & - ~TypeDependence::VariablyModified)) {} + ~TypeDependence::VariablyModified)), + DeducedAsType(DeducedAsType) {} public: - bool isSugared() const { return !isCanonicalUnqualified(); } - QualType desugar() const { return getCanonicalTypeInternal(); } - - /// Get the type deduced for this placeholder type, or null if it's - /// either not been deduced or was deduced to a dependent type. - QualType getDeducedType() const { - return !isCanonicalUnqualified() ? getCanonicalTypeInternal() : QualType(); + bool isSugared() const { return !DeducedAsType.isNull(); } + QualType desugar() const { + return isSugared() ? DeducedAsType : QualType(this, 0); } + + /// Get the type deduced for this placeholder type, or null if it + /// has not been deduced. + QualType getDeducedType() const { return DeducedAsType; } bool isDeduced() const { - return !isCanonicalUnqualified() || isDependentType(); + return !DeducedAsType.isNull() || isDependentType(); } static bool classof(const Type *T) { @@ -4985,7 +4983,7 @@ class alignas(8) AutoType : public DeducedType, public llvm::FoldingSetNode { ConceptDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, ConceptDecl *CD, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD, ArrayRef TypeConstraintArgs); const TemplateArgument *getArgBuffer() const { @@ -5059,7 +5057,9 @@ class DeducedTemplateSpecializationType : public DeducedType, toTypeDependence(Template.getDependence()) | (IsDeducedAsDependent ? TypeDependence::DependentInstantiation - : TypeDependence::None)), + : TypeDependence::None), + DeducedAsType.isNull() ? QualType(this, 0) + : DeducedAsType.getCanonicalType()), Template(Template) {} public: @@ -6018,10 +6018,9 @@ inline ObjCProtocolDecl **ObjCTypeParamType::getProtocolStorageImpl() { class ObjCInterfaceType : public ObjCObjectType { friend class ASTContext; // ASTContext creates these. friend class ASTReader; - friend class ObjCInterfaceDecl; template friend class serialization::AbstractTypeReader; - mutable ObjCInterfaceDecl *Decl; + ObjCInterfaceDecl *Decl; ObjCInterfaceType(const ObjCInterfaceDecl *D) : ObjCObjectType(Nonce_ObjCInterface), @@ -6029,7 +6028,7 @@ class ObjCInterfaceType : public ObjCObjectType { public: /// Get the declaration of this interface. - ObjCInterfaceDecl *getDecl() const { return Decl; } + ObjCInterfaceDecl *getDecl() const; bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -6976,6 +6975,10 @@ inline bool Type::isFloat128Type() const { return isSpecificBuiltinType(BuiltinType::Float128); } +inline bool Type::isIbm128Type() const { + return isSpecificBuiltinType(BuiltinType::Ibm128); +} + inline bool Type::isNullPtrType() const { return isSpecificBuiltinType(BuiltinType::NullPtr); } @@ -7144,7 +7147,7 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, /// into a diagnostic with <<. inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &PD, QualType T) { - PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), + PD.AddTaggedVal(reinterpret_cast(T.getAsOpaquePtr()), DiagnosticsEngine::ak_qualtype); return PD; } diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 65e95d52c30..bb668c1980f 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -581,10 +581,9 @@ public: bool needsExtraLocalData() const { BuiltinType::Kind bk = getTypePtr()->getKind(); - return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) - || (bk >= BuiltinType::Short && bk <= BuiltinType::Float128) - || bk == BuiltinType::UChar - || bk == BuiltinType::SChar; + return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) || + (bk >= BuiltinType::Short && bk <= BuiltinType::Ibm128) || + bk == BuiltinType::UChar || bk == BuiltinType::SChar; } unsigned getExtraLocalDataSize() const { diff --git a/clang/include/clang/AST/TypeOrdering.h b/clang/include/clang/AST/TypeOrdering.h index 6630105136f..8037f98cc96 100644 --- a/clang/include/clang/AST/TypeOrdering.h +++ b/clang/include/clang/AST/TypeOrdering.h @@ -34,7 +34,6 @@ struct QualTypeOrdering { } namespace llvm { - template struct DenseMapInfo; template<> struct DenseMapInfo { static inline clang::QualType getEmptyKey() { return clang::QualType(); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h index 91024f9425e..dafafa151a6 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h @@ -167,6 +167,7 @@ public: MatchCallback *Action); void addMatcher(const TemplateArgumentLocMatcher &NodeMatch, MatchCallback *Action); + void addMatcher(const AttrMatcher &NodeMatch, MatchCallback *Action); /// @} /// Adds a matcher to execute when running over the AST. @@ -219,6 +220,7 @@ public: std::vector> CtorInit; std::vector> TemplateArgumentLoc; + std::vector> Attr; /// All the callbacks in one container to simplify iteration. llvm::SmallPtrSet AllCallbacks; }; diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 8e3ee6cb9e7..d6e5b215462 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -148,6 +148,8 @@ using CXXBaseSpecifierMatcher = internal::Matcher; using CXXCtorInitializerMatcher = internal::Matcher; using TemplateArgumentMatcher = internal::Matcher; using TemplateArgumentLocMatcher = internal::Matcher; +using LambdaCaptureMatcher = internal::Matcher; +using AttrMatcher = internal::Matcher; /// @} /// Matches any node. @@ -307,7 +309,7 @@ AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, /// Matches statements that are (transitively) expanded from the named macro. /// Does not match if only part of the statement is expanded from that macro or -/// if different parts of the the statement are expanded from different +/// if different parts of the statement are expanded from different /// appearances of the macro. AST_POLYMORPHIC_MATCHER_P(isExpandedFromMacro, AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc), @@ -752,9 +754,11 @@ AST_MATCHER_P(ClassTemplateSpecializationDecl, hasSpecializedTemplate, InnerMatcher.matches(*Decl, Finder, Builder)); } -/// Matches a declaration that has been implicitly added -/// by the compiler (eg. implicit default/copy constructors). -AST_MATCHER(Decl, isImplicit) { +/// Matches an entity that has been implicitly added by the compiler (e.g. +/// implicit default/copy constructors). +AST_POLYMORPHIC_MATCHER(isImplicit, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr, + LambdaCapture)) { return Node.isImplicit(); } @@ -3489,8 +3493,8 @@ internal::Matcher findAll(const internal::Matcher &Matcher) { /// Usable as: Any Matcher extern const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, - internal::TypeList, - internal::TypeList> + internal::TypeList, + internal::TypeList> hasParent; /// Matches AST nodes that have an ancestor that matches the provided @@ -3506,8 +3510,8 @@ extern const internal::ArgumentAdaptingMatcherFunc< /// Usable as: Any Matcher extern const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, - internal::TypeList, - internal::TypeList> + internal::TypeList, + internal::TypeList> hasAncestor; /// Matches if the provided matcher does not match. @@ -4201,6 +4205,45 @@ AST_MATCHER_P( InnerMatcher.matches(*Initializer, Finder, Builder)); } +/// Matches a variable serving as the implicit variable for a lambda init- +/// capture. +/// +/// Example matches x (matcher = varDecl(isInitCapture())) +/// \code +/// auto f = [x=3]() { return x; }; +/// \endcode +AST_MATCHER(VarDecl, isInitCapture) { return Node.isInitCapture(); } + +/// Matches each lambda capture in a lambda expression. +/// +/// Given +/// \code +/// int main() { +/// int x, y; +/// float z; +/// auto f = [=]() { return x + y + z; }; +/// } +/// \endcode +/// lambdaExpr(forEachLambdaCapture( +/// lambdaCapture(capturesVar(varDecl(hasType(isInteger())))))) +/// will trigger two matches, binding for 'x' and 'y' respectively. +AST_MATCHER_P(LambdaExpr, forEachLambdaCapture, LambdaCaptureMatcher, + InnerMatcher) { + BoundNodesTreeBuilder Result; + bool Matched = false; + for (const auto &Capture : Node.captures()) { + if (Finder->isTraversalIgnoringImplicitNodes() && Capture.isImplicit()) + continue; + BoundNodesTreeBuilder CaptureBuilder(*Builder); + if (InnerMatcher.matches(Capture, Finder, &CaptureBuilder)) { + Matched = true; + Result.addMatch(CaptureBuilder); + } + } + *Builder = std::move(Result); + return Matched; +} + /// \brief Matches a static variable with local scope. /// /// Example matches y (matcher = varDecl(isStaticLocal())) @@ -4586,49 +4629,79 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, return false; } -/// Matches any capture of a lambda expression. +/// Matches lambda captures. +/// +/// Given +/// \code +/// int main() { +/// int x; +/// auto f = [x](){}; +/// auto g = [x = 1](){}; +/// } +/// \endcode +/// In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`, +/// `lambdaCapture()` matches `x` and `x=1`. +extern const internal::VariadicAllOfMatcher lambdaCapture; + +/// Matches any capture in a lambda expression. +/// +/// Given +/// \code +/// void foo() { +/// int t = 5; +/// auto f = [=](){ return t; }; +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(lambdaCapture())) and +/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) +/// both match `[=](){ return t; }`. +AST_MATCHER_P(LambdaExpr, hasAnyCapture, LambdaCaptureMatcher, InnerMatcher) { + for (const LambdaCapture &Capture : Node.captures()) { + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Capture, Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// Matches a `LambdaCapture` that refers to the specified `VarDecl`. The +/// `VarDecl` can be a separate variable that is captured by value or +/// reference, or a synthesized variable if the capture has an initializer. /// /// Given /// \code /// void foo() { /// int x; /// auto f = [x](){}; +/// auto g = [x = 1](){}; /// } /// \endcode -/// lambdaExpr(hasAnyCapture(anything())) -/// matches [x](){}; -AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, internal::Matcher, - InnerMatcher, 0) { - for (const LambdaCapture &Capture : Node.captures()) { - if (Capture.capturesVariable()) { - BoundNodesTreeBuilder Result(*Builder); - if (InnerMatcher.matches(*Capture.getCapturedVar(), Finder, &Result)) { - *Builder = std::move(Result); - return true; - } - } - } - return false; +/// In the matcher +/// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), +/// capturesVar(hasName("x")) matches `x` and `x = 1`. +AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher, + InnerMatcher) { + auto *capturedVar = Node.getCapturedVar(); + return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder); } -/// Matches any capture of 'this' in a lambda expression. +/// Matches a `LambdaCapture` that refers to 'this'. /// /// Given /// \code -/// struct foo { -/// void bar() { -/// auto f = [this](){}; -/// } +/// class C { +/// int cc; +/// int f() { +/// auto l = [this]() { return cc; }; +/// return l(); /// } +/// }; /// \endcode -/// lambdaExpr(hasAnyCapture(cxxThisExpr())) -/// matches [this](){}; -AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, - internal::Matcher, InnerMatcher, 1) { - return llvm::any_of(Node.captures(), [](const LambdaCapture &LC) { - return LC.capturesThis(); - }); -} +/// lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis()))) +/// matches `[this]() { return cc; }`. +AST_MATCHER(LambdaCapture, capturesThis) { return Node.capturesThis(); } /// Matches a constructor call expression which uses list initialization. AST_MATCHER(CXXConstructExpr, isListInitialization) { @@ -5875,6 +5948,10 @@ AST_MATCHER(CXXMethodDecl, isVirtualAsWritten) { return Node.isVirtualAsWritten(); } +AST_MATCHER(CXXConstructorDecl, isInheritingConstructor) { + return Node.isInheritingConstructor(); +} + /// Matches if the given method or class declaration is final. /// /// Given: @@ -6333,6 +6410,187 @@ AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher, loc, new internal::TypeLocTypeMatcher(InnerMatcher)); } +/// Matches `QualifiedTypeLoc`s in the clang AST. +/// +/// Given +/// \code +/// const int x = 0; +/// \endcode +/// qualifiedTypeLoc() +/// matches `const int`. +extern const internal::VariadicDynCastAllOfMatcher + qualifiedTypeLoc; + +/// Matches `QualifiedTypeLoc`s that have an unqualified `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// int* const x; +/// const int y; +/// \endcode +/// qualifiedTypeLoc(hasUnqualifiedLoc(pointerTypeLoc())) +/// matches the `TypeLoc` of the variable declaration of `x`, but not `y`. +AST_MATCHER_P(QualifiedTypeLoc, hasUnqualifiedLoc, internal::Matcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getUnqualifiedLoc(), Finder, Builder); +} + +/// Matches a function declared with the specified return `TypeLoc`. +/// +/// Given +/// \code +/// int f() { return 5; } +/// void g() {} +/// \endcode +/// functionDecl(hasReturnTypeLoc(loc(asString("int")))) +/// matches the declaration of `f`, but not `g`. +AST_MATCHER_P(FunctionDecl, hasReturnTypeLoc, internal::Matcher, + ReturnMatcher) { + auto Loc = Node.getFunctionTypeLoc(); + return Loc && ReturnMatcher.matches(Loc.getReturnLoc(), Finder, Builder); +} + +/// Matches pointer `TypeLoc`s. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc() +/// matches `int*`. +extern const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; + +/// Matches pointer `TypeLoc`s that have a pointee `TypeLoc` matching +/// `PointeeMatcher`. +/// +/// Given +/// \code +/// int* x; +/// \endcode +/// pointerTypeLoc(hasPointeeLoc(loc(asString("int")))) +/// matches `int*`. +AST_MATCHER_P(PointerTypeLoc, hasPointeeLoc, internal::Matcher, + PointeeMatcher) { + return PointeeMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches reference `TypeLoc`s. +/// +/// Given +/// \code +/// int x = 3; +/// int& l = x; +/// int&& r = 3; +/// \endcode +/// referenceTypeLoc() +/// matches `int&` and `int&&`. +extern const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; + +/// Matches reference `TypeLoc`s that have a referent `TypeLoc` matching +/// `ReferentMatcher`. +/// +/// Given +/// \code +/// int x = 3; +/// int& xx = x; +/// \endcode +/// referenceTypeLoc(hasReferentLoc(loc(asString("int")))) +/// matches `int&`. +AST_MATCHER_P(ReferenceTypeLoc, hasReferentLoc, internal::Matcher, + ReferentMatcher) { + return ReferentMatcher.matches(Node.getPointeeLoc(), Finder, Builder); +} + +/// Matches template specialization `TypeLoc`s. +/// +/// Given +/// \code +/// template class C {}; +/// C var; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc()))) +/// matches `C var`. +extern const internal::VariadicDynCastAllOfMatcher< + TypeLoc, TemplateSpecializationTypeLoc> + templateSpecializationTypeLoc; + +/// Matches template specialization `TypeLoc`s that have at least one +/// `TemplateArgumentLoc` matching the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A a; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc( +/// hasTypeLoc(loc(asString("int"))))))) +/// matches `A a`. +AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc, + internal::Matcher, InnerMatcher) { + for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) { + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// Matches template specialization `TypeLoc`s where the n'th +/// `TemplateArgumentLoc` matches the given `InnerMatcher`. +/// +/// Given +/// \code +/// template class A {}; +/// A b; +/// A c; +/// \endcode +/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0, +/// hasTypeLoc(loc(asString("double"))))))) +/// matches `A b`, but not `A c`. +AST_POLYMORPHIC_MATCHER_P2( + hasTemplateArgumentLoc, + AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc), + unsigned, Index, internal::Matcher, InnerMatcher) { + return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder, + Builder); +} + +/// Matches C or C++ elaborated `TypeLoc`s. +/// +/// Given +/// \code +/// struct s {}; +/// struct s ss; +/// \endcode +/// elaboratedTypeLoc() +/// matches the `TypeLoc` of the variable declaration of `ss`. +extern const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + +/// Matches elaborated `TypeLoc`s that have a named `TypeLoc` matching +/// `InnerMatcher`. +/// +/// Given +/// \code +/// template +/// class C {}; +/// class C c; +/// +/// class D {}; +/// class D d; +/// \endcode +/// elaboratedTypeLoc(hasNamedTypeLoc(templateSpecializationTypeLoc())); +/// matches the `TypeLoc` of the variable declaration of `c`, but not `d`. +AST_MATCHER_P(ElaboratedTypeLoc, hasNamedTypeLoc, internal::Matcher, + InnerMatcher) { + return InnerMatcher.matches(Node.getNamedTypeLoc(), Finder, Builder); +} + /// Matches type \c bool. /// /// Given @@ -7133,6 +7391,24 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace, return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder); } +/// Matches attributes. +/// Attributes may be attached with a variety of different syntaxes (including +/// keywords, C++11 attributes, GNU ``__attribute``` and MSVC `__declspec``, +/// and ``#pragma``s). They may also be implicit. +/// +/// Given +/// \code +/// struct [[nodiscard]] Foo{}; +/// void bar(int * __attribute__((nonnull)) ); +/// __declspec(noinline) void baz(); +/// +/// #pragma omp declare simd +/// int min(); +/// \endcode +/// attr() +/// matches "nodiscard", "nonnull", "noinline", and the whole "#pragma" line. +extern const internal::VariadicAllOfMatcher attr; + /// Overloads for the \c equalsNode matcher. /// FIXME: Implement for other node types. /// @{ diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 71f4f2d17ae..a77611001fb 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -312,8 +312,7 @@ public: template bool removeBindings(const ExcludePredicate &Predicate) { - Bindings.erase(std::remove_if(Bindings.begin(), Bindings.end(), Predicate), - Bindings.end()); + llvm::erase_if(Bindings, Predicate); return !Bindings.empty(); } @@ -757,7 +756,8 @@ public: std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || - std::is_base_of::value, + std::is_base_of::value || + std::is_base_of::value, "unsupported type for recursive matching"); return matchesChildOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, Bind); @@ -771,7 +771,8 @@ public: std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || - std::is_base_of::value, + std::is_base_of::value || + std::is_base_of::value, "unsupported type for recursive matching"); return matchesDescendantOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, Bind); @@ -785,7 +786,8 @@ public: static_assert(std::is_base_of::value || std::is_base_of::value || std::is_base_of::value || - std::is_base_of::value, + std::is_base_of::value || + std::is_base_of::value, "type not allowed for recursive matching"); return matchesAncestorOf(DynTypedNode::create(Node), getASTContext(), Matcher, Builder, MatchMode); @@ -954,7 +956,7 @@ class HasNameMatcher : public SingleNodeMatcherInterface { bool matchesNode(const NamedDecl &Node) const override; - private: +private: /// Unqualified match routine. /// /// It is much faster than the full match, but it only works for unqualified @@ -1025,31 +1027,29 @@ private: BoundNodesTreeBuilder *Builder) const { // DeducedType does not have declarations of its own, so // match the deduced type instead. - const Type *EffectiveType = &Node; if (const auto *S = dyn_cast(&Node)) { - EffectiveType = S->getDeducedType().getTypePtrOrNull(); - if (!EffectiveType) - return false; + QualType DT = S->getDeducedType(); + return !DT.isNull() ? matchesSpecialized(*DT, Finder, Builder) : false; } // First, for any types that have a declaration, extract the declaration and // match on it. - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getDecl(), Finder, Builder); } - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesDecl(S->getInterface(), Finder, Builder); } @@ -1061,14 +1061,14 @@ private: // template struct X { T t; } class A {}; X a; // The following matcher will match, which otherwise would not: // fieldDecl(hasType(pointerType())). - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->getReplacementType(), Finder, Builder); } // For template specialization types, we want to match the template // declaration, as long as the type is still dependent, and otherwise the // declaration of the instantiated tag type. - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { if (!S->isTypeAlias() && S->isSugared()) { // If the template is non-dependent, we want to match the instantiated // tag type. @@ -1087,7 +1087,7 @@ private: // FIXME: We desugar elaborated types. This makes the assumption that users // do never want to match on whether a type is elaborated - there are // arguments for both sides; for now, continue desugaring. - if (const auto *S = dyn_cast(EffectiveType)) { + if (const auto *S = dyn_cast(&Node)) { return matchesSpecialized(S->desugar(), Finder, Builder); } return false; @@ -1175,7 +1175,8 @@ struct IsBaseType { std::is_same::value || std::is_same::value || std::is_same::value || - std::is_same::value; + std::is_same::value || + std::is_same::value; }; template const bool IsBaseType::value; @@ -1185,7 +1186,7 @@ const bool IsBaseType::value; /// Useful for matchers like \c anything and \c unless. using AllNodeBaseTypes = TypeList; + Type, TypeLoc, CXXCtorInitializer, Attr>; /// Helper meta-function to extract the argument out of a function of /// type void(Arg). @@ -1212,7 +1213,7 @@ template constexpr T *new_from_tuple(Tuple &&t) { using AdaptativeDefaultFromTypes = AllNodeBaseTypes; using AdaptativeDefaultToTypes = TypeList; + QualType, Attr>; /// All types that are supported by HasDeclarationMatcher above. using HasDeclarationSupportedTypes = @@ -2245,11 +2246,7 @@ public: bool matchesNode(const T &Node) const override { Optional OptOpName = getOpName(Node); - if (!OptOpName) - return false; - return llvm::any_of(Names, [OpName = *OptOpName](const std::string &Name) { - return Name == OpName; - }); + return OptOpName && llvm::is_contained(Names, *OptOpName); } private: @@ -2304,6 +2301,26 @@ std::shared_ptr createAndVerifyRegex(StringRef Regex, llvm::Regex::RegexFlags Flags, StringRef MatcherID); +inline bool +MatchTemplateArgLocAt(const DeclRefExpr &Node, unsigned int Index, + internal::Matcher InnerMatcher, + internal::ASTMatchFinder *Finder, + internal::BoundNodesTreeBuilder *Builder) { + llvm::ArrayRef ArgLocs = Node.template_arguments(); + return Index < ArgLocs.size() && + InnerMatcher.matches(ArgLocs[Index], Finder, Builder); +} + +inline bool +MatchTemplateArgLocAt(const TemplateSpecializationTypeLoc &Node, + unsigned int Index, + internal::Matcher InnerMatcher, + internal::ASTMatchFinder *Finder, + internal::BoundNodesTreeBuilder *Builder) { + return !Node.isNull() && Index < Node.getNumArgs() && + InnerMatcher.matches(Node.getArgLoc(Index), Finder, Builder); +} + } // namespace internal } // namespace ast_matchers diff --git a/clang/include/clang/Analysis/Analyses/Dominators.h b/clang/include/clang/Analysis/Analyses/Dominators.h index 25a5ba9d83f..f588a5c7d1d 100644 --- a/clang/include/clang/Analysis/Analyses/Dominators.h +++ b/clang/include/clang/Analysis/Analyses/Dominators.h @@ -202,7 +202,7 @@ struct ChildrenGetterTy { auto Children = children(N); ChildrenTy Ret{Children.begin(), Children.end()}; - Ret.erase(std::remove(Ret.begin(), Ret.end(), nullptr), Ret.end()); + llvm::erase_value(Ret, nullptr); return Ret; } }; diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index 9e32eb8e066..f9223fe58a2 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -1337,6 +1337,7 @@ public: const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; } using try_block_iterator = std::vector::const_iterator; + using try_block_range = llvm::iterator_range; try_block_iterator try_blocks_begin() const { return TryDispatchBlocks.begin(); @@ -1346,6 +1347,10 @@ public: return TryDispatchBlocks.end(); } + try_block_range try_blocks() const { + return try_block_range(try_blocks_begin(), try_blocks_end()); + } + void addTryDispatchBlock(const CFGBlock *block) { TryDispatchBlocks.push_back(block); } diff --git a/clang/include/clang/Analysis/CloneDetection.h b/clang/include/clang/Analysis/CloneDetection.h index db827c3a6d6..0b86c7fd86d 100644 --- a/clang/include/clang/Analysis/CloneDetection.h +++ b/clang/include/clang/Analysis/CloneDetection.h @@ -235,9 +235,7 @@ public: static void filterGroups( std::vector &CloneGroups, llvm::function_ref Filter) { - CloneGroups.erase( - std::remove_if(CloneGroups.begin(), CloneGroups.end(), Filter), - CloneGroups.end()); + llvm::erase_if(CloneGroups, Filter); } /// Splits the given CloneGroups until the given Compare function returns true diff --git a/clang/include/clang/Analysis/PathDiagnostic.h b/clang/include/clang/Analysis/PathDiagnostic.h index 539aa20b816..235d2608319 100644 --- a/clang/include/clang/Analysis/PathDiagnostic.h +++ b/clang/include/clang/Analysis/PathDiagnostic.h @@ -75,14 +75,8 @@ struct PathDiagnosticConsumerOptions { bool ShouldSerializeStats = false; /// If the consumer intends to produce multiple output files, should it - /// use randomly generated file names for these files (with the tiny risk of - /// having random collisions) or deterministic human-readable file names - /// (with a larger risk of deterministic collisions or invalid characters - /// in the file name). We should not really give this choice to the users - /// because deterministic mode is always superior when done right, but - /// for some consumers this mode is experimental and needs to be - /// off by default. - bool ShouldWriteStableReportFilename = false; + /// use a pseudo-random file name name or a human-readable file name. + bool ShouldWriteVerboseReportFilename = false; /// Whether the consumer should treat consumed diagnostics as hard errors. /// Useful for breaking your build when issues are found. @@ -151,11 +145,14 @@ public: /// Only runs visitors, no output generated. None, - /// Used for HTML, SARIF, and text output. + /// Used for SARIF and text output. Minimal, /// Used for plist output, used for "arrows" generation. Extensive, + + /// Used for HTML, shows both "arrows" and control notes. + Everything }; virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } @@ -164,7 +161,11 @@ public: return getGenerationScheme() != None; } - bool shouldAddPathEdges() const { return getGenerationScheme() == Extensive; } + bool shouldAddPathEdges() const { return getGenerationScheme() >= Extensive; } + bool shouldAddControlNotes() const { + return getGenerationScheme() == Minimal || + getGenerationScheme() == Everything; + } virtual bool supportsLogicalOpControlFlow() const { return false; } @@ -552,7 +553,7 @@ public: /// Return true if the diagnostic piece is prunable. bool isPrunable() const { - return IsPrunable.hasValue() ? IsPrunable.getValue() : false; + return IsPrunable.getValueOr(false); } void dump() const override; diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 12d09181a2e..d8f0fcd5655 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -848,6 +848,7 @@ def Availability : InheritableAttr { [{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { return llvm::StringSwitch(Platform) .Case("android", "Android") + .Case("fuchsia", "Fuchsia") .Case("ios", "iOS") .Case("macos", "macOS") .Case("tvos", "tvOS") @@ -1835,6 +1836,22 @@ def BPFPreserveAccessIndex : InheritableAttr, let LangOpts = [COnly]; } +def BTFDeclTag : InheritableAttr { + let Spellings = [Clang<"btf_decl_tag">]; + let Args = [StringArgument<"BTFDeclTag">]; + let Subjects = SubjectList<[Var, Function, Record, Field, TypedefName], + ErrorDiag>; + let Documentation = [BTFDeclTagDocs]; + let LangOpts = [COnly]; +} + +def BTFTypeTag : TypeAttr { + let Spellings = [Clang<"btf_type_tag">]; + let Args = [StringArgument<"BTFTypeTag">]; + let Documentation = [BTFTypeTagDocs]; + let LangOpts = [COnly]; +} + def WebAssemblyExportName : InheritableAttr, TargetSpecificAttr { let Spellings = [Clang<"export_name">]; @@ -1971,7 +1988,7 @@ def NoReturn : InheritableAttr { def NoInstrumentFunction : InheritableAttr { let Spellings = [GCC<"no_instrument_function">]; - let Subjects = SubjectList<[Function]>; + let Subjects = SubjectList<[Function, ObjCMethod]>; let Documentation = [Undocumented]; let SimpleHandler = 1; } @@ -2940,6 +2957,13 @@ def NoSanitizeSpecific : InheritableAttr { let ASTNode = 0; } +def DisableSanitizerInstrumentation : InheritableAttr { + let Spellings = [Clang<"disable_sanitizer_instrumentation">]; + let Subjects = SubjectList<[Function, ObjCMethod, GlobalVar]>; + let Documentation = [DisableSanitizerInstrumentationDocs]; + let SimpleHandler = 1; +} + def CFICanonicalJumpTable : InheritableAttr { let Spellings = [Clang<"cfi_canonical_jump_table">]; let Subjects = SubjectList<[Function], ErrorDiag>; @@ -3659,7 +3683,8 @@ def OMPAllocateDecl : InheritableAttr { "OMPCGroupMemAlloc", "OMPPTeamMemAlloc", "OMPThreadMemAlloc", "OMPUserDefinedMemAlloc" ]>, - ExprArgument<"Allocator"> + ExprArgument<"Allocator">, + ExprArgument<"Alignment"> ]; let Documentation = [Undocumented]; } @@ -3674,6 +3699,11 @@ def OMPDeclareVariant : InheritableAttr { let Args = [ ExprArgument<"VariantFuncRef">, OMPTraitInfoArgument<"TraitInfos">, + VariadicExprArgument<"AdjustArgsNothing">, + VariadicExprArgument<"AdjustArgsNeedDevicePtr">, + VariadicEnumArgument<"AppendArgs", "InteropType", + ["target", "targetsync", "target,targetsync"], + ["Target", "TargetSync", "Target_TargetSync"]> ]; let AdditionalMembers = [{ OMPTraitInfo &getTraitInfo() { return *traitInfos; } @@ -3823,3 +3853,12 @@ def EnforceTCBLeaf : InheritableAttr { let Documentation = [EnforceTCBLeafDocs]; bit InheritEvenIfAlreadyPresent = 1; } + +def Error : InheritableAttr { + let Spellings = [GCC<"error">, GCC<"warning">]; + let Accessors = [Accessor<"isError", [GCC<"error">]>, + Accessor<"isWarning", [GCC<"warning">]>]; + let Args = [StringArgument<"UserDiagnostic">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [ErrorAttrDocs]; +} diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index c265a877e3b..e7afb3699eb 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -22,7 +22,7 @@ // Windows (from within the clang\docs directory): // make.bat html // Non-Windows (from within the clang\docs directory): -// make -f Makefile.sphinx html +// sphinx-build -b html _build/html def GlobalDocumentation { code Intro =[{.. @@ -2011,6 +2011,34 @@ preserving struct or union member access debuginfo indices of this struct or union, similar to clang ``__builtin_preserve_access_index()``. }]; } +def BTFDeclTagDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the ``__attribute__((btf_decl_tag("ARGUMENT")))`` attribute for +all targets. This attribute may be attached to a struct/union, struct/union +field, function, function parameter, variable or typedef declaration. If -g is +specified, the ``ARGUMENT`` info will be preserved in IR and be emitted to +dwarf. For BPF targets, the ``ARGUMENT`` info will be emitted to .BTF ELF +section too. + }]; +} + +def BTFTypeTagDocs : Documentation { + let Category = DocCatType; + let Content = [{ +Clang supports the ``__attribute__((btf_type_tag("ARGUMENT")))`` attribute for +all targets. It only has effect when ``-g`` is specified on the command line and +is currently silently ignored when not applied to a pointer type (note: this +scenario may be diagnosed in the future). + +The ``ARGUMENT`` string will be preserved in IR and emitted to DWARF for the +types used in variable declarations, function declarations, or typedef +declarations. + +For BPF targets, the ``ARGUMENT`` string will also be emitted to .BTF ELF +section. + }]; +} def MipsInterruptDocs : Documentation { let Category = DocCatFunction; @@ -2592,6 +2620,18 @@ full list of supported sanitizer flags. }]; } +def DisableSanitizerInstrumentationDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Use the ``disable_sanitizer_instrumentation`` attribute on a function, +Objective-C method, or global variable, to specify that no sanitizer +instrumentation should be applied. + +This is not the same as ``__attribute__((no_sanitize(...)))``, which depending +on the tool may still insert instrumentation to prevent false positive reports. + }]; +} + def NoSanitizeAddressDocs : Documentation { let Category = DocCatFunction; // This function has multiple distinct spellings, and so it requires a custom @@ -5859,19 +5899,21 @@ def AcquireHandleDocs : Documentation { If this annotation is on a function or a function type it is assumed to return a new handle. In case this annotation is on an output parameter, the function is assumed to fill the corresponding argument with a new -handle. +handle. The attribute requires a string literal argument which used to +identify the handle with later uses of ``use_handle`` or +``release_handle``. .. code-block:: c++ // Output arguments from Zircon. zx_status_t zx_socket_create(uint32_t options, - zx_handle_t __attribute__((acquire_handle)) * out0, - zx_handle_t* out1 [[clang::acquire_handle]]); + zx_handle_t __attribute__((acquire_handle("zircon"))) * out0, + zx_handle_t* out1 [[clang::acquire_handle("zircon")]]); // Returned handle. - [[clang::acquire_handle]] int open(const char *path, int oflag, ... ); - int open(const char *path, int oflag, ... ) __attribute__((acquire_handle)); + [[clang::acquire_handle("tag")]] int open(const char *path, int oflag, ... ); + int open(const char *path, int oflag, ... ) __attribute__((acquire_handle("tag"))); }]; } @@ -5879,12 +5921,13 @@ def UseHandleDocs : Documentation { let Category = HandleDocs; let Content = [{ A function taking a handle by value might close the handle. If a function -parameter is annotated with ``use_handle`` it is assumed to not to change +parameter is annotated with ``use_handle(tag)`` it is assumed to not to change the state of the handle. It is also assumed to require an open handle to work with. +The attribute requires a string literal argument to identify the handle being used. .. code-block:: c++ - zx_status_t zx_port_wait(zx_handle_t handle [[clang::use_handle]], + zx_status_t zx_port_wait(zx_handle_t handle [[clang::use_handle("zircon")]], zx_time_t deadline, zx_port_packet_t* packet); }]; @@ -5893,12 +5936,13 @@ the state of the handle. It is also assumed to require an open handle to work wi def ReleaseHandleDocs : Documentation { let Category = HandleDocs; let Content = [{ -If a function parameter is annotated with ``release_handle`` it is assumed to -close the handle. It is also assumed to require an open handle to work with. +If a function parameter is annotated with ``release_handle(tag)`` it is assumed to +close the handle. It is also assumed to require an open handle to work with. The +attribute requires a string literal argument to identify the handle being released. .. code-block:: c++ - zx_status_t zx_handle_close(zx_handle_t handle [[clang::release_handle]]); + zx_status_t zx_handle_close(zx_handle_t handle [[clang::release_handle("tag")]]); }]; } @@ -6045,3 +6089,29 @@ def EnforceTCBLeafDocs : Documentation { - ``enforce_tcb_leaf(Name)`` indicates that this function is a part of the TCB named ``Name`` }]; } + +def ErrorAttrDocs : Documentation { + let Category = DocCatFunction; + let Heading = "error, warning"; + let Content = [{ +The ``error`` and ``warning`` function attributes can be used to specify a +custom diagnostic to be emitted when a call to such a function is not +eliminated via optimizations. This can be used to create compile time +assertions that depend on optimizations, while providing diagnostics +pointing to precise locations of the call site in the source. + +.. code-block:: c++ + + __attribute__((warning("oh no"))) void dontcall(); + void foo() { + if (someCompileTimeAssertionThatsTrue) + dontcall(); // Warning + + dontcall(); // Warning + + if (someCompileTimeAssertionThatsFalse) + dontcall(); // No Warning + sizeof(dontcall()); // No Warning + } + }]; +} diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 0e3898537bc..b05777889e7 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -80,9 +80,7 @@ // builtin even if type doesn't match signature, and don't warn if we // can't be sure the type is right // F -> this is a libc/libm function with a '__builtin_' prefix added. -// f -> this is a libc/libm function without the '__builtin_' prefix. It can -// be followed by ':headername:' to state which header this function -// comes from. +// f -> this is a libc/libm function without the '__builtin_' prefix. // h -> this function requires a specific header or an explicit declaration. // i -> this is a runtime library implemented function without the // '__builtin_' prefix. It will be implemented in compiler-rt or libgcc. @@ -645,6 +643,12 @@ BUILTIN(__builtin_alloca, "v*z" , "Fn") BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn") BUILTIN(__builtin_call_with_static_chain, "v.", "nt") +BUILTIN(__builtin_elementwise_abs, "v.", "nct") +BUILTIN(__builtin_elementwise_max, "v.", "nct") +BUILTIN(__builtin_elementwise_min, "v.", "nct") +BUILTIN(__builtin_reduce_max, "v.", "nct") +BUILTIN(__builtin_reduce_min, "v.", "nct") + BUILTIN(__builtin_matrix_transpose, "v.", "nFt") BUILTIN(__builtin_matrix_column_major_load, "v.", "nFt") BUILTIN(__builtin_matrix_column_major_store, "v.", "nFt") @@ -794,6 +798,7 @@ ATOMIC_BUILTIN(__c11_atomic_fetch_sub, "v.", "t") ATOMIC_BUILTIN(__c11_atomic_fetch_and, "v.", "t") ATOMIC_BUILTIN(__c11_atomic_fetch_or, "v.", "t") ATOMIC_BUILTIN(__c11_atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_nand, "v.", "t") ATOMIC_BUILTIN(__c11_atomic_fetch_max, "v.", "t") ATOMIC_BUILTIN(__c11_atomic_fetch_min, "v.", "t") BUILTIN(__c11_atomic_thread_fence, "vi", "n") diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index 1dac5d2371d..634bcaed20a 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -243,6 +243,9 @@ TARGET_HEADER_BUILTIN(_ReadStatusReg, "LLii", "nh", "intrin.h", ALL_MS_LANGUAG TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__mulh, "SLLiSLLiSLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "") + #undef BUILTIN #undef LANGBUILTIN #undef TARGET_HEADER_BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 3570431d952..2e1d3c7ccbf 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -196,6 +196,19 @@ TARGET_BUILTIN(__builtin_amdgcn_perm, "UiUiUiUi", "nc", "gfx8-insts") TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_f64, "dd*1d", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_f32, "ff*1f", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2f16, "V2hV2h*1V2h", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fmin_f64, "dd*1d", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fmax_f64, "dd*1d", "t", "gfx90a-insts") + +TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_f64, "dd*0d", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fmin_f64, "dd*0d", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fmax_f64, "dd*0d", "t", "gfx90a-insts") + +TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_f64, "dd*3d", "t", "gfx90a-insts") +TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_f32, "ff*3f", "t", "gfx8-insts") + //===----------------------------------------------------------------------===// // Deep learning builtins. //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def index 3c96900136a..025fef05c8e 100644 --- a/clang/include/clang/Basic/BuiltinsNVPTX.def +++ b/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -39,7 +39,13 @@ #pragma push_macro("PTX70") #pragma push_macro("PTX71") #pragma push_macro("PTX72") -#define PTX72 "ptx72" +#pragma push_macro("PTX73") +#pragma push_macro("PTX74") +#pragma push_macro("PTX75") +#define PTX75 "ptx75" +#define PTX74 "ptx74|" PTX75 +#define PTX73 "ptx73|" PTX74 +#define PTX72 "ptx72|" PTX73 #define PTX71 "ptx71|" PTX72 #define PTX70 "ptx70|" PTX71 #define PTX65 "ptx65|" PTX70 @@ -683,6 +689,12 @@ BUILTIN(__nvvm_ldg_f2, "E2fE2fC*", "") BUILTIN(__nvvm_ldg_f4, "E4fE4fC*", "") BUILTIN(__nvvm_ldg_d2, "E2dE2dC*", "") +// Address space predicates. +BUILTIN(__nvvm_isspacep_const, "bvC*", "nc") +BUILTIN(__nvvm_isspacep_global, "bvC*", "nc") +BUILTIN(__nvvm_isspacep_local, "bvC*", "nc") +BUILTIN(__nvvm_isspacep_shared, "bvC*", "nc") + // Builtins to support WMMA instructions on sm_70 TARGET_BUILTIN(__hmma_m16n16k16_ld_a, "vi*iC*UiIi", "", AND(SM_70,PTX60)) TARGET_BUILTIN(__hmma_m16n16k16_ld_b, "vi*iC*UiIi", "", AND(SM_70,PTX60)) @@ -815,3 +827,6 @@ TARGET_BUILTIN(__nvvm_cp_async_wait_all, "v", "", AND(SM_80,PTX70)) #pragma pop_macro("PTX70") #pragma pop_macro("PTX71") #pragma pop_macro("PTX72") +#pragma pop_macro("PTX73") +#pragma pop_macro("PTX74") +#pragma pop_macro("PTX75") diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def index dfe97af300f..cd6b2df10e5 100644 --- a/clang/include/clang/Basic/BuiltinsPPC.def +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -74,8 +74,8 @@ BUILTIN(__builtin_ppc_fetch_and_swap, "UiUiD*Ui", "") BUILTIN(__builtin_ppc_fetch_and_swaplp, "ULiULiD*ULi", "") BUILTIN(__builtin_ppc_ldarx, "LiLiD*", "") BUILTIN(__builtin_ppc_lwarx, "iiD*", "") -BUILTIN(__builtin_ppc_lharx, "isD*", "") -BUILTIN(__builtin_ppc_lbarx, "UiUcD*", "") +BUILTIN(__builtin_ppc_lharx, "ssD*", "") +BUILTIN(__builtin_ppc_lbarx, "ccD*", "") BUILTIN(__builtin_ppc_stdcx, "iLiD*Li", "") BUILTIN(__builtin_ppc_stwcx, "iiD*i", "") BUILTIN(__builtin_ppc_sthcx, "isD*s", "") @@ -96,6 +96,13 @@ BUILTIN(__builtin_ppc_swdiv_nochk, "ddd", "") BUILTIN(__builtin_ppc_swdivs_nochk, "fff", "") BUILTIN(__builtin_ppc_alignx, "vIivC*", "nc") BUILTIN(__builtin_ppc_rdlam, "UWiUWiUWiUWIi", "nc") +BUILTIN(__builtin_ppc_compare_exp_uo, "idd", "") +BUILTIN(__builtin_ppc_compare_exp_lt, "idd", "") +BUILTIN(__builtin_ppc_compare_exp_gt, "idd", "") +BUILTIN(__builtin_ppc_compare_exp_eq, "idd", "") +BUILTIN(__builtin_ppc_test_data_class, "idIi", "t") +BUILTIN(__builtin_ppc_swdiv, "ddd", "") +BUILTIN(__builtin_ppc_swdivs, "fff", "") // Compare BUILTIN(__builtin_ppc_cmpeqb, "LLiLLiLLi", "") BUILTIN(__builtin_ppc_cmprb, "iCIiii", "") @@ -110,11 +117,11 @@ BUILTIN(__builtin_ppc_maddhd, "LLiLLiLLiLLi", "") BUILTIN(__builtin_ppc_maddhdu, "ULLiULLiULLiULLi", "") BUILTIN(__builtin_ppc_maddld, "LLiLLiLLiLLi", "") // Rotate -BUILTIN(__builtin_ppc_rlwnm, "UiUiIUiIUi", "") +BUILTIN(__builtin_ppc_rlwnm, "UiUiUiIUi", "") BUILTIN(__builtin_ppc_rlwimi, "UiUiUiIUiIUi", "") BUILTIN(__builtin_ppc_rldimi, "ULLiULLiULLiIUiIULLi", "") // load -BUILTIN(__builtin_ppc_load2r, "UiUs*", "") +BUILTIN(__builtin_ppc_load2r, "UsUs*", "") BUILTIN(__builtin_ppc_load4r, "UiUi*", "") BUILTIN(__builtin_ppc_load8r, "ULLiULLi*", "") // store @@ -144,6 +151,7 @@ BUILTIN(__builtin_ppc_mfspr, "ULiIi", "") BUILTIN(__builtin_ppc_mtmsr, "vUi", "") BUILTIN(__builtin_ppc_mtspr, "vIiULi", "") BUILTIN(__builtin_ppc_stfiw, "viC*d", "") +BUILTIN(__builtin_ppc_addex, "LLiLLiLLiCIi", "") BUILTIN(__builtin_ppc_get_timebase, "ULLi", "n") @@ -391,6 +399,7 @@ BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") BUILTIN(__builtin_altivec_vgbbd, "V16UcV16Uc", "") BUILTIN(__builtin_altivec_vbpermq, "V2ULLiV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vbpermd, "V2ULLiV2ULLiV16Uc", "") // P8 Crypto built-ins. BUILTIN(__builtin_altivec_crypto_vsbox, "V2ULLiV2ULLi", "") @@ -771,6 +780,10 @@ BUILTIN(__builtin_cfuged, "ULLiULLiULLi", "") BUILTIN(__builtin_cntlzdm, "ULLiULLiULLi", "") BUILTIN(__builtin_cnttzdm, "ULLiULLiULLi", "") +// Double-double (un)pack +BUILTIN(__builtin_unpack_longdouble, "dLdIi", "") +BUILTIN(__builtin_pack_longdouble, "Lddd", "") + // Generate random number BUILTIN(__builtin_darn, "LLi", "") BUILTIN(__builtin_darn_raw, "LLi", "") @@ -812,18 +825,20 @@ BUILTIN(__builtin_dcbf, "vvC*", "") // its given accumulator. // Provided builtins with _mma_ prefix for compatibility. -CUSTOM_BUILTIN(mma_lxvp, vsx_lxvp, "W256SLLiW256C*", false) -CUSTOM_BUILTIN(mma_stxvp, vsx_stxvp, "vW256SLLiW256C*", false) +CUSTOM_BUILTIN(mma_lxvp, vsx_lxvp, "W256SLiW256C*", false) +CUSTOM_BUILTIN(mma_stxvp, vsx_stxvp, "vW256SLiW256C*", false) CUSTOM_BUILTIN(mma_assemble_pair, vsx_assemble_pair, "vW256*VV", false) CUSTOM_BUILTIN(mma_disassemble_pair, vsx_disassemble_pair, "vv*W256*", false) +CUSTOM_BUILTIN(vsx_build_pair, vsx_assemble_pair, "vW256*VV", false) +CUSTOM_BUILTIN(mma_build_acc, mma_assemble_acc, "vW512*VVVV", false) // UNALIASED_CUSTOM_BUILTIN macro is used for built-ins that have // the same name as that of the intrinsic they generate, i.e. the // ID and INTR are the same. // This avoids repeating the ID and INTR in the macro expression. -UNALIASED_CUSTOM_BUILTIN(vsx_lxvp, "W256SLLiW256C*", false) -UNALIASED_CUSTOM_BUILTIN(vsx_stxvp, "vW256SLLiW256C*", false) +UNALIASED_CUSTOM_BUILTIN(vsx_lxvp, "W256SLiW256C*", false) +UNALIASED_CUSTOM_BUILTIN(vsx_stxvp, "vW256SLiW256C*", false) UNALIASED_CUSTOM_BUILTIN(vsx_assemble_pair, "vW256*VV", false) UNALIASED_CUSTOM_BUILTIN(vsx_disassemble_pair, "vv*W256*", false) diff --git a/clang/include/clang/Basic/BuiltinsRISCV.def b/clang/include/clang/Basic/BuiltinsRISCV.def index b2b4950f92b..06560415e68 100644 --- a/clang/include/clang/Basic/BuiltinsRISCV.def +++ b/clang/include/clang/Basic/BuiltinsRISCV.def @@ -15,8 +15,6 @@ # define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) #endif -#include "clang/Basic/riscv_vector_builtins.inc" - // Zbb extension TARGET_BUILTIN(__builtin_riscv_orc_b_32, "ZiZi", "nc", "experimental-zbb") TARGET_BUILTIN(__builtin_riscv_orc_b_64, "WiWi", "nc", "experimental-zbb,64bit") diff --git a/clang/include/clang/Basic/BuiltinsRISCVVector.def b/clang/include/clang/Basic/BuiltinsRISCVVector.def new file mode 100644 index 00000000000..008cb939a30 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsRISCVVector.def @@ -0,0 +1,21 @@ +//==- BuiltinsRISCVVector.def - RISC-V Vector Builtin Database ---*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the RISC-V-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +#include "clang/Basic/riscv_vector_builtins.inc" + +#undef BUILTIN +#undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def index 04ec45aa3b7..057d968e9bc 100644 --- a/clang/include/clang/Basic/BuiltinsWebAssembly.def +++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def @@ -119,18 +119,22 @@ TARGET_BUILTIN(__builtin_wasm_all_true_i16x8, "iV8s", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_all_true_i32x4, "iV4i", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_all_true_i64x2, "iV2LLi", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_bitmask_i8x16, "iV16Sc", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_bitmask_i16x8, "iV8s", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_bitmask_i32x4, "iV4i", "nc", "simd128") -TARGET_BUILTIN(__builtin_wasm_bitmask_i64x2, "iV2LLi", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_bitmask_i8x16, "UiV16Sc", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_bitmask_i16x8, "UiV8s", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_bitmask_i32x4, "UiV4i", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_bitmask_i64x2, "UiV2LLi", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_f32x4, "V4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_abs_f64x2, "V2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_min_f32x4, "V4fV4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_f32x4, "V4fV4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_pmin_f32x4, "V4fV4fV4f", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_pmax_f32x4, "V4fV4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_min_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_max_f64x2, "V2dV2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_pmin_f64x2, "V2dV2dV2d", "nc", "simd128") +TARGET_BUILTIN(__builtin_wasm_pmax_f64x2, "V2dV2dV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_ceil_f32x4, "V4fV4f", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_floor_f32x4, "V4fV4f", "nc", "simd128") @@ -157,5 +161,28 @@ TARGET_BUILTIN(__builtin_wasm_narrow_u_i16x8_i32x4, "V8UsV4iV4i", "nc", "simd128 TARGET_BUILTIN(__builtin_wasm_trunc_sat_zero_s_f64x2_i32x4, "V4iV2d", "nc", "simd128") TARGET_BUILTIN(__builtin_wasm_trunc_sat_zero_u_f64x2_i32x4, "V4UiV2d", "nc", "simd128") +// Relaxed SIMD builtins (experimental) +TARGET_BUILTIN(__builtin_wasm_fma_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_fms_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_fma_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_fms_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd") + +TARGET_BUILTIN(__builtin_wasm_laneselect_i8x16, "V16ScV16ScV16ScV16Sc", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_laneselect_i16x8, "V8sV8sV8sV8s", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_laneselect_i32x4, "V4iV4iV4iV4i", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_laneselect_i64x2, "V2LLiV2LLiV2LLiV2LLi", "nc", "relaxed-simd") + +TARGET_BUILTIN(__builtin_wasm_relaxed_swizzle_i8x16, "V16ScV16ScV16Sc", "nc", "relaxed-simd") + +TARGET_BUILTIN(__builtin_wasm_relaxed_min_f32x4, "V4fV4fV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_max_f32x4, "V4fV4fV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_min_f64x2, "V2dV2dV2d", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_max_f64x2, "V2dV2dV2d", "nc", "relaxed-simd") + +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_s_i32x4_f32x4, "V4iV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_u_i32x4_f32x4, "V4UiV4f", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2, "V4iV2d", "nc", "relaxed-simd") +TARGET_BUILTIN(__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2, "V4UiV2d", "nc", "relaxed-simd") + #undef BUILTIN #undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index 18e541fe9cb..bc6208be456 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -421,9 +421,9 @@ TARGET_BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16ciIc","ncV:128:", "sse4.2 TARGET_BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16ciIc","ncV:128:", "sse4.2") TARGET_BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16ciIc","ncV:128:", "sse4.2") -TARGET_BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "nc", "sse4.2") -TARGET_BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "nc", "sse4.2") -TARGET_BUILTIN(__builtin_ia32_crc32si, "UiUiUi", "nc", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "nc", "crc32") +TARGET_BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "nc", "crc32") +TARGET_BUILTIN(__builtin_ia32_crc32si, "UiUiUi", "nc", "crc32") // SSE4a TARGET_BUILTIN(__builtin_ia32_extrqi, "V2OiV2OiIcIc", "ncV:128:", "sse4a") @@ -1849,6 +1849,203 @@ TARGET_BUILTIN(__builtin_ia32_vp2intersect_d_512, "vV16iV16iUs*Us*", "nV:512:", TARGET_BUILTIN(__builtin_ia32_vp2intersect_d_256, "vV8iV8iUc*Uc*", "nV:256:", "avx512vp2intersect,avx512vl") TARGET_BUILTIN(__builtin_ia32_vp2intersect_d_128, "vV4iV4iUc*Uc*", "nV:128:", "avx512vp2intersect,avx512vl") +// AVX512 fp16 intrinsics +TARGET_BUILTIN(__builtin_ia32_vcomish, "iV8xV8xIiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_addph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_subph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_mulph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_divph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_maxph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_minph512, "V32xV32xV32xIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_minph256, "V16xV16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_minph128, "V8xV8xV8x", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxph256, "V16xV16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_maxph128, "V8xV8xV8x", "ncV:128:", "avx512fp16,avx512vl") + +TARGET_BUILTIN(__builtin_ia32_addsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_divsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_mulsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_subsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_maxsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_minsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_cmpph512_mask, "UiV32xV32xIiUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_cmpph256_mask, "UsV16xV16xIiUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpph128_mask, "UcV8xV8xIiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_cmpsh_mask, "UcV8xV8xIiUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_loadsh128_mask, "V8xV8x*V8xUc", "nV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_storesh128_mask, "vV8x*V8xUc", "nV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_rcpph128_mask, "V8xV8xV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rcpph256_mask, "V16xV16xV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rcpph512_mask, "V32xV32xV32xUi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_rsqrtph128_mask, "V8xV8xV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rsqrtph256_mask, "V16xV16xV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rsqrtph512_mask, "V32xV32xV32xUi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_getmantph128_mask, "V8xV8xIiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_getmantph256_mask, "V16xV16xIiV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_getmantph512_mask, "V32xV32xIiV32xUiIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_getexpph128_mask, "V8xV8xV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexpph256_mask, "V16xV16xV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_getexpph512_mask, "V32xV32xV32xUiIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_scalefph128_mask, "V8xV8xV8xV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefph256_mask, "V16xV16xV16xV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_scalefph512_mask, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_rndscaleph_128_mask, "V8xV8xIiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscaleph_256_mask, "V16xV16xIiV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_rndscaleph_mask, "V32xV32xIiV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reduceph128_mask, "V8xV8xIiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduceph256_mask, "V16xV16xIiV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduceph512_mask, "V32xV32xIiV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_rcpsh_mask, "V8xV8xV8xV8xUc", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_rsqrtsh_mask, "V8xV8xV8xV8xUc", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_getmantsh_round_mask, "V8xV8xV8xIiV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_getexpsh128_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_scalefsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_rndscalesh_round_mask, "V8xV8xV8xV8xUcIiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reducesh_mask, "V8xV8xV8xV8xUcIiIi", "ncV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_sqrtph, "V8xV8x", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_sqrtph256, "V16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_sqrtph512, "V32xV32xIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_sqrtsh_round_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_fpclassph128_mask, "UcV8xIiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_fpclassph256_mask, "UsV16xIiUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_fpclassph512_mask, "UiV32xIiUi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_fpclasssh_mask, "UcV8xIiUc", "ncV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vcvtpd2ph128_mask, "V8xV2dV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtpd2ph256_mask, "V8xV4dV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtpd2ph512_mask, "V8xV8dV8xUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2pd128_mask, "V2dV8xV2dUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2pd256_mask, "V4dV8xV4dUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2pd512_mask, "V8dV8xV8dUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2ss_round_mask, "V4fV4fV8xV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtss2sh_round_mask, "V8xV8xV4fV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsd2sh_round_mask, "V8xV8xV2dV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2sd_round_mask, "V2dV2dV8xV2dUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2w128_mask, "V8sV8xV8sUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2w256_mask, "V16sV16xV16sUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2w512_mask, "V32sV32xV32sUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2w128_mask, "V8sV8xV8sUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2w256_mask, "V16sV16xV16sUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2w512_mask, "V32sV32xV32sUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtw2ph128_mask, "V8xV8sV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtw2ph256_mask, "V16xV16sV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtw2ph512_mask, "V32xV32sV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uw128_mask, "V8UsV8xV8UsUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uw256_mask, "V16UsV16xV16UsUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uw512_mask, "V32UsV32xV32UsUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uw128_mask, "V8UsV8xV8UsUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uw256_mask, "V16UsV16xV16UsUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uw512_mask, "V32UsV32xV32UsUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtuw2ph128_mask, "V8xV8UsV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtuw2ph256_mask, "V16xV16UsV16xUs", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtuw2ph512_mask, "V32xV32UsV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2dq128_mask, "V4iV8xV4iUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2dq256_mask, "V8iV8xV8iUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2dq512_mask, "V16iV16xV16iUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2udq128_mask, "V4UiV8xV4UiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2udq256_mask, "V8UiV8xV8UiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2udq512_mask, "V16UiV16xV16UiUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtdq2ph128_mask, "V8xV4iV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtdq2ph256_mask, "V8xV8iV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtdq2ph512_mask, "V16xV16iV16xUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtudq2ph128_mask, "V8xV4UiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtudq2ph256_mask, "V8xV8UiV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtudq2ph512_mask, "V16xV16UiV16xUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2dq128_mask, "V4iV8xV4iUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2dq256_mask, "V8iV8xV8iUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2dq512_mask, "V16iV16xV16iUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2udq128_mask, "V4UiV8xV4UiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2udq256_mask, "V8UiV8xV8UiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2udq512_mask, "V16UiV16xV16UiUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtqq2ph128_mask, "V8xV2OiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtqq2ph256_mask, "V8xV4OiV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtqq2ph512_mask, "V8xV8OiV8xUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2qq128_mask, "V2OiV8xV2OiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2qq256_mask, "V4OiV8xV4OiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2qq512_mask, "V8OiV8xV8OiUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtuqq2ph128_mask, "V8xV2UOiV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtuqq2ph256_mask, "V8xV4UOiV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtuqq2ph512_mask, "V8xV8UOiV8xUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uqq128_mask, "V2UOiV8xV2UOiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uqq256_mask, "V4UOiV8xV4UOiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2uqq512_mask, "V8UOiV8xV8UOiUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2qq128_mask, "V2OiV8xV2OiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2qq256_mask, "V4OiV8xV4OiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2qq512_mask, "V8OiV8xV8OiUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uqq128_mask, "V2UOiV8xV2UOiUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uqq256_mask, "V4UOiV8xV4UOiUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvttph2uqq512_mask, "V8UOiV8xV8UOiUcIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2si32, "iV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2usi32, "UiV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtusi2sh, "V8xV8xUiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsi2sh, "V8xV8xiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttsh2si32, "iV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttsh2usi32, "UiV8xIi", "ncV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vcvtph2psx128_mask, "V4fV8xV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2psx256_mask, "V8fV8xV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtph2psx512_mask, "V16fV16xV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtps2phx128_mask, "V8xV4fV8xUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtps2phx256_mask, "V8xV8fV8xUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vcvtps2phx512_mask, "V16xV16fV16xUsIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vfmaddph, "V8xV8xV8xV8x", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddph256, "V16xV16xV16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddph512_mask, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddph512_mask3, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddph512_maskz, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubph, "V8xV8xV8xV8x", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubph256, "V16xV16xV16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubph512_mask, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubph512_maskz, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddsubph512_mask3, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vfmsubaddph512_mask3, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmsubph512_mask3, "V32xV32xV32xV32xUiIi", "ncV:512:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vfmaddsh3_mask, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddsh3_maskz, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddsh3_mask3, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmsubsh3_mask3, "V8xV8xV8xV8xUcIi", "ncV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vfmaddcph128_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph128_maskz, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph256_mask, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph256_maskz, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph512_mask, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph512_maskz, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcph512_mask3, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph128_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph128_maskz, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph256_mask, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph256_maskz, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph512_mask, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph512_maskz, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcph512_mask3, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcsh_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcsh_maskz, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcsh_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcsh_maskz, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcsh_round_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmaddcsh_round_mask3, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcsh_round_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmaddcsh_round_mask3, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") + +TARGET_BUILTIN(__builtin_ia32_vfmulcsh_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmulcsh_mask, "V4fV4fV4fV4fUcIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfmulcph128_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmulcph256_mask, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfmulcph512_mask, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vfcmulcph128_mask, "V4fV4fV4fV4fUc", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmulcph256_mask, "V8fV8fV8fV8fUc", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_vfcmulcph512_mask, "V16fV16fV16fV16fUsIi", "ncV:512:", "avx512fp16") + // generic select intrinsics TARGET_BUILTIN(__builtin_ia32_selectb_128, "V16cUsV16cV16c", "ncV:128:", "avx512bw,avx512vl") TARGET_BUILTIN(__builtin_ia32_selectb_256, "V32cUiV32cV32c", "ncV:256:", "avx512bw,avx512vl") @@ -1859,6 +2056,9 @@ TARGET_BUILTIN(__builtin_ia32_selectw_512, "V32sUiV32sV32s", "ncV:512:", "avx512 TARGET_BUILTIN(__builtin_ia32_selectd_128, "V4iUcV4iV4i", "ncV:128:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectd_256, "V8iUcV8iV8i", "ncV:256:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectd_512, "V16iUsV16iV16i", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_selectph_128, "V8xUcV8xV8x", "ncV:128:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_selectph_256, "V16xUsV16xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_selectph_512, "V32xUiV32xV32x", "ncV:512:", "avx512fp16") TARGET_BUILTIN(__builtin_ia32_selectq_128, "V2OiUcV2OiV2Oi", "ncV:128:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectq_256, "V4OiUcV4OiV4Oi", "ncV:256:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectq_512, "V8OiUcV8OiV8Oi", "ncV:512:", "avx512f") @@ -1868,6 +2068,7 @@ TARGET_BUILTIN(__builtin_ia32_selectps_512, "V16fUsV16fV16f", "ncV:512:", "avx51 TARGET_BUILTIN(__builtin_ia32_selectpd_128, "V2dUcV2dV2d", "ncV:128:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectpd_256, "V4dUcV4dV4d", "ncV:256:", "avx512vl") TARGET_BUILTIN(__builtin_ia32_selectpd_512, "V8dUcV8dV8d", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_selectsh_128, "V8xUcV8xV8x", "ncV:128:", "avx512fp16") TARGET_BUILTIN(__builtin_ia32_selectss_128, "V4fUcV4fV4f", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_selectsd_128, "V2dUcV2dV2d", "ncV:128:", "avx512f") @@ -1878,12 +2079,24 @@ TARGET_BUILTIN(__builtin_ia32_reduce_and_d512, "iV16i", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_and_q512, "OiV8Oi", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_fadd_pd512, "ddV8d", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ps512, "ffV16f", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ph512, "xxV32x", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ph256, "xxV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduce_fadd_ph128, "xxV8x", "ncV:128:", "avx512fp16,avx512vl") TARGET_BUILTIN(__builtin_ia32_reduce_fmax_pd512, "dV8d", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_fmax_ps512, "fV16f", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_reduce_fmax_ph512, "xV32x", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reduce_fmax_ph256, "xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduce_fmax_ph128, "xV8x", "ncV:128:", "avx512fp16,avx512vl") TARGET_BUILTIN(__builtin_ia32_reduce_fmin_pd512, "dV8d", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_fmin_ps512, "fV16f", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_reduce_fmin_ph512, "xV32x", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reduce_fmin_ph256, "xV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduce_fmin_ph128, "xV8x", "ncV:128:", "avx512fp16,avx512vl") TARGET_BUILTIN(__builtin_ia32_reduce_fmul_pd512, "ddV8d", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_fmul_ps512, "ffV16f", "ncV:512:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_reduce_fmul_ph512, "xxV32x", "ncV:512:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_reduce_fmul_ph256, "xxV16x", "ncV:256:", "avx512fp16,avx512vl") +TARGET_BUILTIN(__builtin_ia32_reduce_fmul_ph128, "xxV8x", "ncV:128:", "avx512fp16,avx512vl") TARGET_BUILTIN(__builtin_ia32_reduce_mul_d512, "iV16i", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_mul_q512, "OiV8Oi", "ncV:512:", "avx512f") TARGET_BUILTIN(__builtin_ia32_reduce_or_d512, "iV16i", "ncV:512:", "avx512f") diff --git a/clang/include/clang/Basic/BuiltinsX86_64.def b/clang/include/clang/Basic/BuiltinsX86_64.def index ce2b1decdf6..c3b9703a9cc 100644 --- a/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/clang/include/clang/Basic/BuiltinsX86_64.def @@ -44,7 +44,7 @@ TARGET_BUILTIN(__builtin_ia32_cvttsd2si64, "OiV2d", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_movnti64, "vOi*Oi", "n", "sse2") TARGET_BUILTIN(__builtin_ia32_vec_ext_v2di, "OiV2OiIi", "ncV:128:", "sse2") TARGET_BUILTIN(__builtin_ia32_vec_set_v2di, "V2OiV2OiOiIi", "ncV:128:", "sse4.1") -TARGET_BUILTIN(__builtin_ia32_crc32di, "UOiUOiUOi", "nc", "sse4.2") +TARGET_BUILTIN(__builtin_ia32_crc32di, "UOiUOiUOi", "nc", "crc32") TARGET_BUILTIN(__builtin_ia32_vec_ext_v4di, "OiV4OiIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_vec_set_v4di, "V4OiV4OiOiIi", "ncV:256:", "avx") TARGET_BUILTIN(__builtin_ia32_rdfsbase32, "Ui", "n", "fsgsbase") @@ -92,6 +92,12 @@ TARGET_BUILTIN(__builtin_ia32_cvtsi2sd64, "V2dV2dOiIi", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_cvtsi2ss64, "V4fV4fOiIi", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_cvtusi2sd64, "V2dV2dUOiIi", "ncV:128:", "avx512f") TARGET_BUILTIN(__builtin_ia32_cvtusi2ss64, "V4fV4fUOiIi", "ncV:128:", "avx512f") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2si64, "OiV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsh2usi64, "UOiV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtusi642sh, "V8xV8xUOiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvtsi642sh, "V8xV8xOiIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttsh2si64, "OiV8xIi", "ncV:128:", "avx512fp16") +TARGET_BUILTIN(__builtin_ia32_vcvttsh2usi64, "UOiV8xIi", "ncV:128:", "avx512fp16") TARGET_BUILTIN(__builtin_ia32_directstore_u64, "vULi*ULi", "n", "movdiri") // UINTR diff --git a/clang/include/clang/Basic/CLWarnings.h b/clang/include/clang/Basic/CLWarnings.h new file mode 100644 index 00000000000..e3351f430c4 --- /dev/null +++ b/clang/include/clang/Basic/CLWarnings.h @@ -0,0 +1,26 @@ +//===--- CLWarnings.h - Maps some cl.exe warning ids -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_CLWARNINGS_H +#define LLVM_CLANG_BASIC_CLWARNINGS_H + +#include "llvm/ADT/Optional.h" + +namespace clang { + +namespace diag { +enum class Group; +} + +/// For cl.exe warning IDs that cleany map to clang diagnostic groups, +/// returns the corresponding group. Else, returns an empty Optional. +llvm::Optional diagGroupFromCLWarningID(unsigned); + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_CLWARNINGS_H diff --git a/clang/include/clang/Basic/CharInfo.h b/clang/include/clang/Basic/CharInfo.h index 8577475fab0..c751b6a005e 100644 --- a/clang/include/clang/Basic/CharInfo.h +++ b/clang/include/clang/Basic/CharInfo.h @@ -43,10 +43,15 @@ LLVM_READNONE inline bool isASCII(char c) { return static_cast(c) <= 127; } +LLVM_READNONE inline bool isASCII(unsigned char c) { return c <= 127; } + +/// Returns true if this is an ASCII character. +LLVM_READNONE inline bool isASCII(uint32_t c) { return c <= 127; } + /// Returns true if this is a valid first character of a C identifier, /// which is [a-zA-Z_]. -LLVM_READONLY inline bool isIdentifierHead(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isAsciiIdentifierStart(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_UNDER)) return true; @@ -55,8 +60,8 @@ LLVM_READONLY inline bool isIdentifierHead(unsigned char c, /// Returns true if this is a body character of a C identifier, /// which is [a-zA-Z0-9_]. -LLVM_READONLY inline bool isIdentifierBody(unsigned char c, - bool AllowDollar = false) { +LLVM_READONLY inline bool isAsciiIdentifierContinue(unsigned char c, + bool AllowDollar = false) { using namespace charinfo; if (InfoTable[c] & (CHAR_UPPER|CHAR_LOWER|CHAR_DIGIT|CHAR_UNDER)) return true; @@ -181,13 +186,13 @@ LLVM_READONLY inline char toUppercase(char c) { /// /// Note that this is a very simple check; it does not accept UCNs as valid /// identifier characters. -LLVM_READONLY inline bool isValidIdentifier(StringRef S, - bool AllowDollar = false) { - if (S.empty() || !isIdentifierHead(S[0], AllowDollar)) +LLVM_READONLY inline bool isValidAsciiIdentifier(StringRef S, + bool AllowDollar = false) { + if (S.empty() || !isAsciiIdentifierStart(S[0], AllowDollar)) return false; for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I) - if (!isIdentifierBody(*I, AllowDollar)) + if (!isAsciiIdentifierContinue(*I, AllowDollar)) return false; return true; diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index e3202cf8875..94b3003a9c3 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -54,6 +54,7 @@ CODEGENOPT(UniqueBasicBlockSectionNames, 1, 1) ///< Set for -funique-basic-block CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX. ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none +CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free. CODEGENOPT(DisableFree , 1, 0) ///< Don't free memory. CODEGENOPT(DiscardValueNames , 1, 0) ///< Discard Value Names from the IR (LLVMContext flag) CODEGENOPT(DisableLLVMPasses , 1, 0) ///< Don't run any LLVM IR passes to get @@ -91,6 +92,8 @@ CODEGENOPT(EmulatedTLS , 1, 0) ///< Set by default or -f[no-]emulated-tls. CODEGENOPT(ExplicitEmulatedTLS , 1, 0) ///< Set if -f[no-]emulated-tls is used. /// Embed Bitcode mode (off/all/bitcode/marker). ENUM_CODEGENOPT(EmbedBitcode, EmbedBitcodeKind, 2, Embed_Off) +/// Inline asm dialect, -masm=(att|intel) +ENUM_CODEGENOPT(InlineAsmDialect, InlineAsmDialectKind, 1, IAD_ATT) CODEGENOPT(ForbidGuardVariables , 1, 0) ///< Issue errors if C++ guard variables ///< are required. CODEGENOPT(FunctionSections , 1, 0) ///< Set when -ffunction-sections is enabled. @@ -188,6 +191,7 @@ CODEGENOPT(NoZeroInitializedInBSS , 1, 0) ///< -fno-zero-initialized-in-bss. ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy) /// Replace certain message sends with calls to ObjC runtime entrypoints CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1) +CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0) VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified. VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified. @@ -259,6 +263,8 @@ CODEGENOPT(SanitizeCoverageInlineBoolFlag, 1, 0) ///< Use inline bool flag. CODEGENOPT(SanitizeCoveragePCTable, 1, 0) ///< Create a PC Table. CODEGENOPT(SanitizeCoverageNoPrune, 1, 0) ///< Disable coverage pruning. CODEGENOPT(SanitizeCoverageStackDepth, 1, 0) ///< Enable max stack depth tracing +CODEGENOPT(SanitizeCoverageTraceLoads, 1, 0) ///< Enable tracing of loads. +CODEGENOPT(SanitizeCoverageTraceStores, 1, 0) ///< Enable tracing of stores. CODEGENOPT(SanitizeStats , 1, 0) ///< Collect statistics for sanitizers. CODEGENOPT(SimplifyLibCalls , 1, 1) ///< Set when -fbuiltin is enabled. CODEGENOPT(SoftFloat , 1, 0) ///< -soft-float. @@ -274,7 +280,7 @@ VALUE_CODEGENOPT(TimeTraceGranularity, 32, 500) ///< Minimum time granularity (i CODEGENOPT(UnrollLoops , 1, 0) ///< Control whether loops are unrolled. CODEGENOPT(RerollLoops , 1, 0) ///< Control whether loops are rerolled. CODEGENOPT(NoUseJumpTables , 1, 0) ///< Set when -fno-jump-tables is enabled. -CODEGENOPT(UnwindTables , 1, 0) ///< Emit unwind tables. +VALUE_CODEGENOPT(UnwindTables, 2, 0) ///< Unwind tables (1) or asynchronous unwind tables (2) CODEGENOPT(VectorizeLoop , 1, 0) ///< Run loop vectorizer. CODEGENOPT(VectorizeSLP , 1, 0) ///< Run SLP vectorizer. CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate. @@ -293,6 +299,8 @@ CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to force stack ///< realignment. CODEGENOPT(UseInitArray , 1, 0) ///< Control whether to use .init_array or ///< .ctors. +VALUE_CODEGENOPT(LoopAlignment , 32, 0) ///< Overrides default loop + ///< alignment, if not 0. VALUE_CODEGENOPT(StackAlignment , 32, 0) ///< Overrides default stack ///< alignment, if not 0. VALUE_CODEGENOPT(StackProbeSize , 32, 4096) ///< Overrides default stack @@ -317,6 +325,12 @@ CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete ///< template parameter descriptions in ///< forward declarations (versus just ///< including them in the name). +ENUM_CODEGENOPT(DebugSimpleTemplateNames, codegenoptions::DebugTemplateNamesKind, 2, codegenoptions::DebugTemplateNamesKind::Full) ///< Whether to emit template parameters + ///< in the textual names of template + ///< specializations. + ///< Implies DebugFwdTemplateNames to + ///< allow decorated names to be + ///< reconstructed when needed. CODEGENOPT(EmitLLVMUseLists, 1, 0) ///< Control whether to serialize use-lists. CODEGENOPT(WholeProgramVTables, 1, 0) ///< Whether to apply whole-program @@ -437,6 +451,14 @@ CODEGENOPT(AAPCSBitfieldWidth, 1, 1) /// propagate signaling NaN inputs per IEEE 754-2008 (AMDGPU Only) CODEGENOPT(EmitIEEENaNCompliantInsts, 1, 1) +// Whether to emit Swift Async function extended frame information: auto, +// never, always. +ENUM_CODEGENOPT(SwiftAsyncFramePointer, SwiftAsyncFramePointerKind, 2, + SwiftAsyncFramePointerKind::Always) + +/// Whether to skip RAX setup when passing variable arguments (x86 only). +CODEGENOPT(SkipRaxSetup, 1, 0) + #undef CODEGENOPT #undef ENUM_CODEGENOPT #undef VALUE_CODEGENOPT diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 617c255641e..664e4998b8d 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -97,6 +97,11 @@ public: Embed_Marker // Embed a marker as a placeholder for bitcode. }; + enum InlineAsmDialectKind { + IAD_ATT, + IAD_Intel, + }; + // This field stores one of the allowed values for the option // -fbasic-block-sections=. The allowed values with this option are: // {"labels", "all", "list=", "none"}. @@ -125,6 +130,13 @@ public: All, // Keep all frame pointers. }; + enum class SwiftAsyncFramePointerKind { + Auto, // Choose Swift async extended frame info based on deployment target. + Always, // Unconditionally emit Swift async extended frame info. + Never, // Don't emit Swift async extended frame info. + Default = Always, + }; + enum FiniteLoopsKind { Language, // Not specified, use language standard. Always, // All loops are assumed to be finite. @@ -456,7 +468,8 @@ public: // Check if any one of SanitizeCoverage* is enabled. bool hasSanitizeCoverage() const { return SanitizeCoverageType || SanitizeCoverageIndirectCalls || - SanitizeCoverageTraceCmp; + SanitizeCoverageTraceCmp || SanitizeCoverageTraceLoads || + SanitizeCoverageTraceStores; } }; diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index aa12724cbf0..8c08ab3f5d7 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -31,8 +31,13 @@ enum class CudaVersion { CUDA_110, CUDA_111, CUDA_112, - LATEST = CUDA_112, - LATEST_SUPPORTED = CUDA_101, + CUDA_113, + CUDA_114, + CUDA_115, + FULLY_SUPPORTED = CUDA_115, + PARTIALLY_SUPPORTED = + CUDA_115, // Partially supported. Proceed with a warning. + NEW = 10000, // Too new. Issue a warning, but allow using it. }; const char *CudaVersionToString(CudaVersion V); // Input is "Major.Minor" diff --git a/clang/include/clang/Basic/DebugInfoOptions.h b/clang/include/clang/Basic/DebugInfoOptions.h index c1259d7797d..a99a2b5903d 100644 --- a/clang/include/clang/Basic/DebugInfoOptions.h +++ b/clang/include/clang/Basic/DebugInfoOptions.h @@ -54,6 +54,12 @@ enum DebugInfoKind { UnusedTypeInfo, }; +enum class DebugTemplateNamesKind { + Full, + Simple, + Mangled +}; + } // end namespace codegenoptions } // end namespace clang diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h index 3b915fb15a8..e5577e74fa6 100644 --- a/clang/include/clang/Basic/Diagnostic.h +++ b/clang/include/clang/Basic/Diagnostic.h @@ -164,9 +164,9 @@ struct DiagnosticStorage { /// The values for the various substitution positions. /// /// This is used when the argument is not an std::string. The specific value - /// is mangled into an intptr_t and the interpretation depends on exactly + /// is mangled into an uint64_t and the interpretation depends on exactly /// what sort of argument kind it is. - intptr_t DiagArgumentsVal[MaxArguments]; + uint64_t DiagArgumentsVal[MaxArguments]; /// The values for the various substitution positions that have /// string arguments. @@ -807,6 +807,9 @@ public: bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc = SourceLocation()); + bool setSeverityForGroup(diag::Flavor Flavor, diag::Group Group, + diag::Severity Map, + SourceLocation Loc = SourceLocation()); /// Set the warning-as-error flag for the given diagnostic group. /// @@ -1176,7 +1179,7 @@ public: DiagStorage = nullptr; } - void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + void AddTaggedVal(uint64_t V, DiagnosticsEngine::ArgumentKind Kind) const { if (!DiagStorage) DiagStorage = getStorage(); @@ -1399,6 +1402,12 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, return DB; } +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + int64_t I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return DB; +} + // We use enable_if here to prevent that this overload is selected for // pointers or other arguments that are implicitly convertible to bool. template @@ -1415,6 +1424,12 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, return DB; } +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + uint64_t I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); + return DB; +} + inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, tok::TokenKind I) { DB.AddTaggedVal(static_cast(I), DiagnosticsEngine::ak_tokenkind); @@ -1577,18 +1592,18 @@ public: /// Return the specified signed integer argument. /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_sint - int getArgSInt(unsigned Idx) const { + int64_t getArgSInt(unsigned Idx) const { assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint && "invalid argument accessor!"); - return (int)DiagObj->DiagStorage.DiagArgumentsVal[Idx]; + return (int64_t)DiagObj->DiagStorage.DiagArgumentsVal[Idx]; } /// Return the specified unsigned integer argument. /// \pre getArgKind(Idx) == DiagnosticsEngine::ak_uint - unsigned getArgUInt(unsigned Idx) const { + uint64_t getArgUInt(unsigned Idx) const { assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint && "invalid argument accessor!"); - return (unsigned)DiagObj->DiagStorage.DiagArgumentsVal[Idx]; + return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; } /// Return the specified IdentifierInfo argument. @@ -1602,7 +1617,7 @@ public: /// Return the specified non-string argument in an opaque form. /// \pre getArgKind(Idx) != DiagnosticsEngine::ak_std_string - intptr_t getRawArg(unsigned Idx) const { + uint64_t getRawArg(unsigned Idx) const { assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string && "invalid argument accessor!"); return DiagObj->DiagStorage.DiagArgumentsVal[Idx]; diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 496d86ee2fe..d788c851791 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -567,8 +567,8 @@ def remark_sanitize_address_insert_extra_padding_accepted : Remark< def remark_sanitize_address_insert_extra_padding_rejected : Remark< "-fsanitize-address-field-padding ignored for %0 because it " "%select{is not C++|is packed|is a union|is trivially copyable|" - "has trivial destructor|is standard layout|is in a blacklisted file|" - "is blacklisted}1">, ShowInSystemHeader, + "has trivial destructor|is standard layout|is in a ignorelisted file|" + "is ignorelisted}1">, ShowInSystemHeader, InGroup; def warn_npot_ms_struct : Warning< diff --git a/clang/include/clang/Basic/DiagnosticCategories.h b/clang/include/clang/Basic/DiagnosticCategories.h index 0decf15080a..2bbdeb31a7b 100644 --- a/clang/include/clang/Basic/DiagnosticCategories.h +++ b/clang/include/clang/Basic/DiagnosticCategories.h @@ -19,6 +19,13 @@ namespace clang { #undef GET_CATEGORY_TABLE DiagCat_NUM_CATEGORIES }; + + enum class Group { +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups) GroupName, +#include "clang/Basic/DiagnosticGroups.inc" +#undef CATEGORY +#undef DIAG_ENTRY + }; } // end namespace diag } // end namespace clang diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 4dff3379ed3..fe4ac5ed6cb 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -149,8 +149,8 @@ def err_nullability_conflicting : Error< // OpenCL Section 6.8.g def err_opencl_unknown_type_specifier : Error< - "%select{OpenCL C|C++ for OpenCL}0 version %1 does not support the " - "'%2' %select{type qualifier|storage class specifier}3">; + "%0 does not support the '%1' " + "%select{type qualifier|storage class specifier}2">; def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup; @@ -298,6 +298,8 @@ def err_target_unsupported_unaligned : Error< "the %0 sub-architecture does not support unaligned accesses">; def err_target_unsupported_execute_only : Error< "execute only is not supported for the %0 sub-architecture">; +def err_target_unsupported_tp_hard : Error< + "hardware TLS register is not supported for the %0 sub-architecture">; def err_target_unsupported_mcmse : Error< "-mcmse is not supported for %0">; def err_opt_not_valid_with_opt : Error< @@ -306,6 +308,8 @@ def err_opt_not_valid_without_opt : Error< "option '%0' cannot be specified without '%1'">; def err_opt_not_valid_on_target : Error< "option '%0' cannot be specified on this target">; +def err_invalid_feature_combination : Error< + "invalid feature combination: %0">; // Source manager def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 3b4daa59f66..ff8c36910e1 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -16,6 +16,8 @@ def err_drv_unsupported_opt_with_suggestion : Error< "unsupported option '%0'; did you mean '%1'?">; def err_drv_unsupported_opt_for_target : Error< "unsupported option '%0' for target '%1'">; +def err_drv_unsupported_opt_for_language_mode : Error< + "unsupported option '%0' for language mode '%1'">; def err_drv_unsupported_option_argument : Error< "unsupported argument '%1' to option '%0'">; def err_drv_unknown_stdin_type : Error< @@ -29,6 +31,9 @@ def err_drv_invalid_riscv_arch_name : Error< "invalid arch name '%0', %1">; def err_drv_invalid_riscv_ext_arch_name : Error< "invalid arch name '%0', %1 '%2'">; +def warn_drv_invalid_arch_name_with_suggestion : Warning< + "ignoring invalid /arch: argument '%0'; for %select{64|32}1-bit expected one of %2">, + InGroup; def warn_drv_avr_mcu_not_specified : Warning< "no target microcontroller specified on command line, cannot " "link standard libraries, please pass -mmcu=">, @@ -52,38 +57,57 @@ def warn_drv_avr_stdlib_not_linked: Warning< "standard library not linked and so no interrupt vector table or " "compiler runtime routines will be linked">, InGroup; -def err_drv_cuda_bad_gpu_arch : Error<"Unsupported CUDA gpu architecture: %0">; +def err_drv_cuda_bad_gpu_arch : Error<"unsupported CUDA gpu architecture: %0">; def err_drv_no_cuda_installation : Error< - "cannot find CUDA installation. Provide its path via --cuda-path, or pass " - "-nocudainc to build without CUDA includes.">; + "cannot find CUDA installation; provide its path via '--cuda-path', or pass " + "'-nocudainc' to build without CUDA includes">; def err_drv_no_cuda_libdevice : Error< - "cannot find libdevice for %0. Provide path to different CUDA installation " - "via --cuda-path, or pass -nocudalib to build without linking with libdevice.">; + "cannot find libdevice for %0; provide path to different CUDA installation " + "via '--cuda-path', or pass '-nocudalib' to build without linking with " + "libdevice">; def err_drv_no_rocm_device_lib : Error< - "cannot find ROCm device library%select{| for %1}0. Provide its path via --rocm-path or " - "--rocm-device-lib-path, or pass -nogpulib to build without ROCm device library.">; + "cannot find ROCm device library%select{| for %1}0; provide its path via " + "'--rocm-path' or '--rocm-device-lib-path', or pass '-nogpulib' to build " + "without ROCm device library">; def err_drv_no_hip_runtime : Error< - "cannot find HIP runtime. Provide its path via --rocm-path, or pass " - "-nogpuinc to build without HIP runtime.">; + "cannot find HIP runtime; provide its path via '--rocm-path', or pass " + "'-nogpuinc' to build without HIP runtime">; def err_drv_undetermined_amdgpu_arch : Error< - "Cannot determine AMDGPU architecture: %0. Consider passing it via --march.">; + "cannot determine AMDGPU architecture: %0; consider passing it via " + "'--march'">; def err_drv_cuda_version_unsupported : Error< "GPU arch %0 is supported by CUDA versions between %1 and %2 (inclusive), " - "but installation at %3 is %4. Use --cuda-path to specify a different CUDA " - "install, pass a different GPU arch with --cuda-gpu-arch, or pass " - "--no-cuda-version-check.">; -def warn_drv_unknown_cuda_version: Warning< - "Unknown CUDA version. %0 Assuming the latest supported version %1">, + "but installation at %3 is %4; use '--cuda-path' to specify a different CUDA " + "install, pass a different GPU arch with '--cuda-gpu-arch', or pass " + "'--no-cuda-version-check'">; +def warn_drv_new_cuda_version: Warning< + "CUDA version%0 is newer than the latest%select{| partially}1 supported version %2">, InGroup; -def err_drv_cuda_host_arch : Error<"unsupported architecture '%0' for host compilation.">; -def err_drv_mix_cuda_hip : Error<"Mixed Cuda and HIP compilation is not supported.">; -def err_drv_bad_target_id : Error<"Invalid target ID: %0 (A target ID is a processor name " - "followed by an optional list of predefined features post-fixed by a plus or minus sign deliminated " - "by colon, e.g. 'gfx908:sramecc+:xnack-')">; -def err_drv_bad_offload_arch_combo : Error<"Invalid offload arch combinations: %0 and %1 (For a specific " - "processor, a feature should either exist in all offload archs, or not exist in any offload archs)">; +def warn_drv_partially_supported_cuda_version: Warning< + "CUDA version %0 is only partially supported">, + InGroup; +def err_drv_cuda_host_arch : Error< + "unsupported architecture '%0' for host compilation">; +def err_drv_mix_cuda_hip : Error< + "mixed CUDA and HIP compilation is not supported">; +def err_drv_bad_target_id : Error< + "invalid target ID '%0'; format is a processor name followed by an optional " + "colon-delimited list of features followed by an enable/disable sign (e.g., " + "'gfx908:sramecc+:xnack-')">; +def err_drv_bad_offload_arch_combo : Error< + "invalid offload arch combinations: '%0' and '%1' (for a specific processor, " + "a feature should either exist in all offload archs, or not exist in any " + "offload archs)">; +def warn_drv_unsupported_option_for_offload_arch_req_feature : Warning< + "ignoring '%0' option as it is not currently supported for " + "offload arch '%1'. Use it with an offload arch containing '%2' instead">, + InGroup; +def warn_drv_unsupported_option_for_target : Warning< + "ignoring '%0' option as it is not currently supported for target '%1'">, + InGroup; + def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; def err_drv_invalid_linker_name : Error< @@ -171,8 +195,8 @@ def err_drv_invalid_argument_to_option : Error< "invalid argument '%0' to -%1">; def err_drv_malformed_sanitizer_ignorelist : Error< "malformed sanitizer ignorelist: '%0'">; -def err_drv_malformed_sanitizer_coverage_whitelist : Error< - "malformed sanitizer coverage whitelist: '%0'">; +def err_drv_malformed_sanitizer_coverage_allowlist : Error< + "malformed sanitizer coverage allowlist: '%0'">; def err_drv_malformed_sanitizer_coverage_ignorelist : Error< "malformed sanitizer coverage ignorelist: '%0'">; def err_drv_duplicate_config : Error< @@ -195,7 +219,7 @@ def err_target_unsupported_arch def err_cpu_unsupported_isa : Error<"CPU '%0' does not support '%1' execution mode">; def err_arch_unsupported_isa - : Error<"Architecture '%0' does not support '%1' execution mode">; + : Error<"architecture '%0' does not support '%1' execution mode">; def err_drv_I_dash_not_supported : Error< "'%0' not supported, please use -iquote instead">; @@ -220,6 +244,7 @@ def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; def err_drv_invalid_value_with_suggestion : Error< "invalid value '%1' in '%0', expected one of: %2">; +def err_drv_alignment_not_power_of_two : Error<"alignment is not a power of 2 in '%0'">; def err_drv_invalid_remap_file : Error< "invalid option '%0' not of the form ;">; def err_drv_invalid_gcc_output_type : Error< @@ -235,6 +260,7 @@ def warn_invalid_ios_deployment_target : Warning< DefaultError; def err_invalid_macos_32bit_deployment_target : Error< "32-bit targets are not supported when building for Mac Catalyst">; +def err_drv_invalid_os_in_arg : Error<"invalid OS value '%0' in '%1'">; def err_drv_conflicting_deployment_targets : Error< "conflicting deployment targets, both '%0' and '%1' are present in environment">; def err_arc_unsupported_on_runtime : Error< @@ -262,20 +288,26 @@ def err_drv_optimization_remark_format : Error< "unknown remark serializer format: '%0'">; def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">; def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">; +def err_drv_debug_no_new_runtime : Error<"OpenMP target device debugging enabled with incompatible runtime">; def err_drv_incompatible_omp_arch : Error<"OpenMP target architecture '%0' pointer size is incompatible with host '%1'">; def err_drv_omp_host_ir_file_not_found : Error< - "The provided host compiler IR file '%0' is required to generate code for OpenMP target regions but cannot be found.">; + "provided host compiler IR file '%0' is required to generate code for OpenMP " + "target regions but cannot be found">; def err_drv_omp_host_target_not_supported : Error< - "The target '%0' is not a supported OpenMP host target.">; + "target '%0' is not a supported OpenMP host target">; def err_drv_expecting_fopenmp_with_fopenmp_targets : Error< - "The option -fopenmp-targets must be used in conjunction with a -fopenmp option compatible with offloading, please use -fopenmp=libomp or -fopenmp=libiomp5.">; + "'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option " + "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">; def err_drv_omp_offload_target_missingbcruntime : Error< - "No library '%0' found in the default clang lib directory or in LIBRARY_PATH. Please use --libomptarget-%1-bc-path to specify %1 bitcode library.">; -def err_drv_omp_offload_target_bcruntime_not_found : Error<"Bitcode library '%0' does not exist.">; -def err_drv_omp_offload_target_cuda_version_not_support : Error<"NVPTX target requires CUDA 9.2 or above. CUDA %0 is detected.">; + "no library '%0' found in the default clang lib directory or in LIBRARY_PATH" + "; use '--libomptarget-%1-bc-path' to specify %1 bitcode library">; +def err_drv_omp_offload_target_bcruntime_not_found : Error< + "bitcode library '%0' does not exist">; +def err_drv_omp_offload_target_cuda_version_not_support : Error< + "NVPTX target requires CUDA 9.2 or above; CUDA %0 detected">; def warn_drv_omp_offload_target_duplicate : Warning< - "The OpenMP offloading target '%0' is similar to target '%1' already specified - will be ignored.">, - InGroup; + "OpenMP offloading target '%0' is similar to target '%1' already specified; " + "will be ignored">, InGroup; def err_drv_unsupported_embed_bitcode : Error<"%0 is not supported with -fembed-bitcode">; def err_drv_bitcode_unsupported_on_toolchain : Error< @@ -302,7 +334,8 @@ def warn_drv_unsupported_debug_info_opt_for_target : Warning< "debug information option '%0' is not supported for target '%1'">, InGroup; def warn_drv_dwarf_version_limited_by_target : Warning< - "debug information option '%0' is not supported. It needs DWARF-%2 but target '%1' only provides DWARF-%3.">, + "debug information option '%0' is not supported; requires DWARF-%2 but " + "target '%1' only provides DWARF-%3">, InGroup; def warn_c_kext : Warning< "ignoring -fapple-kext which is valid for C++ and Objective-C++ only">; @@ -369,7 +402,7 @@ def err_sls_hardening_arm_not_supported : Error< def note_drv_command_failed_diag_msg : Note< "diagnostic msg: %0">; def note_drv_t_option_is_global : Note< - "The last /TC or /TP option takes precedence over earlier instances">; + "the last '/TC' or '/TP' option takes precedence over earlier instances">; def note_drv_address_sanitizer_debug_runtime : Note< "AddressSanitizer doesn't support linking with debug runtime libraries yet">; def note_drv_use_standard : Note<"use '%0'" @@ -409,7 +442,8 @@ def err_test_module_file_extension_format : Error< def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">, InGroup>; -def note_use_dashdash : Note<"Use '--' to treat subsequent arguments as filenames">; +def note_use_dashdash : Note< + "use '--' to treat subsequent arguments as filenames">; def err_drv_ropi_rwpi_incompatible_with_pic : Error< "embedded and GOT-based position independence are incompatible">; @@ -478,14 +512,14 @@ def warn_drv_ps4_sdk_dir : Warning< def err_drv_unsupported_linker : Error<"unsupported value '%0' for -linker option">; def err_drv_defsym_invalid_format : Error<"defsym must be of the form: sym=value: %0">; -def err_drv_defsym_invalid_symval : Error<"Value is not an integer: %0">; +def err_drv_defsym_invalid_symval : Error<"value is not an integer: %0">; def warn_drv_msvc_not_found : Warning< "unable to find a Visual Studio installation; " "try running Clang from a developer command prompt">, InGroup>; def warn_drv_fuse_ld_path : Warning< - "'-fuse-ld=' taking a path is deprecated. Use '--ld-path=' instead">, + "'-fuse-ld=' taking a path is deprecated; use '--ld-path=' instead">, InGroup, DefaultIgnore; def warn_drv_fine_grained_bitfield_accesses_ignored : Warning< @@ -505,11 +539,11 @@ def warn_drv_global_isel_incomplete_opt : Warning< InGroup; def warn_drv_moutline_unsupported_opt : Warning< - "The '%0' architecture does not support -moutline; flag ignored">, + "'%0' does not support '-moutline'; flag ignored">, InGroup; def warn_drv_moutline_atomics_unsupported_opt : Warning< - "The '%0' architecture does not support -moutline-atomics; flag ignored">, + "'%0' does not support '-moutline-atomics'; flag ignored">, InGroup; def warn_drv_darwin_sdk_invalid_settings : Warning< @@ -517,25 +551,28 @@ def warn_drv_darwin_sdk_invalid_settings : Warning< InGroup>; def err_drv_trivial_auto_var_init_zero_disabled : Error< - "-ftrivial-auto-var-init=zero hasn't been enabled. Enable it at your own peril for benchmarking purpose only with " - "-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang">; + "'-ftrivial-auto-var-init=zero' hasn't been enabled; enable it at your own " + "peril for benchmarking purpose only with " + "'-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang'">; def err_drv_trivial_auto_var_init_stop_after_missing_dependency : Error< - "-ftrivial-auto-var-init-stop-after=* is used without -ftrivial-auto-var-init=zero or -ftrivial-auto-var-init=pattern.">; + "'-ftrivial-auto-var-init-stop-after=*' is used without " + "'-ftrivial-auto-var-init=zero' or '-ftrivial-auto-var-init=pattern'">; def err_drv_trivial_auto_var_init_stop_after_invalid_value : Error< - "-ftrivial-auto-var-init-stop-after=* only accepts positive integers.">; + "'-ftrivial-auto-var-init-stop-after=*' only accepts positive integers">; -def warn_drv_msp430_hwmult_unsupported : Warning<"the given MCU does not " - "support hardware multiply, but -mhwmult is set to %0.">, +def warn_drv_msp430_hwmult_unsupported : Warning< + "the given MCU does not support hardware multiply, but '-mhwmult' is set to " + "%0">, InGroup; +def warn_drv_msp430_hwmult_mismatch : Warning< + "the given MCU supports %0 hardware multiply, but '-mhwmult' is set to %1">, InGroup; -def warn_drv_msp430_hwmult_mismatch : Warning<"the given MCU supports %0 " - "hardware multiply, but -mhwmult is set to %1.">, - InGroup; -def warn_drv_msp430_hwmult_no_device : Warning<"no MCU device specified, but " - "'-mhwmult' is set to 'auto', assuming no hardware multiply. Use -mmcu to " - "specify a MSP430 device, or -mhwmult to set hardware multiply type " - "explicitly.">, InGroup; +def warn_drv_msp430_hwmult_no_device : Warning< + "no MCU device specified, but '-mhwmult' is set to 'auto', assuming no " + "hardware multiply; use '-mmcu' to specify an MSP430 device, or '-mhwmult' " + "to set the hardware multiply type explicitly">, + InGroup; def warn_drv_libstdcxx_not_found : Warning< "include path for libstdc++ headers not found; pass '-stdlib=libc++' on the " @@ -544,17 +581,26 @@ def warn_drv_libstdcxx_not_found : Warning< def err_drv_cannot_mix_options : Error<"cannot specify '%1' along with '%0'">; -def err_drv_invalid_object_mode : Error<"OBJECT_MODE setting %0 is not recognized and is not a valid setting.">; +def err_drv_invalid_object_mode : Error< + "OBJECT_MODE setting %0 is not recognized and is not a valid setting">; def err_aix_unsupported_tls_model : Error<"TLS model '%0' is not yet supported on AIX">; -def err_invalid_cxx_abi : Error<"Invalid C++ ABI name '%0'">; +def err_invalid_cxx_abi : Error<"invalid C++ ABI name '%0'">; def err_unsupported_cxx_abi : Error<"C++ ABI '%0' is not supported on target triple '%1'">; -def note_cc1_round_trip_original : Note<"Original arguments in round-trip: %0">; -def note_cc1_round_trip_generated : Note<"Generated arguments #%0 in round-trip: %1">; -def remark_cc1_round_trip_generated : Remark<"Generated arguments #%0 in round-trip: %1">, InGroup; -def err_cc1_round_trip_fail_then_ok : Error<"Original arguments parse failed, then succeeded in round-trip">; -def err_cc1_round_trip_ok_then_fail : Error<"Generated arguments parse failed in round-trip">; -def err_cc1_round_trip_mismatch : Error<"Generated arguments do not match in round-trip">; +def note_cc1_round_trip_original : Note<"original arguments in round-trip: %0">; +def note_cc1_round_trip_generated : Note< + "generated arguments #%0 in round-trip: %1">; +def remark_cc1_round_trip_generated : Remark< + "generated arguments #%0 in round-trip: %1">, InGroup; +def err_cc1_round_trip_fail_then_ok : Error< + "original arguments parse failed, then succeeded in round-trip">; +def err_cc1_round_trip_ok_then_fail : Error< + "generated arguments parse failed in round-trip">; +def err_cc1_round_trip_mismatch : Error< + "generated arguments do not match in round-trip">; + +def err_drv_ssp_missing_offset_argument : Error< + "'%0' is used without '-mstack-protector-guard-offset', and there is no default">; } diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 0f4ccec3855..eacb7e4de0e 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -22,10 +22,11 @@ def note_fe_inline_asm_here : Note<"instantiated into assembly here">; def err_fe_source_mgr : Error<"%0">, CatSourceMgr; def warn_fe_source_mgr : Warning<"%0">, CatSourceMgr, InGroup; def note_fe_source_mgr : Note<"%0">, CatSourceMgr; -def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">, - DefaultFatal; +def err_fe_linking_module : Error<"cannot link module '%0': %1">, DefaultFatal; +def warn_fe_linking_module : Warning<"linking module '%0': %1">, InGroup; +def note_fe_linking_module : Note<"linking module '%0': %1">; -def warn_fe_frame_larger_than : Warning<"stack frame size (%0) exceeds limit (%1) in %q2">, +def warn_fe_frame_larger_than : Warning<"stack frame size (%0) exceeds limit (%1) in '%2'">, BackendInfo, InGroup; def warn_fe_backend_frame_larger_than: Warning<"%0">, BackendInfo, InGroup; @@ -72,6 +73,12 @@ def note_fe_backend_invalid_loc : Note<"could " def err_fe_backend_unsupported : Error<"%0">, BackendInfo; def warn_fe_backend_unsupported : Warning<"%0">, BackendInfo; +def err_fe_backend_error_attr : + Error<"call to %0 declared with 'error' attribute: %1">, BackendInfo; +def warn_fe_backend_warning_attr : + Warning<"call to %0 declared with 'warning' attribute: %1">, BackendInfo, + InGroup; + def err_fe_invalid_code_complete_file : Error< "cannot locate code-completion file %0">, DefaultFatal; def err_fe_dependency_file_requires_MT : Error< @@ -229,6 +236,8 @@ def remark_module_build : Remark<"building module '%0' as '%1'">, InGroup; def remark_module_build_done : Remark<"finished building module '%0'">, InGroup; +def remark_module_lock : Remark<"locking '%0' to build module '%1'">, + InGroup; def err_modules_embed_file_not_found : Error<"file '%0' specified by '-fmodules-embed-file=' not found">, DefaultFatal; @@ -245,7 +254,7 @@ def err_invalid_vfs_overlay : Error< "invalid virtual filesystem overlay file '%0'">, DefaultFatal; def warn_option_invalid_ocl_version : Warning< - "OpenCL version %0 does not support the option '%1'">, InGroup; + "%0 does not support the option '%1'">, InGroup; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; def err_function_needs_feature : Error< diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 4b4928a7a00..85d373845c8 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -54,7 +54,9 @@ def CompoundTokenSplit : DiagGroup<"compound-token-split", CompoundTokenSplitBySpace]>; def CoroutineMissingUnhandledException : DiagGroup<"coroutine-missing-unhandled-exception">; -def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException]>; +def DeprecatedExperimentalCoroutine : + DiagGroup<"deprecated-experimental-coroutine">; +def Coroutine : DiagGroup<"coroutine", [CoroutineMissingUnhandledException, DeprecatedExperimentalCoroutine]>; def ObjCBoolConstantConversion : DiagGroup<"objc-bool-constant-conversion">; def ConstantConversion : DiagGroup<"constant-conversion", [BitFieldConstantConversion, @@ -64,6 +66,8 @@ def StringConversion : DiagGroup<"string-conversion">; def SignConversion : DiagGroup<"sign-conversion">; def PointerBoolConversion : DiagGroup<"pointer-bool-conversion">; def UndefinedBoolConversion : DiagGroup<"undefined-bool-conversion">; +def BitwiseInsteadOfLogical : DiagGroup<"bitwise-instead-of-logical">; +def BoolOperation : DiagGroup<"bool-operation", [BitwiseInsteadOfLogical]>; def BoolConversion : DiagGroup<"bool-conversion", [PointerBoolConversion, UndefinedBoolConversion]>; def IntConversion : DiagGroup<"int-conversion">; @@ -184,6 +188,7 @@ def DeprecatedThisCapture : DiagGroup<"deprecated-this-capture">; def DeprecatedVolatile : DiagGroup<"deprecated-volatile">; def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings", [CXX11CompatDeprecatedWritableStr]>; +def DeprecatedPragma : DiagGroup<"deprecated-pragma">; // FIXME: Why is DeprecatedImplementations not in this group? def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion, DeprecatedArrayCompare, @@ -198,6 +203,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion, DeprecatedEnumEnumConversion, DeprecatedEnumFloatConversion, DeprecatedIncrementBool, + DeprecatedPragma, DeprecatedRegister, DeprecatedThisCapture, DeprecatedVolatile, @@ -393,6 +399,7 @@ def Dangling : DiagGroup<"dangling", [DanglingField, DanglingGsl, ReturnStackAddress]>; def DistributedObjectModifiers : DiagGroup<"distributed-object-modifiers">; +def DllexportExplicitInstantiationDecl : DiagGroup<"dllexport-explicit-instantiation-decl">; def ExcessInitializers : DiagGroup<"excess-initializers">; def ExpansionToDefined : DiagGroup<"expansion-to-defined">; def FlagEnum : DiagGroup<"flag-enum">; @@ -400,7 +407,8 @@ def IncrementBool : DiagGroup<"increment-bool", [DeprecatedIncrementBool]>; def InfiniteRecursion : DiagGroup<"infinite-recursion">; def PureVirtualCallFromCtorDtor: DiagGroup<"call-to-pure-virtual-from-ctor-dtor">; def GNUImaginaryConstant : DiagGroup<"gnu-imaginary-constant">; -def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; +def IgnoredReferenceQualifiers : DiagGroup<"ignored-reference-qualifiers">; +def IgnoredQualifiers : DiagGroup<"ignored-qualifiers", [IgnoredReferenceQualifiers]>; def : DiagGroup<"import">; def GNUIncludeNext : DiagGroup<"gnu-include-next">; def IncompatibleMSStruct : DiagGroup<"incompatible-ms-struct">; @@ -462,6 +470,7 @@ def MismatchedParameterTypes : DiagGroup<"mismatched-parameter-types">; def MismatchedReturnTypes : DiagGroup<"mismatched-return-types">; def MismatchedTags : DiagGroup<"mismatched-tags">; def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def ModuleLock : DiagGroup<"module-lock">; def ModuleBuild : DiagGroup<"module-build">; def ModuleImport : DiagGroup<"module-import">; def ModuleConflict : DiagGroup<"module-conflict">; @@ -642,6 +651,8 @@ def AmbiguousMacro : DiagGroup<"ambiguous-macro">; def KeywordAsMacro : DiagGroup<"keyword-macro">; def ReservedIdAsMacro : DiagGroup<"reserved-macro-identifier">; def ReservedIdAsMacroAlias : DiagGroup<"reserved-id-macro", [ReservedIdAsMacro]>; +def RestrictExpansionMacro : DiagGroup<"restrict-expansion">; +def FinalMacro : DiagGroup<"final-macro">; // Just silence warnings about -Wstrict-aliasing for now. def : DiagGroup<"strict-aliasing=0">; @@ -742,6 +753,7 @@ def UnusedLocalTypedef : DiagGroup<"unused-local-typedef">; def UnusedPropertyIvar : DiagGroup<"unused-property-ivar">; def UnusedGetterReturnValue : DiagGroup<"unused-getter-return-value">; def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; +def UsedSearchPath : DiagGroup<"search-path-usage">; def UserDefinedLiterals : DiagGroup<"user-defined-literals">; def UserDefinedWarnings : DiagGroup<"user-defined-warnings">; def ReorderCtor : DiagGroup<"reorder-ctor">; @@ -816,8 +828,10 @@ def ReservedIdentifier : DiagGroup<"reserved-identifier", // under separate flags. // def UnreachableCodeLoopIncrement : DiagGroup<"unreachable-code-loop-increment">; +def UnreachableCodeFallthrough : DiagGroup<"unreachable-code-fallthrough">; def UnreachableCode : DiagGroup<"unreachable-code", - [UnreachableCodeLoopIncrement]>; + [UnreachableCodeLoopIncrement, + UnreachableCodeFallthrough]>; def UnreachableCodeBreak : DiagGroup<"unreachable-code-break">; def UnreachableCodeReturn : DiagGroup<"unreachable-code-return">; def UnreachableCodeAggressive : DiagGroup<"unreachable-code-aggressive", @@ -940,6 +954,7 @@ def Extra : DiagGroup<"extra", [ ]>; def Most : DiagGroup<"most", [ + BoolOperation, CharSubscript, Comment, DeleteNonVirtualDtor, @@ -1185,6 +1200,9 @@ def ASM : DiagGroup<"asm", [ ASMOperandWidths ]>; +// Linker warnings. +def LinkerWarnings : DiagGroup<"linker-warnings">; + // OpenMP warnings. def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">; def OpenMPClauses : DiagGroup<"openmp-clauses">; @@ -1210,6 +1228,7 @@ def BackendOptimizationRemark : DiagGroup<"pass">; def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">; def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; def BackendOptimizationFailure : DiagGroup<"pass-failed">; +def BackendWarningAttributes : DiagGroup<"attribute-warning">; // Instrumentation based profiling warnings. def ProfileInstrMissing : DiagGroup<"profile-instr-missing">; @@ -1247,8 +1266,9 @@ def OptionIgnored : DiagGroup<"option-ignored">; def UnknownArgument : DiagGroup<"unknown-argument">; // A warning group for warnings about code that clang accepts when -// compiling OpenCL C/C++ but which is not compatible with the SPIR spec. +// compiling OpenCL C/C++ but which is not compatible with the SPIR(-V) spec. def SpirCompat : DiagGroup<"spir-compat">; +def : DiagGroup<"spirv-compat", [SpirCompat]>; // Alias. // Warning for the GlobalISel options. def GlobalISel : DiagGroup<"global-isel">; @@ -1303,3 +1323,11 @@ def WebAssemblyExceptionSpec : DiagGroup<"wasm-exception-spec">; def RTTI : DiagGroup<"rtti">; def OpenCLCoreFeaturesDiagGroup : DiagGroup<"pedantic-core-features">; + +// Warnings and extensions to make preprocessor macro usage pedantic. +def PedanticMacros : DiagGroup<"pedantic-macros", + [DeprecatedPragma, + MacroRedefined, + BuiltinMacroRedefined, + RestrictExpansionMacro, + FinalMacro]>; diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index 288504def5e..aef86516707 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -25,6 +25,8 @@ namespace clang { // Import the diagnostic enums themselves. namespace diag { + enum class Group; + // Size of each of the diagnostic categories. enum { DIAG_SIZE_COMMON = 300, @@ -224,6 +226,10 @@ public: /// static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); + /// Given a group ID, returns the flag that toggles the group. + /// For example, for Group::DeprecatedDeclarations, returns + /// "deprecated-declarations". + static StringRef getWarningOptionForGroup(diag::Group); /// Return the lowest-level warning option that enables the specified /// diagnostic. diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index ce6d0d0394b..a4436208799 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -113,8 +113,10 @@ def warn_four_char_character_literal : Warning< // Unicode and UCNs def err_invalid_utf8 : Error< "source file is not valid UTF-8">; -def err_non_ascii : Error< - "non-ASCII characters are not allowed outside of literals and identifiers">; +def err_character_not_allowed : Error< + "unexpected character ">; +def err_character_not_allowed_identifier : Error< + "character not allowed %select{in|at the start of}1 an identifier">; def ext_unicode_whitespace : ExtWarn< "treating Unicode character as whitespace">, InGroup>; @@ -125,6 +127,15 @@ def warn_utf8_symbol_zero_width : Warning< "identifier contains Unicode character that is invisible in " "some environments">, InGroup>; +def ext_delimited_escape_sequence : Extension< + "delimited escape sequences are a Clang extension">, + InGroup>; +def err_delimited_escape_empty : Error< + "delimited escape sequence cannot be empty">; +def err_delimited_escape_missing_brace: Error< + "expected '{' after '\\%0' escape sequence">; +def err_delimited_escape_invalid : Error< + "invalid digit '%0' in escape sequence">; def err_hex_escape_no_digits : Error< "\\%0 used with no following hex digits">; def warn_ucn_escape_no_digits : Warning< @@ -132,6 +143,12 @@ def warn_ucn_escape_no_digits : Warning< "treating as '\\' followed by identifier">, InGroup; def err_ucn_escape_incomplete : Error< "incomplete universal character name">; +def warn_delimited_ucn_incomplete : Warning< + "incomplete delimited universal character name; " + "treating as '\\' 'u' '{' identifier">, InGroup; +def warn_delimited_ucn_empty : Warning< + "empty delimited universal character name; " + "treating as '\\' 'u' '{' '}'">, InGroup; def warn_ucn_escape_incomplete : Warning< "incomplete universal character name; " "treating as '\\' followed by identifier">, InGroup; @@ -150,9 +167,6 @@ def warn_c99_compat_unicode_id : Warning< "%select{using this character in an identifier|starting an identifier with " "this character}0 is incompatible with C99">, InGroup, DefaultIgnore; -def warn_cxx98_compat_unicode_id : Warning< - "using this character in an identifier is incompatible with C++98">, - InGroup, DefaultIgnore; def warn_cxx98_compat_literal_ucn_escape_basic_scs : Warning< "specifying character '%0' with a universal character name " @@ -184,12 +198,10 @@ def warn_c2x_compat_digit_separator : Warning< InGroup, DefaultIgnore; def err_digit_separator_not_between_digits : Error< "digit separator cannot appear at %select{start|end}0 of digit sequence">; -def warn_extraneous_char_constant : Warning< - "extraneous characters in character constant ignored">; def warn_char_constant_too_large : Warning< "character constant too long for its type">; -def err_multichar_utf_character_literal : Error< - "Unicode character literals may not contain multiple characters">; +def err_multichar_character_literal : Error< + "%select{wide|Unicode}0 character literals may not contain multiple characters">; def err_exponent_has_no_digits : Error<"exponent has no digits">; def err_hex_constant_requires : Error< "hexadecimal floating %select{constant|literal}0 requires " @@ -257,7 +269,9 @@ def err_bad_character_encoding : Error< def warn_bad_character_encoding : ExtWarn< "illegal character encoding in character literal">, InGroup; -def err_lexing_string : Error<"failure when lexing a string">; +def err_lexing_string : Error<"failure when lexing a string literal">; +def err_lexing_char : Error<"failure when lexing a character literal">; +def err_lexing_numeric : Error<"failure when lexing a numeric literal">; def err_placeholder_in_source : Error<"editor placeholder in source file">; //===----------------------------------------------------------------------===// @@ -300,6 +314,13 @@ def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">, def pp_pragma_sysheader_in_main_file : Warning< "#pragma system_header ignored in main file">, InGroup>; + +def err_pragma_include_instead_not_sysheader : Error< + "'#pragma clang include_instead' cannot be used outside of system headers">; +def err_pragma_include_instead_system_reserved : Error< + "header '%0' is an implementation detail; #include %select{'%2'|either '%2' " + "or '%3'|one of %2}1 instead">; + def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; def pp_out_of_date_dependency : Warning< "current file is older than dependency %0">; @@ -393,6 +414,10 @@ def ext_embedded_directive : Extension< def ext_missing_varargs_arg : Extension< "must specify at least one argument for '...' parameter of variadic macro">, InGroup; +def warn_cxx17_compat_missing_varargs_arg : Warning< + "passing no argument for the '...' parameter of a variadic macro is " + "incompatible with C++ standards before C++20">, + InGroup, DefaultIgnore; def ext_empty_fnmacro_arg : Extension< "empty macro arguments are a C99 feature">, InGroup; def warn_cxx98_compat_empty_fnmacro_arg : Warning< @@ -423,6 +448,9 @@ def warn_pp_hdrstop_filename_ignored : Warning< "#pragma hdrstop filename not supported, " "/Fp can be used to specify precompiled header filename">, InGroup; +def remark_pp_search_path_usage : Remark< + "search path used: '%0'">, + InGroup; def err_pp_file_not_found_angled_include_not_fatal : Error< "'%0' file not found with %select{include|import}1; " "use \"quotes\" instead">; @@ -519,6 +547,27 @@ def warn_pragma_warning_expected_number : ExtWarn<"#pragma warning expected a warning number">, InGroup; +// - #pragma deprecated(...) +def warn_pragma_deprecated_macro_use : + ExtWarn<"macro %0 has been marked as deprecated%select{|: %2}1">, + InGroup; + +// - #pragma clang restrict_expansion(...) +def warn_pragma_restrict_expansion_macro_use : + ExtWarn<"macro %0 has been marked as unsafe for use in headers" + "%select{|: %2}1">, + InGroup; + +// - Note for macro annotations. +def note_pp_macro_annotation : + Note<"macro marked '%select{deprecated|restrict_expansion|final}0' here">; + +// - #pragma clang final(...) +def warn_pragma_final_macro : + ExtWarn<"macro %0 has been marked as final and should not be " + "%select{undefined|redefined}1">, + InGroup, ShowInSystemHeader; + // - #pragma execution_character_set(...) def warn_pragma_exec_charset_expected : ExtWarn<"#pragma execution_character_set expected '%0'">, diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 7e4b0841e06..1bc2e8b0c7e 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -549,6 +549,12 @@ def err_expected_init_in_condition_lparen : Error< "variable declaration in condition cannot have a parenthesized initializer">; def err_extraneous_rparen_in_condition : Error< "extraneous ')' after condition, expected a statement">; +def ext_alias_in_init_statement : ExtWarn< + "alias declaration in this context is a C++2b extension">, + InGroup; +def warn_cxx20_alias_in_init_statement : Warning< + "alias declaration in this context is incompatible with C++ standards before C++2b">, + DefaultIgnore, InGroup; def warn_dangling_else : Warning< "add explicit braces to avoid dangling else">, InGroup; @@ -626,6 +632,13 @@ def ext_constexpr_if : ExtWarn< def warn_cxx14_compat_constexpr_if : Warning< "constexpr if is incompatible with C++ standards before C++17">, DefaultIgnore, InGroup; +def ext_consteval_if : ExtWarn< + "consteval if is a C++2b extension">, + InGroup; +def warn_cxx20_compat_consteval_if : Warning< + "consteval if is incompatible with C++ standards before C++2b">, + InGroup, DefaultIgnore; + def ext_init_statement : ExtWarn< "'%select{if|switch}0' initialization statements are a C++17 extension">, InGroup; @@ -742,8 +755,9 @@ def err_unknown_template_name : Error< "unknown template name %0">; def err_expected_comma_greater : Error< "expected ',' or '>' in template-parameter-list">; -def err_class_on_template_template_param : Error< - "template template parameter requires 'class' after the parameter list">; +def err_class_on_template_template_param + : Error<"template template parameter requires 'class'%select{| or " + "'typename'}0 after the parameter list">; def ext_template_template_param_typename : ExtWarn< "template template parameter using 'typename' is a C++17 extension">, InGroup; @@ -806,10 +820,10 @@ def err_requires_expr_expected_type_constraint : Error< def err_requires_expr_simple_requirement_noexcept : Error< "'noexcept' can only be used in a compound requirement (with '{' '}' around " "the expression)">; -def warn_requires_expr_in_simple_requirement : Warning< - "this requires expression will only be checked for syntactic validity; did " +def err_requires_expr_in_simple_requirement : Error< + "requires expression in requirement body; did " "you intend to place it in a nested requirement? (add another 'requires' " - "before the expression)">, InGroup>; + "before the expression)">; def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; @@ -944,6 +958,9 @@ def err_duplicate_class_virt_specifier : Error< def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; +def err_virt_specifier_outside_class : Error< + "'%0' specifier is not allowed outside a class definition">; + def err_expected_parameter_pack : Error< "expected the name of a parameter pack">; def err_paren_sizeof_parameter_pack : Error< @@ -1102,6 +1119,9 @@ def warn_pragma_expected_integer : Warning< def warn_pragma_ms_struct : Warning< "incorrect use of '#pragma ms_struct on|off' - ignored">, InGroup; +def warn_pragma_ms_fenv_access : Warning< + "incorrect use of '#pragma fenv_access (on|off)' - ignored">, + InGroup; def warn_pragma_extra_tokens_at_eol : Warning< "extra tokens at end of '#pragma %0' - ignored">, InGroup; @@ -1167,9 +1187,6 @@ def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, // The C standard 7.6.1p2 says "The [FENV_ACCESS] pragma shall occur either // outside external declarations or preceding all explicit declarations and // statements inside a compound statement. -def err_pragma_stdc_fenv_access_scope : Error< - "'#pragma STDC FENV_ACCESS' can only appear at file scope or at the start of" - " a compound statement">; def warn_stdc_fenv_round_not_supported : Warning<"pragma STDC FENV_ROUND is not supported">, InGroup; @@ -1303,8 +1320,8 @@ def err_omp_decl_in_declare_simd_variant : Error< def err_omp_unknown_map_type : Error< "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; def err_omp_unknown_map_type_modifier : Error< - "incorrect map type modifier, expected 'always', 'close', " - "%select{or 'mapper'|'mapper', or 'present'}0">; + "incorrect map type modifier, expected one of: 'always', 'close', 'mapper'" + "%select{|, 'present'}0%select{|, 'ompx_hold'}1">; def err_omp_map_type_missing : Error< "missing map type">; def err_omp_map_type_modifier_missing : Error< @@ -1342,8 +1359,11 @@ def err_omp_mapper_illegal_identifier : Error< "illegal OpenMP user-defined mapper identifier">; def err_omp_mapper_expected_declarator : Error< "expected declarator on 'omp declare mapper' directive">; +def err_omp_unexpected_append_op : Error< + "unexpected operation specified in 'append_args' clause, expected 'interop'">; def err_omp_declare_variant_wrong_clause : Error< - "expected '%0' clause on 'omp declare variant' directive">; + "expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause " + "on 'omp declare variant' directive">; def err_omp_declare_variant_duplicate_nested_trait : Error< "nested OpenMP context selector contains duplicated trait '%0'" " in selector '%1' and set '%2' with different score">; @@ -1436,6 +1456,9 @@ def warn_omp51_compat_attributes : Warning< "specifying OpenMP directives with [[]] is incompatible with OpenMP " "standards before OpenMP 5.1">, InGroup, DefaultIgnore; +def err_omp_expected_colon : Error<"missing ':' in %0">; +def err_omp_expected_context_selector + : Error<"expected valid context selector in %0">; // Pragma loop support. def err_pragma_loop_missing_argument : Error< @@ -1472,7 +1495,7 @@ def warn_pragma_unroll_cuda_value_in_parens : Warning< InGroup; def warn_cuda_attr_lambda_position : Warning< - "nvcc does not allow '__%0__' to appear after '()' in lambdas">, + "nvcc does not allow '__%0__' to appear after the parameter list in lambdas">, InGroup; def warn_pragma_force_cuda_host_device_bad_arg : Warning< "incorrect use of #pragma clang force_cuda_host_device begin|end">, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 108f1796415..dc67f86f25c 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -66,6 +66,7 @@ def warn_infinite_recursive_function : Warning< def warn_comma_operator : Warning<"possible misuse of comma operator here">, InGroup>, DefaultIgnore; def note_cast_to_void : Note<"cast expression to void to silence warning">; +def note_cast_operand_to_int : Note<"cast one or both operands to int to silence this warning">; // Constant expressions def err_expr_not_ice : Error< @@ -82,11 +83,11 @@ def err_typecheck_converted_constant_expression_indirect : Error< "bind reference to a temporary">; def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|" - "array size|explicit specifier argument}0 " + "array size|explicit specifier argument|noexcept specifier argument}0 " "is not a constant expression">; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|" - "array size|explicit specifier argument}0 " + "array size|explicit specifier argument|noexcept specifier argument}0 " "%select{cannot be narrowed from type %2 to %3|" "evaluates to %2, which cannot be narrowed to type %3}1">, InGroup, DefaultError, SFINAEFailure; @@ -267,10 +268,12 @@ def err_invalid_vector_double_decl_spec : Error < def err_invalid_vector_bool_int128_decl_spec : Error < "use of '__int128' with '__vector bool' requires VSX support enabled (on " "POWER10 or later)">; +def err_invalid_vector_int128_decl_spec : Error< + "use of '__int128' with '__vector' requires extended Altivec support" + " (available on POWER8 or later)">; def err_invalid_vector_long_long_decl_spec : Error < - "use of 'long long' with '__vector bool' requires VSX support (available on " - "POWER7 or later) or extended Altivec support (available on POWER8 or later) " - "to be enabled">; + "use of 'long long' with '__vector' requires VSX support (available on " + "POWER7 or later) to be enabled">; def err_invalid_vector_long_double_decl_spec : Error< "cannot use 'long double' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< @@ -388,6 +391,7 @@ def warn_reserved_extern_symbol: Warning< "identifier %0 is reserved because %select{" "|" // ReservedIdentifierStatus::NotReserved "it starts with '_' at global scope|" + "it starts with '_' and has C language linkage|" "it starts with '__'|" "it starts with '_' followed by a capital letter|" "it contains '__'}1">, @@ -682,6 +686,9 @@ def warn_unreachable_return : Warning< def warn_unreachable_loop_increment : Warning< "loop will run at most once (loop increment never executed)">, InGroup, DefaultIgnore; +def warn_unreachable_fallthrough_attr : Warning< + "fallthrough annotation in unreachable code">, + InGroup, DefaultIgnore; def note_unreachable_silence : Note< "silence by adding parentheses to mark code as explicitly dead">; @@ -816,11 +823,20 @@ def warn_fortify_source_size_mismatch : Warning< "'%0' size argument is too large; destination buffer has size %1," " but size argument is %2">, InGroup; +def warn_fortify_strlen_overflow: Warning< + "'%0' will always overflow; destination buffer has size %1," + " but the source string has length %2 (including NUL byte)">, + InGroup; + def warn_fortify_source_format_overflow : Warning< "'%0' will always overflow; destination buffer has size %1," " but format string expands to at least %2">, InGroup; +def warn_fortify_scanf_overflow : Warning< + "'%0' may overflow; destination buffer in argument %1 has size " + "%2, but the corresponding specifier may require size %3">, + InGroup; /// main() // static main() is not an error in C, just in C++. @@ -908,6 +924,9 @@ def warn_pragma_options_align_reset_failed : Warning< InGroup; def err_pragma_options_align_mac68k_target_unsupported : Error< "mac68k alignment pragma is not supported on this target">; +def warn_pragma_align_not_xl_compatible : Warning< + "#pragma align(packed) may not be compatible with objects generated with AIX XL C/C++">, + InGroup; def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, InGroup; @@ -933,7 +952,8 @@ def warn_pragma_pack_pop_identifier_and_alignment : Warning< def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, InGroup; def err_pragma_fc_pp_scope : Error< - "'#pragma float_control push/pop' can only appear at file scope or namespace scope">; + "'#pragma float_control push/pop' can only appear at file or namespace scope " + "or within a language linkage specification">; def err_pragma_fc_noprecise_requires_nofenv : Error< "'#pragma float_control(precise, off)' is illegal when fenv_access is enabled">; def err_pragma_fc_except_requires_precise : Error< @@ -1493,6 +1513,10 @@ def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; def err_static_assert_requirement_failed : Error< "static_assert failed due to requirement '%0'%select{ %2|}1">; +def warn_consteval_if_always_true : Warning< + "consteval if is always true in an %select{unevaluated|immediate}0 context">, + InGroup>; + def ext_inline_variable : ExtWarn< "inline variables are a C++17 extension">, InGroup; def warn_cxx14_compat_inline_variable : Warning< @@ -1624,8 +1648,7 @@ def warn_weak_vtable : Warning< "emitted in every translation unit">, InGroup>, DefaultIgnore; def warn_weak_template_vtable : Warning< - "explicit template instantiation %0 will emit a vtable in every " - "translation unit">, + "this warning is no longer in use and will be removed in the next release">, InGroup>, DefaultIgnore; def ext_using_undefined_std : ExtWarn< @@ -2953,7 +2976,7 @@ def err_attribute_requires_positive_integer : Error< "%0 attribute requires a %select{positive|non-negative}1 " "integral compile time constant expression">; def err_attribute_requires_opencl_version : Error< - "%0 attribute requires OpenCL version %1%select{| or above}2">; + "attribute %0 is supported in the OpenCL version %1%select{| onwards}2">; def err_invalid_branch_protection_spec : Error< "invalid or misplaced branch protection specification '%0'">; def warn_unsupported_target_attribute @@ -2980,6 +3003,8 @@ def err_alignas_mismatch : Error< "redeclaration has different alignment requirement (%1 vs %0)">; def err_alignas_underaligned : Error< "requested alignment is less than minimum alignment of %1 for type %0">; +def warn_aligned_attr_underaligned : Warning, + InGroup; def err_attribute_sizeless_type : Error< "%0 attribute cannot be applied to sizeless type %1">; def err_attribute_argument_n_type : Error< @@ -3256,7 +3281,8 @@ def warn_assume_aligned_too_great InGroup>; def warn_not_xl_compatible : Warning<"requesting an alignment of 16 bytes or greater for struct" - " members is not binary compatible with AIX XL 16.1 and older">, + " members is not binary compatible with IBM XL C/C++ for AIX" + " 16.1.0 and older">, InGroup; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "%q0 redeclared without %1 attribute: previous %1 ignored">, @@ -3298,11 +3324,11 @@ def warn_attribute_has_no_effect_on_infinite_loop : Warning< InGroup; def note_attribute_has_no_effect_on_infinite_loop_here : Note< "annotating the infinite loop here">; -def warn_attribute_has_no_effect_on_if_constexpr : Warning< - "attribute %0 has no effect when annotating an 'if constexpr' statement">, +def warn_attribute_has_no_effect_on_compile_time_if : Warning< + "attribute %0 has no effect when annotating an 'if %select{constexpr|consteval}1' statement">, InGroup; -def note_attribute_has_no_effect_on_if_constexpr_here : Note< - "annotating the 'if constexpr' statement here">; +def note_attribute_has_no_effect_on_compile_time_if_here : Note< + "annotating the 'if %select{constexpr|consteval}0' statement here">; def err_decl_attribute_invalid_on_stmt : Error< "%0 attribute cannot be applied to a statement">; def err_stmt_attribute_invalid_on_decl : Error< @@ -3382,7 +3408,7 @@ def warn_attribute_dllimport_static_field_definition : Warning< InGroup>; def warn_attribute_dllexport_explicit_instantiation_decl : Warning< "explicit instantiation declaration should not be 'dllexport'">, - InGroup>; + InGroup; def warn_attribute_dllexport_explicit_instantiation_def : Warning< "'dllexport' attribute ignored on explicit instantiation definition">, InGroup; @@ -3532,6 +3558,9 @@ def warn_availability_swift_unavailable_deprecated_only : Warning< InGroup; def note_protocol_method : Note< "protocol method is here">; +def warn_availability_fuchsia_unavailable_minor : Warning< + "Fuchsia API Level prohibits specifying a minor or sub-minor version">, + InGroup; def warn_unguarded_availability : Warning<"%0 is only available on %1 %2 or newer">, @@ -4472,7 +4501,8 @@ def note_ovl_candidate_bad_conv_incomplete : Note< "; remove &}7">; def note_ovl_candidate_bad_list_argument : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " - "cannot convert initializer list argument to %4">; + "%select{cannot convert initializer list|too few initializers in list" + "|too many initializers in list}7 argument to %4">; def note_ovl_candidate_bad_overload : Note< "candidate %sub{select_ovl_candidate_kind}0,1,2 not viable: " "no overload of %4 matching %3 for %ordinal5 argument">; @@ -5563,8 +5593,8 @@ def warn_undefined_inline : Warning<"inline function %q0 is not defined">, def err_undefined_inline_var : Error<"inline variable %q0 is not defined">; def note_used_here : Note<"used here">; -def err_internal_linkage_redeclaration : Error< - "'internal_linkage' attribute does not appear on the first declaration of %0">; +def err_attribute_missing_on_first_decl : Error< + "%0 attribute does not appear on the first declaration">; def warn_internal_linkage_local_storage : Warning< "'internal_linkage' attribute on a non-static local variable is ignored">, InGroup; @@ -5727,7 +5757,7 @@ def warn_typecheck_function_qualifiers_unspecified : Warning< "'%0' qualifier on function type %1 has unspecified behavior">; def warn_typecheck_reference_qualifiers : Warning< "'%0' qualifier on reference type %1 has no effect">, - InGroup; + InGroup; def err_typecheck_invalid_restrict_not_pointer : Error< "restrict requires a pointer or reference (%0 is invalid)">; def err_typecheck_invalid_restrict_not_pointer_noarg : Error< @@ -5926,6 +5956,8 @@ def note_protected_by_vla_type_alias : Note< "jump bypasses initialization of VLA type alias">; def note_protected_by_constexpr_if : Note< "jump enters controlled statement of constexpr if">; +def note_protected_by_consteval_if : Note< + "jump enters controlled statement of consteval if">; def note_protected_by_if_available : Note< "jump enters controlled statement of if available">; def note_protected_by_vla : Note< @@ -6397,11 +6429,6 @@ def warn_gnu_null_ptr_arith : Warning< def warn_pointer_sub_null_ptr : Warning< "performing pointer subtraction with a null pointer %select{has|may have}0 undefined behavior">, InGroup, DefaultIgnore; -def err_kernel_invalidates_sycl_unique_stable_name - : Error<"kernel instantiation changes the result of an evaluated " - "'__builtin_sycl_unique_stable_name'">; -def note_sycl_unique_stable_name_evaluated_here - : Note<"'__builtin_sycl_unique_stable_name' evaluated here">; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, @@ -6770,7 +6797,7 @@ def warn_taking_address_of_packed_member : Warning< "taking address of packed member %0 of class or structure %q1 may result in an unaligned pointer value">, InGroup>; def warn_param_mismatched_alignment : Warning< - "passing %0-byte aligned argument to %1-byte aligned parameter %2 of %3 may result in an unaligned pointer access">, + "passing %0-byte aligned argument to %1-byte aligned parameter %2%select{| of %4}3 may result in an unaligned pointer access">, InGroup>; def err_objc_object_assignment : Error< @@ -7413,10 +7440,13 @@ def note_member_declared_here : Note< "member %0 declared here">; def note_member_first_declared_here : Note< "member %0 first declared here">; +def warn_bitwise_instead_of_logical : Warning< + "use of bitwise '%0' with boolean operands">, + InGroup, DefaultIgnore; def warn_bitwise_negation_bool : Warning< "bitwise negation of a boolean expression%select{;| always evaluates to 'true';}0 " "did you mean logical negation?">, - InGroup>; + InGroup, DefaultIgnore; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated and " @@ -7490,7 +7520,8 @@ def note_throw_in_function : Note<"function declared non-throwing here">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< - "cannot use C++ 'try' in the same function as SEH '__try'">; + "cannot use %select{C++ 'try'|Objective-C '@try'}0 " + "in the same function as SEH '__try'">; def err_seh_try_unsupported : Error< "SEH '__try' is not supported on this target">; def note_conflicting_try_here : Note< @@ -8380,8 +8411,10 @@ def err_ref_bad_target_global_initializer : Error< "function %1 in global initializer">; def err_capture_bad_target : Error< "capture host variable %0 by reference in device or host device lambda function">; -def err_capture_bad_target_this_ptr : Error< - "capture host side class data member by this pointer in device or host device lambda function">; +def warn_maybe_capture_bad_target_this_ptr : Warning< + "capture host side class data member by this pointer in device or host device lambda function " + "may result in invalid memory access if this pointer is not accessible on device side">, + InGroup>; def warn_kern_is_method : Extension< "kernel function %0 is a member function; this may not be accepted by nvcc">, InGroup; @@ -8551,6 +8584,9 @@ def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, InGroup; +def warn_unused_comma_left_operand : Warning< + "left operand of comma operator has no effect">, + InGroup; def warn_unused_voidptr : Warning< "expression result unused; should this cast be to 'void'?">, InGroup; @@ -9142,14 +9178,18 @@ def note_defaulted_comparison_calls_deleted : Note< "defaulted %0 is implicitly deleted because it would invoke a deleted " "comparison function%select{| for member %2| for base class %2}1">; def note_defaulted_comparison_no_viable_function : Note< - "defaulted %0 is implicitly deleted because there is no viable three-way " - "comparison function for%select{| member| base class}1 %2">; + "defaulted %0 is implicitly deleted because there is no viable " + "%select{three-way comparison function|'operator=='}1 for " + "%select{|member |base class }2%3">; def note_defaulted_comparison_no_viable_function_synthesized : Note< "three-way comparison cannot be synthesized because there is no viable " "function for %select{'=='|'<'}0 comparison">; def note_defaulted_comparison_not_rewritten_callee : Note< "defaulted %0 is implicitly deleted because this non-rewritten comparison " "function would be the best match for the comparison">; +def note_defaulted_comparison_not_rewritten_conversion : Note< + "defaulted %0 is implicitly deleted because a builtin comparison function " + "using this conversion would be the best match for the comparison">; def note_defaulted_comparison_cannot_deduce : Note< "return type of defaulted 'operator<=>' cannot be deduced because " "return type %2 of three-way comparison for %select{|member|base class}0 %1 " @@ -9570,9 +9610,6 @@ def err_fallthrough_attr_outside_switch : Error< "fallthrough annotation is outside switch statement">; def err_fallthrough_attr_invalid_placement : Error< "fallthrough annotation does not directly precede switch label">; -def warn_fallthrough_attr_unreachable : Warning< - "fallthrough annotation in unreachable code">, - InGroup, DefaultIgnore; def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, @@ -9668,10 +9705,6 @@ def warn_falloff_noreturn_function : Warning< InGroup; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; -def err_noreturn_missing_on_first_decl : Error< - "function declared '[[noreturn]]' after its first declaration">; -def note_noreturn_missing_first_decl : Note< - "declaration missing '[[noreturn]]' attribute is here">; def err_carries_dependency_missing_on_first_decl : Error< "%select{function|parameter}0 declared '[[carries_dependency]]' " "after its first declaration">; @@ -9729,6 +9762,9 @@ def err_argument_invalid_range : Error< def warn_argument_invalid_range : Warning< "argument value %0 is outside the valid range [%1, %2]">, DefaultError, InGroup>; +def warn_argument_undefined_behaviour : Warning< + "argument value %0 will result in undefined behaviour">, + InGroup>; def err_argument_not_multiple : Error< "argument should be a multiple of %0">; def err_argument_not_power_of_2 : Error< @@ -9769,8 +9805,14 @@ def err_mips_builtin_requires_msa : Error< "this builtin requires 'msa' ASE, please use -mmsa">; def err_ppc_builtin_only_on_arch : Error< "this builtin is only valid on POWER%0 or later CPUs">; +def err_ppc_builtin_requires_vsx : Error< + "this builtin requires VSX to be enabled">; +def err_ppc_builtin_requires_abi : Error< + "this builtin requires ABI -mabi=%0">; def err_ppc_invalid_use_mma_type : Error< "invalid use of PPC MMA type">; +def err_ppc_invalid_test_data_class_type : Error< + "expected a 'float' or 'double' for the first argument">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< @@ -10091,8 +10133,7 @@ def err_opencl_type_can_only_be_used_as_function_parameter : Error < def err_opencl_type_not_found : Error< "%0 type %1 not found; include the base header with -finclude-default-header">; def warn_opencl_attr_deprecated_ignored : Warning < - "%0 attribute is deprecated and ignored in OpenCL version %1">, - InGroup; + "%0 attribute is deprecated and ignored in %1">, InGroup; def err_opencl_variadic_function : Error< "invalid prototype, variadic arguments are not allowed in OpenCL">; def err_opencl_requires_extension : Error< @@ -10100,8 +10141,6 @@ def err_opencl_requires_extension : Error< def ext_opencl_double_without_pragma : Extension< "Clang permits use of type 'double' regardless pragma if 'cl_khr_fp64' is" " supported">; -def err_opencl_double_requires_extension : Error< - "use of type 'double' requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0 support">; def warn_opencl_generic_address_space_arg : Warning< "passing non-generic address space pointer to %0" " may cause dynamic conversion affecting performance">, @@ -10159,7 +10198,7 @@ def err_opencl_builtin_expected_type : Error< // OpenCL v3.0 s6.3.7 - Vector Components def ext_opencl_ext_vector_type_rgba_selector: ExtWarn< - "vector component name '%0' is an OpenCL C version 3.0 feature">, + "vector component name '%0' is a feature from OpenCL version 3.0 onwards">, InGroup; def err_openclcxx_placement_new : Error< @@ -10530,6 +10569,8 @@ def err_omp_map_shared_storage : Error< "variable already marked as mapped in current construct">; def err_omp_invalid_map_type_for_directive : Error< "%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">; +def err_omp_invalid_map_type_modifier_for_directive : Error< + "map type modifier '%0' is not allowed for '#pragma omp %1'">; def err_omp_no_clause_for_directive : Error< "expected at least one %0 clause for '#pragma omp %1'">; def err_omp_threadprivate_in_clause : Error< @@ -10558,6 +10599,8 @@ def err_omp_depend_sink_unexpected_expr : Error< "unexpected expression: number of expressions is larger than the number of associated loops">; def err_omp_depend_sink_expected_plus_minus : Error< "expected '+' or '-' operation">; +def err_omp_taskwait_depend_mutexinoutset_not_allowed : Error< + "'mutexinoutset' modifier not allowed in 'depend' clause on 'taskwait' directive">; def err_omp_depend_sink_source_not_allowed : Error< "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; def err_omp_depend_zero_length_array_section_not_allowed : Error< @@ -10679,9 +10722,9 @@ def err_omp_invariant_or_linear_dependency : Error< "expected loop invariant expression or ' * %0 + ' kind of expression">; def err_omp_wrong_dependency_iterator_type : Error< "expected an integer or a pointer type of the outer loop counter '%0' for non-rectangular nests">; -def err_device_unsupported_type - : Error<"%0 requires %select{|%2 bit size}1 %3 type support, but device " - "'%4' does not support it">; +def err_target_unsupported_type + : Error<"%0 requires %select{|%2 bit size}1 %3 %select{|return }4type support," + " but target '%5' does not support it">; def err_omp_lambda_capture_in_declare_target_not_to : Error< "variable captured in declare target region must appear in a to clause">; def err_omp_device_type_mismatch : Error< @@ -10716,9 +10759,14 @@ def err_omp_declare_variant_diff : Error< "function with '#pragma omp declare variant' has a different %select{calling convention" "|return type|constexpr specification|inline specification|storage class|" "linkage}0">; +def err_omp_declare_variant_prototype_required : Error< + "function with '#pragma omp declare variant' must have a prototype when " + "'append_args' is used">; +def err_omp_interop_type_not_found : Error< + "'omp_interop_t' must be defined when 'append_args' clause is used; include ">; def err_omp_declare_variant_incompat_types : Error< - "variant in '#pragma omp declare variant' with type %0 is incompatible with type %1" - >; + "variant in '#pragma omp declare variant' with type %0 is incompatible with" + " type %1%select{| with appended arguments}2">; def warn_omp_declare_variant_marked_as_declare_variant : Warning< "variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'" >, InGroup; @@ -10764,6 +10812,9 @@ def note_omp_protected_structured_block : Note<"jump bypasses OpenMP structured block">; def note_omp_exits_structured_block : Note<"jump exits scope of OpenMP structured block">; +def err_omp_lastprivate_loop_var_non_loop_iteration : Error< + "only loop iteration variables are allowed in 'lastprivate' clause in " + "'omp loop' directives">; def err_omp_interop_variable_expected : Error< "expected%select{| non-const}0 variable of type 'omp_interop_t'">; def err_omp_interop_variable_wrong_type : Error< @@ -10781,6 +10832,14 @@ def err_omp_dispatch_statement_call def err_omp_unroll_full_variable_trip_count : Error< "loop to be fully unrolled must have a constant trip count">; def note_omp_directive_here : Note<"'%0' directive found here">; +def err_omp_instantiation_not_supported + : Error<"instantiation of '%0' not supported yet">; +def err_omp_adjust_arg_multiple_clauses : Error< + "'adjust_arg' argument %0 used in multiple clauses">; +def err_omp_clause_requires_dispatch_construct : Error< + "'%0' clause requires 'dispatch' context selector">; +def err_omp_append_args_with_varargs : Error< + "'append_args' is not allowed with varargs functions">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { @@ -10951,19 +11010,29 @@ def err_coroutine_invalid_func_context : Error< "|a function with a deduced return type|a varargs function" "|a consteval function}0">; def err_implied_coroutine_type_not_found : Error< - "%0 type was not found; include before defining " - "a coroutine">; + "%0 type was not found; include before defining " + "a coroutine; include if your version " + "of libcxx is less than 14.0">; +def warn_deprecated_coroutine_namespace : Warning< + "Please move from std::experimental::%0 to std::%0. " + "Support for std::experimental::%0 will be removed in LLVM 15.">, + InGroup; +def err_mixed_use_std_and_experimental_namespace_for_coroutine : Error < + "Found mixed use of std namespace and std::experimental namespace for " + "coroutine, which is disallowed. The coroutine components in " + "std::experimental namespace is deprecated. Please use coroutine components " + "under std namespace.">; def err_implicit_coroutine_std_nothrow_type_not_found : Error< "std::nothrow was not found; include before defining a coroutine which " "uses get_return_object_on_allocation_failure()">; def err_malformed_std_nothrow : Error< "std::nothrow must be a valid variable declaration">; def err_malformed_std_coroutine_handle : Error< - "std::experimental::coroutine_handle must be a class template">; + "std::coroutine_handle isn't a class template">; def err_coroutine_handle_missing_member : Error< - "std::experimental::coroutine_handle missing a member named '%0'">; + "std::coroutine_handle must have a member named '%0'">; def err_malformed_std_coroutine_traits : Error< - "'std::experimental::coroutine_traits' must be a class template">; + "std::coroutine_traits isn't a class template">; def err_implied_std_coroutine_traits_promise_type_not_found : Error< "this function cannot be a coroutine: %q0 has no member named 'promise_type'">; def err_implied_std_coroutine_traits_promise_type_not_class : Error< @@ -11193,8 +11262,8 @@ def err_multiversion_mismatched_attrs "%0 %select{is missing|has different arguments}1">; def err_multiversion_diff : Error< "multiversioned function declaration has a different %select{calling convention" - "|return type|constexpr specification|inline specification|storage class|" - "linkage}0">; + "|return type|constexpr specification|inline specification|linkage|" + "language linkage}0">; def err_multiversion_doesnt_support : Error< "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not " "yet support %select{function templates|virtual functions|" @@ -11259,6 +11328,12 @@ def err_builtin_launder_invalid_arg : Error< "%select{non-pointer|function pointer|void pointer}0 argument to " "'__builtin_launder' is not allowed">; +def err_builtin_invalid_arg_type: Error < + "%ordinal0 argument must be a " + "%select{vector, integer or floating point type|matrix|" + "pointer to a valid matrix element type|" + "signed integer or floating point type|vector type}1 (was %2)">; + def err_builtin_matrix_disabled: Error< "matrix types extension is disabled. Pass -fenable-matrix to enable it">; def err_matrix_index_not_integer: Error< @@ -11271,11 +11346,8 @@ def err_matrix_separate_incomplete_index: Error< "matrix row and column subscripts cannot be separated by any expression">; def err_matrix_subscript_comma: Error< "comma expressions are not allowed as indices in matrix subscript expressions">; -def err_builtin_matrix_arg: Error<"1st argument must be a matrix">; def err_builtin_matrix_scalar_unsigned_arg: Error< "%0 argument must be a constant unsigned integer expression">; -def err_builtin_matrix_pointer_arg: Error< - "%ordinal0 argument must be a pointer to a valid matrix element type">; def err_builtin_matrix_pointer_arg_mismatch: Error< "the pointee of the 2nd argument must match the element type of the 1st argument (%0 != %1)">; def err_builtin_matrix_store_to_const: Error< diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index bf3221be004..f15a935d2af 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -20,7 +20,7 @@ def err_fe_pch_malformed_block : Error< def err_fe_ast_file_modified : Error< "file '%0' has been modified since the " "%select{precompiled header|module file|AST file}1 '%2' was built" - ": %select{size|mtime|content}3 changed">, + ": %select{size|mtime|content}3 changed%select{| (was %5, now %6)}4">, DefaultFatal; def err_fe_pch_file_overridden : Error< "file '%0' from the precompiled header has been overridden">; diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index f2379c7ddfb..19c967efcc4 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -43,11 +43,28 @@ class SourceLocation; enum class ReservedIdentifierStatus { NotReserved = 0, StartsWithUnderscoreAtGlobalScope, + StartsWithUnderscoreAndIsExternC, StartsWithDoubleUnderscore, StartsWithUnderscoreFollowedByCapitalLetter, ContainsDoubleUnderscore, }; +/// Determine whether an identifier is reserved for use as a name at global +/// scope. Such identifiers might be implementation-specific global functions +/// or variables. +inline bool isReservedAtGlobalScope(ReservedIdentifierStatus Status) { + return Status != ReservedIdentifierStatus::NotReserved; +} + +/// Determine whether an identifier is reserved in all contexts. Such +/// identifiers might be implementation-specific keywords or macros, for +/// example. +inline bool isReservedInAllContexts(ReservedIdentifierStatus Status) { + return Status != ReservedIdentifierStatus::NotReserved && + Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope && + Status != ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC; +} + /// A simple pair of identifier info and location. using IdentifierLocPair = std::pair; @@ -121,7 +138,16 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { // True if this is a mangled OpenMP variant name. unsigned IsMangledOpenMPVariantName : 1; - // 28 bits left in a 64-bit word. + // True if this is a deprecated macro. + unsigned IsDeprecatedMacro : 1; + + // True if this macro is unsafe in headers. + unsigned IsRestrictExpansion : 1; + + // True if this macro is final. + unsigned IsFinal : 1; + + // 22 bits left in a 64-bit word. // Managed by the language front-end. void *FETokenInfo = nullptr; @@ -134,7 +160,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { IsPoisoned(false), IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false), - IsModulesImport(false), IsMangledOpenMPVariantName(false) {} + IsModulesImport(false), IsMangledOpenMPVariantName(false), + IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {} public: IdentifierInfo(const IdentifierInfo &) = delete; @@ -182,6 +209,14 @@ public: NeedsHandleIdentifier = true; HadMacro = true; } else { + // If this is a final macro, make the deprecation and header unsafe bits + // stick around after the undefinition so they apply to any redefinitions. + if (!IsFinal) { + // Because calling the setters of these calls recomputes, just set them + // manually to avoid recomputing a bunch of times. + IsDeprecatedMacro = false; + IsRestrictExpansion = false; + } RecomputeNeedsHandleIdentifier(); } } @@ -192,6 +227,34 @@ public: return HadMacro; } + bool isDeprecatedMacro() const { return IsDeprecatedMacro; } + + void setIsDeprecatedMacro(bool Val) { + if (IsDeprecatedMacro == Val) + return; + IsDeprecatedMacro = Val; + if (Val) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + + bool isRestrictExpansion() const { return IsRestrictExpansion; } + + void setIsRestrictExpansion(bool Val) { + if (IsRestrictExpansion == Val) + return; + IsRestrictExpansion = Val; + if (Val) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + + bool isFinal() const { return IsFinal; } + + void setIsFinal(bool Val) { IsFinal = Val; } + /// If this is a source-language token (e.g. 'for'), this API /// can be used to cause the lexer to map identifiers to source-language /// tokens. diff --git a/clang/include/clang/Basic/JsonSupport.h b/clang/include/clang/Basic/JsonSupport.h index 8b02e440df4..2ccb08e4bda 100644 --- a/clang/include/clang/Basic/JsonSupport.h +++ b/clang/include/clang/Basic/JsonSupport.h @@ -12,6 +12,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include @@ -70,7 +71,7 @@ inline std::string JsonFormat(StringRef RawSR, bool AddQuotes) { } // Remove new-lines. - Str.erase(std::remove(Str.begin(), Str.end(), '\n'), Str.end()); + llvm::erase_value(Str, '\n'); if (!AddQuotes) return Str; @@ -98,18 +99,19 @@ inline void printSourceLocationAsJson(raw_ostream &Out, SourceLocation Loc, if (AddBraces) Out << "{ "; std::string filename(PLoc.getFilename()); -#ifdef _WIN32 - // Remove forbidden Windows path characters - auto RemoveIt = - std::remove_if(filename.begin(), filename.end(), [](auto Char) { - static const char ForbiddenChars[] = "<>*?\"|"; - return std::find(std::begin(ForbiddenChars), std::end(ForbiddenChars), - Char) != std::end(ForbiddenChars); - }); - filename.erase(RemoveIt, filename.end()); - // Handle windows-specific path delimiters. - std::replace(filename.begin(), filename.end(), '\\', '/'); -#endif + if (is_style_windows(llvm::sys::path::Style::native)) { + // Remove forbidden Windows path characters + auto RemoveIt = + std::remove_if(filename.begin(), filename.end(), [](auto Char) { + static const char ForbiddenChars[] = "<>*?\"|"; + return std::find(std::begin(ForbiddenChars), + std::end(ForbiddenChars), + Char) != std::end(ForbiddenChars); + }); + filename.erase(RemoveIt, filename.end()); + // Handle windows-specific path delimiters. + std::replace(filename.begin(), filename.end(), '\\', '/'); + } Out << "\"line\": " << PLoc.getLine() << ", \"column\": " << PLoc.getColumn() << ", \"file\": \"" << filename << "\""; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 08b8d8851af..4651f4fff6a 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -224,13 +224,14 @@ LANGOPT(OpenCLVersion , 32, 0, "OpenCL C version") LANGOPT(OpenCLCPlusPlus , 1, 0, "C++ for OpenCL") LANGOPT(OpenCLCPlusPlusVersion , 32, 0, "C++ for OpenCL version") LANGOPT(OpenCLGenericAddressSpace, 1, 0, "OpenCL generic keyword") -LANGOPT(OpenCLPipe , 1, 0, "OpenCL pipe keyword") +LANGOPT(OpenCLPipes , 1, 0, "OpenCL pipes language constructs and built-ins") LANGOPT(NativeHalfType , 1, 0, "Native half type support") LANGOPT(NativeHalfArgsAndReturns, 1, 0, "Native half args and returns") LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns") LANGOPT(CUDA , 1, 0, "CUDA") LANGOPT(HIP , 1, 0, "HIP") LANGOPT(OpenMP , 32, 0, "OpenMP support and version of OpenMP (31, 40 or 45)") +LANGOPT(OpenMPExtensions , 1, 1, "Enable all Clang extensions for OpenMP directives and clauses") LANGOPT(OpenMPSimd , 1, 0, "Use SIMD only OpenMP support.") LANGOPT(OpenMPUseTLS , 1, 0, "Use TLS for threadprivates or runtime calls") LANGOPT(OpenMPIsDevice , 1, 0, "Generate code only for OpenMP target device") @@ -241,7 +242,10 @@ LANGOPT(OpenMPCUDANumSMs , 32, 0, "Number of SMs for CUDA devices.") LANGOPT(OpenMPCUDABlocksPerSM , 32, 0, "Number of blocks per SM for CUDA devices.") LANGOPT(OpenMPCUDAReductionBufNum , 32, 1024, "Number of the reduction records in the intermediate reduction buffer used for the teams reductions.") LANGOPT(OpenMPTargetNewRuntime , 1, 0, "Use the new bitcode library for OpenMP offloading") +LANGOPT(OpenMPTargetDebug , 32, 0, "Enable debugging in the OpenMP offloading device RTL") LANGOPT(OpenMPOptimisticCollapse , 1, 0, "Use at most 32 bits to represent the collapsed loop nest counter.") +LANGOPT(OpenMPThreadSubscription , 1, 0, "Assume work-shared loops do not have more iterations than participating threads.") +LANGOPT(OpenMPTeamSubscription , 1, 0, "Assume distributed loops do not have more iterations than participating teams.") LANGOPT(RenderScript , 1, 0, "RenderScript") LANGOPT(CUDAIsDevice , 1, 0, "compiling for CUDA device") @@ -280,6 +284,7 @@ BENIGN_LANGOPT(VisibilityInlinesHiddenStaticLocalVar, 1, 0, "hidden visibility for static local variables in inline C++ " "methods when -fvisibility-inlines hidden is enabled") LANGOPT(GlobalAllocationFunctionVisibilityHidden , 1, 0, "hidden visibility for global operator new and delete declaration") +LANGOPT(NewInfallible , 1, 0, "Treats throwing global C++ operator new as always returning valid memory (annotates with __attribute__((returns_nonnull)) and throw()). This is detectable in source.") BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype") BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support") BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type") @@ -397,6 +402,7 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest, "with") COMPATIBLE_VALUE_LANGOPT(FunctionAlignment, 5, 0, "Default alignment for functions") +COMPATIBLE_VALUE_LANGOPT(LoopAlignment, 32, 0, "Default alignment for loops") LANGOPT(FixedPoint, 1, 0, "fixed point types") LANGOPT(PaddingOnUnsignedFixedPoint, 1, 0, @@ -419,12 +425,15 @@ LANGOPT(SpeculativeLoadHardening, 1, 0, "Speculative load hardening enabled") LANGOPT(RelativeCXXABIVTables, 1, 0, "Use an ABI-incompatible v-table layout that uses relative references") -LANGOPT(ArmSveVectorBits, 32, 0, "SVE vector size in bits") +LANGOPT(VScaleMin, 32, 0, "Minimum vscale value") +LANGOPT(VScaleMax, 32, 0, "Maximum vscale value") -ENUM_LANGOPT(ExtendIntArgs, ExtendArgsKind, 1, ExtendArgsKind::ExtendTo32, +ENUM_LANGOPT(ExtendIntArgs, ExtendArgsKind, 1, ExtendArgsKind::ExtendTo32, "Controls how scalar integer arguments are extended in calls " "to unprototyped and varargs functions") +VALUE_LANGOPT(FuchsiaAPILevel, 32, 0, "Fuchsia API level") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 71cf0c65e69..35b33c2e097 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -354,6 +354,9 @@ public: /// A list of all -fno-builtin-* function names (e.g., memset). std::vector NoBuiltinFuncs; + /// A prefix map for __FILE__, __BASE_FILE__ and __builtin_FILE(). + std::map> MacroPrefixMap; + /// Triples of the OpenMP targets that the host code codegen should /// take into account in order to generate accurate offloading descriptors. std::vector OMPTargetTriples; @@ -428,6 +431,13 @@ public: /// Return the OpenCL C or C++ version as a VersionTuple. VersionTuple getOpenCLVersionTuple() const; + /// Return the OpenCL version that kernel language is compatible with + unsigned getOpenCLCompatibleVersion() const; + + /// Return the OpenCL C or C++ for OpenCL language name and version + /// as a string. + std::string getOpenCLVersionString() const; + /// Check if return address signing is enabled. bool hasSignReturnAddress() const { return getSignReturnAddressScope() != SignReturnAddressScopeKind::None; @@ -460,6 +470,9 @@ public: } bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; } + + /// Remap path prefix according to -fmacro-prefix-path option. + void remapPathPrefix(SmallString<256> &Path) const; }; /// Floating point control options diff --git a/clang/include/clang/Basic/LangStandards.def b/clang/include/clang/Basic/LangStandards.def index 2cfeb68e56d..6056cfd65bb 100644 --- a/clang/include/clang/Basic/LangStandards.def +++ b/clang/include/clang/Basic/LangStandards.def @@ -180,8 +180,15 @@ LANGSTANDARD(opencl20, "cl2.0", LANGSTANDARD(opencl30, "cl3.0", OpenCL, "OpenCL 3.0", LineComment | C99 | Digraphs | HexFloat | OpenCL) -LANGSTANDARD(openclcpp, "clc++", - OpenCL, "C++ for OpenCL", + +LANGSTANDARD(openclcpp10, "clc++1.0", + OpenCL, "C++ for OpenCL 1.0", + LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | + Digraphs | HexFloat | OpenCL) +LANGSTANDARD_ALIAS(openclcpp10, "clc++") + +LANGSTANDARD(openclcpp2021, "clc++2021", + OpenCL, "C++ for OpenCL 2021", LineComment | CPlusPlus | CPlusPlus11 | CPlusPlus14 | CPlusPlus17 | Digraphs | HexFloat | OpenCL) @@ -190,7 +197,9 @@ LANGSTANDARD_ALIAS_DEPR(opencl11, "CL1.1") LANGSTANDARD_ALIAS_DEPR(opencl12, "CL1.2") LANGSTANDARD_ALIAS_DEPR(opencl20, "CL2.0") LANGSTANDARD_ALIAS_DEPR(opencl30, "CL3.0") -LANGSTANDARD_ALIAS_DEPR(openclcpp, "CLC++") +LANGSTANDARD_ALIAS_DEPR(openclcpp10, "CLC++") +LANGSTANDARD_ALIAS_DEPR(openclcpp10, "CLC++1.0") +LANGSTANDARD_ALIAS_DEPR(openclcpp2021, "CLC++2021") // CUDA LANGSTANDARD(cuda, "cuda", CUDA, "NVIDIA CUDA(tm)", diff --git a/clang/include/clang/Basic/MSP430Target.def b/clang/include/clang/Basic/MSP430Target.def index a1e192c1926..7a10be1d54c 100644 --- a/clang/include/clang/Basic/MSP430Target.def +++ b/clang/include/clang/Basic/MSP430Target.def @@ -238,8 +238,7 @@ MSP430_MCU_FEAT("msp430f4793", "32bit") MSP430_MCU_FEAT("msp430f4784", "32bit") MSP430_MCU_FEAT("msp430f4794", "32bit") -// Generic MSUs -MSP430_MCU("msp430") +// Generic MCUs MSP430_MCU("msp430i2xxgeneric") #undef MSP430_MCU diff --git a/clang/include/clang/Basic/ObjCRuntime.h b/clang/include/clang/Basic/ObjCRuntime.h index 26403bfa98c..30a5fde4075 100644 --- a/clang/include/clang/Basic/ObjCRuntime.h +++ b/clang/include/clang/Basic/ObjCRuntime.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Support/VersionTuple.h" #include @@ -480,6 +481,12 @@ public: friend llvm::hash_code hash_value(const ObjCRuntime &OCR) { return llvm::hash_combine(OCR.getKind(), OCR.getVersion()); } + + template + friend void addHash(llvm::HashBuilderImpl &HBuilder, + const ObjCRuntime &OCR) { + HBuilder.add(OCR.getKind(), OCR.getVersion()); + } }; raw_ostream &operator<<(raw_ostream &out, const ObjCRuntime &value); diff --git a/clang/include/clang/Basic/OpenCLOptions.h b/clang/include/clang/Basic/OpenCLOptions.h index 1a035626fad..d6cb1a21051 100644 --- a/clang/include/clang/Basic/OpenCLOptions.h +++ b/clang/include/clang/Basic/OpenCLOptions.h @@ -58,7 +58,7 @@ static inline OpenCLVersionID encodeOpenCLVersion(unsigned OpenCLVersion) { // mask. static inline bool isOpenCLVersionContainedInMask(const LangOptions &LO, unsigned Mask) { - auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; + auto CLVer = LO.getOpenCLCompatibleVersion(); OpenCLVersionID Code = encodeOpenCLVersion(CLVer); return Mask & Code; } @@ -79,8 +79,8 @@ public: // the __opencl_c_program_scope_global_variables feature is supported // C++ for OpenCL inherits rule from OpenCL C v2.0. bool areProgramScopeVariablesSupported(const LangOptions &Opts) const { - return Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200 || - (Opts.OpenCLVersion == 300 && + return Opts.getOpenCLCompatibleVersion() == 200 || + (Opts.getOpenCLCompatibleVersion() == 300 && isSupported("__opencl_c_program_scope_global_variables", Opts)); } @@ -115,8 +115,7 @@ public: // Is option available in OpenCL version \p LO. bool isAvailableIn(const LangOptions &LO) const { // In C++ mode all extensions should work at least as in v2.0. - auto CLVer = LO.OpenCLCPlusPlus ? 200 : LO.OpenCLVersion; - return CLVer >= Avail; + return LO.getOpenCLCompatibleVersion() >= Avail; } // Is core option in OpenCL version \p LO. diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 9f9c32da4aa..80ebda91794 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -59,6 +59,12 @@ #ifndef OPENMP_REDUCTION_MODIFIER #define OPENMP_REDUCTION_MODIFIER(Name) #endif +#ifndef OPENMP_ADJUST_ARGS_KIND +#define OPENMP_ADJUST_ARGS_KIND(Name) +#endif +#ifndef OPENMP_BIND_KIND +#define OPENMP_BIND_KIND(Name) +#endif // Static attributes for 'schedule' clause. OPENMP_SCHEDULE_KIND(static) @@ -123,6 +129,8 @@ OPENMP_MAP_MODIFIER_KIND(always) OPENMP_MAP_MODIFIER_KIND(close) OPENMP_MAP_MODIFIER_KIND(mapper) OPENMP_MAP_MODIFIER_KIND(present) +// This is an OpenMP extension for the sake of OpenACC support. +OPENMP_MAP_MODIFIER_KIND(ompx_hold) // Modifiers for 'to' or 'from' clause. OPENMP_MOTION_MODIFIER_KIND(mapper) @@ -147,6 +155,17 @@ OPENMP_REDUCTION_MODIFIER(default) OPENMP_REDUCTION_MODIFIER(inscan) OPENMP_REDUCTION_MODIFIER(task) +// Adjust-op kinds for the 'adjust_args' clause. +OPENMP_ADJUST_ARGS_KIND(nothing) +OPENMP_ADJUST_ARGS_KIND(need_device_ptr) + +// Binding kinds for the 'bind' clause. +OPENMP_BIND_KIND(teams) +OPENMP_BIND_KIND(parallel) +OPENMP_BIND_KIND(thread) + +#undef OPENMP_BIND_KIND +#undef OPENMP_ADJUST_ARGS_KIND #undef OPENMP_REDUCTION_MODIFIER #undef OPENMP_DEVICE_MODIFIER #undef OPENMP_ORDER_KIND diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index c7a2591de26..e95a717f268 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H #define LLVM_CLANG_BASIC_OPENMPKINDS_H +#include "clang/Basic/LangOptions.h" #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" @@ -166,8 +167,22 @@ enum OpenMPReductionClauseModifier { OMPC_REDUCTION_unknown, }; +/// OpenMP adjust-op kinds for 'adjust_args' clause. +enum OpenMPAdjustArgsOpKind { +#define OPENMP_ADJUST_ARGS_KIND(Name) OMPC_ADJUST_ARGS_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_ADJUST_ARGS_unknown, +}; + +/// OpenMP bindings for the 'bind' clause. +enum OpenMPBindClauseKind { +#define OPENMP_BIND_KIND(Name) OMPC_BIND_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_BIND_unknown +}; + unsigned getOpenMPSimpleClauseType(OpenMPClauseKind Kind, llvm::StringRef Str, - unsigned OpenMPVersion); + const LangOptions &LangOpts); const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type); /// Checks if the specified directive is a directive with an associated @@ -245,6 +260,13 @@ bool isOpenMPDistributeDirective(OpenMPDirectiveKind DKind); /// otherwise - false. bool isOpenMPNestingDistributeDirective(OpenMPDirectiveKind DKind); +/// Checks if the specified directive constitutes a 'loop' directive in the +/// outermost nest. For example, 'omp teams loop' or 'omp loop'. +/// \param DKind Specified directive. +/// \return true - the directive has loop on the outermost nest. +/// otherwise - false. +bool isOpenMPGenericLoopDirective(OpenMPDirectiveKind DKind); + /// Checks if the specified clause is one of private clauses like /// 'private', 'firstprivate', 'reduction' etc.. /// \param Kind Clause kind. diff --git a/clang/include/clang/Basic/Sanitizers.h b/clang/include/clang/Basic/Sanitizers.h index b12a3b7821d..db53010645a 100644 --- a/clang/include/clang/Basic/Sanitizers.h +++ b/clang/include/clang/Basic/Sanitizers.h @@ -16,6 +16,7 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" #include #include @@ -72,6 +73,12 @@ public: llvm::hash_code hash_value() const; + template + friend void addHash(llvm::HashBuilderImpl &HBuilder, + const SanitizerMask &SM) { + HBuilder.addRange(&SM.maskLoToHigh[0], &SM.maskLoToHigh[kNumElem]); + } + constexpr explicit operator bool() const { return maskLoToHigh[0] || maskLoToHigh[1]; } diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h index 540de23b9f5..543245a811d 100644 --- a/clang/include/clang/Basic/SourceLocation.h +++ b/clang/include/clang/Basic/SourceLocation.h @@ -23,8 +23,6 @@ namespace llvm { -template struct DenseMapInfo; - class FoldingSetNodeID; template struct FoldingSetTrait; @@ -363,6 +361,10 @@ class FileEntry; /// A SourceLocation and its associated SourceManager. /// /// This is useful for argument passing to functions that expect both objects. +/// +/// This class does not guarantee the presence of either the SourceManager or +/// a valid SourceLocation. Clients should use `isValid()` and `hasManager()` +/// before calling the member functions. class FullSourceLoc : public SourceLocation { const SourceManager *SrcMgr = nullptr; @@ -373,13 +375,10 @@ public: explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} - bool hasManager() const { - bool hasSrcMgr = SrcMgr != nullptr; - assert(hasSrcMgr == isValid() && "FullSourceLoc has location but no manager"); - return hasSrcMgr; - } + /// Checks whether the SourceManager is present. + bool hasManager() const { return SrcMgr != nullptr; } - /// \pre This FullSourceLoc has an associated SourceManager. + /// \pre hasManager() const SourceManager &getManager() const { assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; @@ -466,7 +465,7 @@ namespace llvm { /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and /// DenseSets. template <> - struct DenseMapInfo { + struct DenseMapInfo { static clang::FileID getEmptyKey() { return {}; } @@ -487,7 +486,7 @@ namespace llvm { /// Define DenseMapInfo so that SourceLocation's can be used as keys in /// DenseMap and DenseSet. This trait class is eqivalent to /// DenseMapInfo which uses SourceLocation::ID is used as a key. - template <> struct DenseMapInfo { + template <> struct DenseMapInfo { static clang::SourceLocation getEmptyKey() { constexpr clang::SourceLocation::UIntTy Zero = 0; return clang::SourceLocation::getFromRawEncoding(~Zero); diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 1c38b411e08..66cdba3f912 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -31,6 +31,15 @@ namespace clang { /// Define the kind of constexpr specifier. enum class ConstexprSpecKind { Unspecified, Constexpr, Consteval, Constinit }; + /// In an if statement, this denotes whether the the statement is + /// a constexpr or consteval if statement. + enum class IfStatementKind : unsigned { + Ordinary, + Constexpr, + ConstevalNonNegated, + ConstevalNegated + }; + /// Specifies the width of a type, e.g., short, long, or long long. enum class TypeSpecifierWidth { Unspecified, Short, Long, LongLong }; @@ -59,6 +68,7 @@ namespace clang { TST_float, TST_double, TST_float128, + TST_ibm128, TST_bool, // _Bool TST_decimal32, // _Decimal32 TST_decimal64, // _Decimal64 diff --git a/clang/include/clang/Basic/Stack.h b/clang/include/clang/Basic/Stack.h index 3418c3bad11..30ebd94aedd 100644 --- a/clang/include/clang/Basic/Stack.h +++ b/clang/include/clang/Basic/Stack.h @@ -39,7 +39,7 @@ namespace clang { /// is insufficient, calls Diag to emit a diagnostic before calling Fn. inline void runWithSufficientStackSpace(llvm::function_ref Diag, llvm::function_ref Fn) { -#ifdef LLVM_ENABLE_THREADS +#if LLVM_ENABLE_THREADS if (LLVM_UNLIKELY(isStackNearlyExhausted())) runWithSufficientStackSpaceSlow(Diag, Fn); else diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 508f1fddf1b..ab31c544ea9 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -219,12 +219,14 @@ def AsTypeExpr : StmtNode; // OpenMP Directives. def OMPCanonicalLoop : StmtNode; def OMPExecutableDirective : StmtNode; +def OMPMetaDirective : StmtNode; def OMPLoopBasedDirective : StmtNode; def OMPLoopDirective : StmtNode; def OMPParallelDirective : StmtNode; def OMPSimdDirective : StmtNode; -def OMPTileDirective : StmtNode; -def OMPUnrollDirective : StmtNode; +def OMPLoopTransformationDirective : StmtNode; +def OMPTileDirective : StmtNode; +def OMPUnrollDirective : StmtNode; def OMPForDirective : StmtNode; def OMPForSimdDirective : StmtNode; def OMPSectionsDirective : StmtNode; @@ -280,3 +282,4 @@ def OMPTargetTeamsDistributeSimdDirective : StmtNode; def OMPInteropDirective : StmtNode; def OMPDispatchDirective : StmtNode; def OMPMaskedDirective : StmtNode; +def OMPGenericLoopDirective : StmtNode; diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h index ed53b10f61e..d4ea8e98b2e 100644 --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -124,10 +124,21 @@ namespace clang { enum { LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, LastTSBuiltin }; } + namespace RISCVVector { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsRISCVVector.def" + FirstTSBuiltin, + }; + } + /// RISCV builtins namespace RISCV { enum { LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, + FirstRVVBuiltin = clang::Builtin::FirstTSBuiltin, + LastRVVBuiltin = RISCVVector::FirstTSBuiltin - 1, #define BUILTIN(ID, TYPE, ATTRS) BI##ID, #include "clang/Basic/BuiltinsRISCV.def" LastTSBuiltin diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 4f0cbf986b3..3e1e09417c6 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -53,6 +53,15 @@ class SourceManager; namespace Builtin { struct Info; } +enum class FloatModeKind { + NoFloat = 255, + Float = 0, + Double, + LongDouble, + Float128, + Ibm128 +}; + /// Fields controlling how types are laid out in memory; these may need to /// be copied for targets like AMDGPU that base their ABIs on an auxiliary /// CPU target. @@ -64,7 +73,7 @@ struct TransferrableTargetInfo { unsigned char BFloat16Width, BFloat16Align; unsigned char FloatWidth, FloatAlign; unsigned char DoubleWidth, DoubleAlign; - unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align; + unsigned char LongDoubleWidth, LongDoubleAlign, Float128Align, Ibm128Align; unsigned char LargeArrayMinWidth, LargeArrayAlign; unsigned char LongWidth, LongAlign; unsigned char LongLongWidth, LongLongAlign; @@ -104,7 +113,7 @@ struct TransferrableTargetInfo { unsigned MaxTLSAlign; const llvm::fltSemantics *HalfFormat, *BFloat16Format, *FloatFormat, - *DoubleFormat, *LongDoubleFormat, *Float128Format; + *DoubleFormat, *LongDoubleFormat, *Float128Format, *Ibm128Format; ///===---- Target Data Type Query Methods -------------------------------===// enum IntType { @@ -121,13 +130,6 @@ struct TransferrableTargetInfo { UnsignedLongLong }; - enum RealType { - NoFloat = 255, - Float = 0, - Double, - LongDouble, - Float128 - }; protected: IntType SizeType, IntMaxType, PtrDiffType, IntPtrType, WCharType, WIntType, Char16Type, Char32Type, Int64Type, Int16Type, SigAtomicType, @@ -200,6 +202,9 @@ protected: bool HasFloat128; bool HasFloat16; bool HasBFloat16; + bool HasIbm128; + bool HasLongDouble; + bool HasFPReturn; bool HasStrictFP; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; @@ -210,9 +215,6 @@ protected: unsigned char RegParmMax, SSERegParmMax; TargetCXXABI TheCXXABI; const LangASMap *AddrSpaceMap; - const unsigned *GridValues = - nullptr; // Array of target-specific GPU grid values that must be - // consistent between host RTL (plugin), device RTL, and clang. mutable StringRef PlatformName; mutable VersionTuple PlatformMinVersion; @@ -401,7 +403,8 @@ public: /// is represented as one of those two). At this time, there is no support /// for an explicit "PPC double-double" type (i.e. __ibm128) so we only /// need to differentiate between "long double" and IEEE quad precision. - RealType getRealTypeByWidth(unsigned BitWidth, bool ExplicitIEEE) const; + FloatModeKind getRealTypeByWidth(unsigned BitWidth, + FloatModeKind ExplicitType) const; /// Return the alignment (in bits) of the specified integer type enum. /// @@ -597,6 +600,16 @@ public: /// Determine whether the _BFloat16 type is supported on this target. virtual bool hasBFloat16Type() const { return HasBFloat16; } + /// Determine whether the __ibm128 type is supported on this target. + virtual bool hasIbm128Type() const { return HasIbm128; } + + /// Determine whether the long double type is supported on this target. + virtual bool hasLongDoubleType() const { return HasLongDouble; } + + /// Determine whether return of a floating point value is supported + /// on this target. + virtual bool hasFPReturn() const { return HasFPReturn; } + /// Determine whether constrained floating point is supported on this target. virtual bool hasStrictFP() const { return HasStrictFP; } @@ -675,12 +688,23 @@ public: return *Float128Format; } + /// getIbm128Width/Align/Format - Return the size/align/format of + /// '__ibm128'. + unsigned getIbm128Width() const { return 128; } + unsigned getIbm128Align() const { return Ibm128Align; } + const llvm::fltSemantics &getIbm128Format() const { return *Ibm128Format; } + /// Return the mangled code of long double. virtual const char *getLongDoubleMangling() const { return "e"; } /// Return the mangled code of __float128. virtual const char *getFloat128Mangling() const { return "g"; } + /// Return the mangled code of __ibm128. + virtual const char *getIbm128Mangling() const { + llvm_unreachable("ibm128 not implemented on this target"); + } + /// Return the mangled code of bfloat. virtual const char *getBFloat16Mangling() const { llvm_unreachable("bfloat not implemented on this target"); @@ -833,8 +857,8 @@ public: /// Check whether the given real type should use the "fpret" flavor of /// Objective-C message passing on this target. - bool useObjCFPRetForRealType(RealType T) const { - return RealTypeUsesObjCFPRet & (1 << T); + bool useObjCFPRetForRealType(FloatModeKind T) const { + return RealTypeUsesObjCFPRet & (1 << (int)T); } /// Check whether _Complex long double should use the "fp2ret" flavor @@ -870,6 +894,11 @@ public: /// across the current set of primary and secondary targets. virtual ArrayRef getTargetBuiltins() const = 0; + /// Returns target-specific min and max values VScale_Range. + virtual Optional> + getVScaleRange(const LangOptions &LangOpts) const { + return None; + } /// The __builtin_clz* and __builtin_ctz* built-in /// functions are specified to have undefined results for zero inputs, but /// on targets that support these operations in a way that provides @@ -993,8 +1022,7 @@ public: } bool isValidAsmImmediate(const llvm::APInt &Value) const { if (!ImmSet.empty()) - return Value.isSignedIntN(32) && - ImmSet.count(Value.getZExtValue()) != 0; + return Value.isSignedIntN(32) && ImmSet.contains(Value.getZExtValue()); return !ImmRange.isConstrained || (Value.sge(ImmRange.Min) && Value.sle(ImmRange.Max)); } @@ -1404,10 +1432,10 @@ public: return LangAS::Default; } - /// Return a target-specific GPU grid value based on the GVIDX enum \p gv - unsigned getGridValue(llvm::omp::GVIDX gv) const { - assert(GridValues != nullptr && "GridValues not initialized"); - return GridValues[gv]; + // access target-specific GPU grid values that must be consistent between + // host RTL (plugin), deviceRTL and clang. + virtual const llvm::omp::GV &getGridValue() const { + llvm_unreachable("getGridValue not implemented on this target"); } /// Retrieve the name of the platform as it is used in the diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 48a664e3494..0dd5936aa3e 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -438,6 +438,7 @@ TYPE_TRAIT_2(__builtin_types_compatible_p, TypeCompatible, KEYNOCXX) KEYWORD(__builtin_va_arg , KEYALL) KEYWORD(__extension__ , KEYALL) KEYWORD(__float128 , KEYALL) +KEYWORD(__ibm128 , KEYALL) KEYWORD(__imag , KEYALL) KEYWORD(__int128 , KEYALL) KEYWORD(__label__ , KEYALL) @@ -827,10 +828,11 @@ PRAGMA_ANNOTATION(pragma_redefine_extname) // handles them. PRAGMA_ANNOTATION(pragma_fp_contract) -// Annotation for #pragma STDC FENV_ACCESS +// Annotations for #pragma STDC FENV_ACCESS and #pragma fenv_access (MS compat) // The lexer produces these so that they only take effect when the parser // handles them. PRAGMA_ANNOTATION(pragma_fenv_access) +PRAGMA_ANNOTATION(pragma_fenv_access_ms) // Annotation for #pragma STDC FENV_ROUND // The lexer produces these so that they only take effect when the parser diff --git a/clang/include/clang/Basic/X86Target.def b/clang/include/clang/Basic/X86Target.def deleted file mode 100644 index 70f3879f33a..00000000000 --- a/clang/include/clang/Basic/X86Target.def +++ /dev/null @@ -1,110 +0,0 @@ -//===--- X86Target.def - X86 Feature/Processor Database ---------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the X86-specific Features and Processors, as used by -// the X86 Targets. -// -//===----------------------------------------------------------------------===// - -#ifndef FEATURE -#define FEATURE(ENUM) -#endif - -#ifndef CPU_SPECIFIC -#define CPU_SPECIFIC(NAME, MANGLING, FEATURES) -#endif - -#ifndef CPU_SPECIFIC_ALIAS -#define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) -#endif - -// List of CPU Supports features in order. These need to remain in the order -// required by attribute 'target' checking. Note that not all are supported/ -// prioritized by GCC, so synchronization with GCC's implementation may require -// changing some existing values. -FEATURE(FEATURE_CMOV) -FEATURE(FEATURE_MMX) -FEATURE(FEATURE_SSE) -FEATURE(FEATURE_SSE2) -FEATURE(FEATURE_SSE3) -FEATURE(FEATURE_SSSE3) -FEATURE(FEATURE_SSE4_A) -FEATURE(FEATURE_SSE4_1) -FEATURE(FEATURE_SSE4_2) -FEATURE(FEATURE_POPCNT) -FEATURE(FEATURE_AES) -FEATURE(FEATURE_PCLMUL) -FEATURE(FEATURE_AVX) -FEATURE(FEATURE_BMI) -FEATURE(FEATURE_FMA4) -FEATURE(FEATURE_XOP) -FEATURE(FEATURE_FMA) -FEATURE(FEATURE_BMI2) -FEATURE(FEATURE_AVX2) -FEATURE(FEATURE_AVX512F) -FEATURE(FEATURE_AVX512VL) -FEATURE(FEATURE_AVX512BW) -FEATURE(FEATURE_AVX512DQ) -FEATURE(FEATURE_AVX512CD) -FEATURE(FEATURE_AVX512ER) -FEATURE(FEATURE_AVX512PF) -FEATURE(FEATURE_AVX512VBMI) -FEATURE(FEATURE_AVX512IFMA) -FEATURE(FEATURE_AVX5124VNNIW) -FEATURE(FEATURE_AVX5124FMAPS) -FEATURE(FEATURE_AVX512VPOPCNTDQ) -FEATURE(FEATURE_AVX512VBMI2) -FEATURE(FEATURE_GFNI) -FEATURE(FEATURE_VPCLMULQDQ) -FEATURE(FEATURE_AVX512VNNI) -FEATURE(FEATURE_AVX512BITALG) -FEATURE(FEATURE_AVX512BF16) -FEATURE(FEATURE_AVX512VP2INTERSECT) - - -// FIXME: When commented out features are supported in LLVM, enable them here. -CPU_SPECIFIC("generic", 'A', "") -CPU_SPECIFIC("pentium", 'B', "") -CPU_SPECIFIC("pentium_pro", 'C', "+cmov") -CPU_SPECIFIC("pentium_mmx", 'D', "+mmx") -CPU_SPECIFIC("pentium_ii", 'E', "+cmov,+mmx") -CPU_SPECIFIC("pentium_iii", 'H', "+cmov,+mmx,+sse") -CPU_SPECIFIC_ALIAS("pentium_iii_no_xmm_regs", "pentium_iii") -CPU_SPECIFIC("pentium_4", 'J', "+cmov,+mmx,+sse,+sse2") -CPU_SPECIFIC("pentium_m", 'K', "+cmov,+mmx,+sse,+sse2") -CPU_SPECIFIC("pentium_4_sse3", 'L', "+cmov,+mmx,+sse,+sse2,+sse3") -CPU_SPECIFIC("core_2_duo_ssse3", 'M', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3") -CPU_SPECIFIC("core_2_duo_sse4_1", 'N', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1") -CPU_SPECIFIC("atom", 'O', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+movbe") -CPU_SPECIFIC("atom_sse4_2", 'c', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt") -CPU_SPECIFIC("core_i7_sse4_2", 'P', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt") -CPU_SPECIFIC("core_aes_pclmulqdq", 'Q', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt") -CPU_SPECIFIC("atom_sse4_2_movbe", 'd', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt") -CPU_SPECIFIC("goldmont", 'i', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt") -CPU_SPECIFIC("sandybridge", 'R', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt,+avx") -CPU_SPECIFIC_ALIAS("core_2nd_gen_avx", "sandybridge") -CPU_SPECIFIC("ivybridge", 'S', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+popcnt,+f16c,+avx") -CPU_SPECIFIC_ALIAS("core_3rd_gen_avx", "ivybridge") -CPU_SPECIFIC("haswell", 'V', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2") -CPU_SPECIFIC_ALIAS("core_4th_gen_avx", "haswell") -CPU_SPECIFIC("core_4th_gen_avx_tsx", 'W', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2") -CPU_SPECIFIC("broadwell", 'X', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+adx") -CPU_SPECIFIC_ALIAS("core_5th_gen_avx", "broadwell") -CPU_SPECIFIC("core_5th_gen_avx_tsx", 'Y', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+adx") -CPU_SPECIFIC("knl", 'Z', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+avx512f,+adx,+avx512er,+avx512pf,+avx512cd") -CPU_SPECIFIC_ALIAS("mic_avx512", "knl") -CPU_SPECIFIC("skylake", 'b', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+adx,+mpx") -CPU_SPECIFIC( "skylake_avx512", 'a', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+avx512dq,+avx512f,+adx,+avx512cd,+avx512bw,+avx512vl,+clwb") -CPU_SPECIFIC("cannonlake", 'e', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+avx512dq,+avx512f,+adx,+avx512ifma,+avx512cd,+avx512bw,+avx512vl,+avx512vbmi") -CPU_SPECIFIC("knm", 'j', "+cmov,+mmx,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+movbe,+popcnt,+f16c,+avx,+fma,+bmi,+lzcnt,+avx2,+avx512f,+adx,+avx512er,+avx512pf,+avx512cd,+avx5124fmaps,+avx5124vnniw,+avx512vpopcntdq") - -#undef CPU_SPECIFIC_ALIAS -#undef CPU_SPECIFIC -#undef PROC_64_BIT -#undef PROC_32_BIT -#undef FEATURE diff --git a/clang/include/clang/Basic/riscv_vector.td b/clang/include/clang/Basic/riscv_vector.td index 48c032dd142..cc242da7f1c 100644 --- a/clang/include/clang/Basic/riscv_vector.td +++ b/clang/include/clang/Basic/riscv_vector.td @@ -170,16 +170,27 @@ class RVVBuiltin Log2LMUL = [0, 1, 2, 3, -1, -2, -3]; @@ -204,13 +215,18 @@ class RVVBuiltin { } let HasNoMaskedOverloaded = false, + HasPolicy = false, ManualCodegen = [{ IntrinsicTypes = {ResultType, Ops[1]->getType()}; Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo()); @@ -568,10 +585,24 @@ let HasNoMaskedOverloaded = false, Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo()); }] in { class RVVVLEMaskBuiltin : RVVBuiltin<"m", "mPCUe", "c"> { - let Name = "vle1_v"; - let IRName = "vle1"; + let Name = "vlm_v"; + let IRName = "vlm"; let HasMask = false; } +} + +let HasNoMaskedOverloaded = false, + ManualCodegen = [{ + IntrinsicTypes = {ResultType, Ops[1]->getType()}; + Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo()); + }], + ManualCodegenMask= [{ + // Move mask to right before vl. + std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); + IntrinsicTypes = {ResultType, Ops[3]->getType()}; + Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo()); + }] in { multiclass RVVVLEBuiltin types> { let Name = NAME # "_v", IRName = "vle", @@ -602,7 +633,7 @@ multiclass RVVVLEFFBuiltin types> { llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0}); // Store new_vl. clang::CharUnits Align = - CGM.getNaturalTypeAlignment(getContext().getSizeType()); + CGM.getNaturalPointeeTypeAlignment(E->getArg(1)->getType()); Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {1}), Address(NewVL, Align)); return V; @@ -612,6 +643,7 @@ multiclass RVVVLEFFBuiltin types> { { // Move mask to right before vl. std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); IntrinsicTypes = {ResultType, Ops[4]->getType()}; Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo()); Value *NewVL = Ops[2]; @@ -621,7 +653,7 @@ multiclass RVVVLEFFBuiltin types> { llvm::Value *V = Builder.CreateExtractValue(LoadValue, {0}); // Store new_vl. clang::CharUnits Align = - CGM.getNaturalTypeAlignment(getContext().getSizeType()); + CGM.getNaturalPointeeTypeAlignment(E->getArg(3)->getType()); Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {1}), Address(NewVL, Align)); return V; @@ -649,6 +681,7 @@ multiclass RVVVLSEBuiltin types> { ManualCodegenMask= [{ // Move mask to right before vl. std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); IntrinsicTypes = {ResultType, Ops[4]->getType()}; Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo()); }] in { @@ -669,6 +702,7 @@ multiclass RVVIndexedLoad { ManualCodegenMask = [{ // Move mask to right before vl. std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); IntrinsicTypes = {ResultType, Ops[2]->getType(), Ops[4]->getType()}; Ops[1] = Builder.CreateBitCast(Ops[1], ResultType->getPointerTo()); }] in { @@ -688,6 +722,7 @@ multiclass RVVIndexedLoad { } let HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ // Builtin: (ptr, value, vl). Intrinsic: (value, ptr, vl) std::swap(Ops[0], Ops[1]); @@ -701,8 +736,8 @@ let HasMaskedOffOperand = false, IntrinsicTypes = {Ops[0]->getType(), Ops[3]->getType()}; }] in { class RVVVSEMaskBuiltin : RVVBuiltin<"m", "0PUem", "c"> { - let Name = "vse1_v"; - let IRName = "vse1"; + let Name = "vsm_v"; + let IRName = "vsm"; let HasMask = false; } multiclass RVVVSEBuiltin types> { @@ -724,6 +759,7 @@ multiclass RVVVSSEBuiltin types> { IRName = "vsse", IRNameMask = "vsse_mask", HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ // Builtin: (ptr, stride, value, vl). Intrinsic: (value, ptr, stride, vl) std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); @@ -747,6 +783,7 @@ multiclass RVVVSSEBuiltin types> { multiclass RVVIndexedStore { let HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ // Builtin: (ptr, index, value, vl). Intrinsic: (value, ptr, index, vl) std::rotate(Ops.begin(), Ops.begin() + 2, Ops.begin() + 3); @@ -805,14 +842,14 @@ multiclass RVVUnitStridedSegLoad { ManualCodegen = [{ { // builtin: (val0 address, val1 address, ..., ptr, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[NF + 1]->getType()}; // intrinsic: (ptr, vl) llvm::Value *Operands[] = {Ops[NF], Ops[NF + 1]}; llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -825,7 +862,7 @@ multiclass RVVUnitStridedSegLoad { { // builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, vl) // intrinsic: (maskedoff0, ..., ptr, mask, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[2 * NF + 2]->getType()}; SmallVector Operands; for (unsigned I = 0; I < NF; ++I) @@ -833,11 +870,12 @@ multiclass RVVUnitStridedSegLoad { Operands.push_back(Ops[2 * NF + 1]); Operands.push_back(Ops[NF]); Operands.push_back(Ops[2 * NF + 2]); - assert(Operands.size() == NF + 3); + Operands.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); + assert(Operands.size() == NF + 4); llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -875,15 +913,15 @@ multiclass RVVUnitStridedSegLoadFF { ManualCodegen = [{ { // builtin: (val0 address, val1 address, ..., ptr, new_vl, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[NF + 2]->getType()}; // intrinsic: (ptr, vl) llvm::Value *Operands[] = {Ops[NF], Ops[NF + 2]}; Value *NewVL = Ops[NF + 1]; llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); for (unsigned I = 0; I < NF; ++I) { Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), Address(Ops[I], Align)); @@ -897,7 +935,7 @@ multiclass RVVUnitStridedSegLoadFF { { // builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, new_vl, vl) // intrinsic: (maskedoff0, ..., ptr, mask, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[2 * NF + 3]->getType()}; SmallVector Operands; for (unsigned I = 0; I < NF; ++I) @@ -905,12 +943,13 @@ multiclass RVVUnitStridedSegLoadFF { Operands.push_back(Ops[2 * NF + 1]); Operands.push_back(Ops[NF]); Operands.push_back(Ops[2 * NF + 3]); + Operands.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); Value *NewVL = Ops[2 * NF + 2]; - assert(Operands.size() == NF + 3); + assert(Operands.size() == NF + 4); llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); for (unsigned I = 0; I < NF; ++I) { Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), Address(Ops[I], Align)); @@ -949,14 +988,14 @@ multiclass RVVStridedSegLoad { ManualCodegen = [{ { // builtin: (val0 address, val1 address, ..., ptr, stride, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[NF + 2]->getType()}; // intrinsic: (ptr, stride, vl) llvm::Value *Operands[] = {Ops[NF], Ops[NF + 1], Ops[NF + 2]}; llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -969,7 +1008,7 @@ multiclass RVVStridedSegLoad { { // builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, stride, vl) // intrinsic: (maskedoff0, ..., ptr, stride, mask, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[2 * NF + 3]->getType()}; SmallVector Operands; for (unsigned I = 0; I < NF; ++I) @@ -978,11 +1017,12 @@ multiclass RVVStridedSegLoad { Operands.push_back(Ops[2 * NF + 2]); Operands.push_back(Ops[NF]); Operands.push_back(Ops[2 * NF + 3]); - assert(Operands.size() == NF + 4); + Operands.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); + assert(Operands.size() == NF + 5); llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -1015,14 +1055,14 @@ multiclass RVVIndexedSegLoad { ManualCodegen = [{ { // builtin: (val0 address, val1 address, ..., ptr, index, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[NF + 1]->getType(), Ops[NF + 2]->getType()}; // intrinsic: (ptr, index, vl) llvm::Value *Operands[] = {Ops[NF], Ops[NF + 1], Ops[NF + 2]}; llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -1034,7 +1074,7 @@ multiclass RVVIndexedSegLoad { ManualCodegenMask = [{ { // builtin: (val0 address, ..., mask, maskedoff0, ..., ptr, index, vl) - IntrinsicTypes = {Ops[0]->getType()->getPointerElementType(), + IntrinsicTypes = {ConvertType(E->getArg(0)->getType()->getPointeeType()), Ops[2 * NF + 2]->getType(), Ops[2 * NF + 3]->getType()}; // intrinsic: (maskedoff0, ..., ptr, index, mask, vl) SmallVector Operands; @@ -1044,11 +1084,12 @@ multiclass RVVIndexedSegLoad { Operands.push_back(Ops[2 * NF + 2]); Operands.push_back(Ops[NF]); Operands.push_back(Ops[2 * NF + 3]); - assert(Operands.size() == NF + 4); + Operands.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); + assert(Operands.size() == NF + 5); llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); llvm::Value *LoadValue = Builder.CreateCall(F, Operands, ""); - clang::CharUnits Align = CharUnits::fromQuantity( - IntrinsicTypes[0]->getScalarSizeInBits() / 8); + clang::CharUnits Align = + CGM.getNaturalPointeeTypeAlignment(E->getArg(0)->getType()); llvm::Value *V; for (unsigned I = 0; I < NF; ++I) { V = Builder.CreateStore(Builder.CreateExtractValue(LoadValue, {I}), @@ -1094,6 +1135,7 @@ multiclass RVVUnitStridedSegStore { IRNameMask = op # nf # "_mask", NF = nf, HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ { // Builtin: (ptr, val0, val1, ..., vl) @@ -1139,6 +1181,7 @@ multiclass RVVStridedSegStore { IRNameMask = op # nf # "_mask", NF = nf, HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ { // Builtin: (ptr, stride, val0, val1, ..., vl). @@ -1180,6 +1223,7 @@ multiclass RVVIndexedSegStore { IRNameMask = op # nf # "_mask", NF = nf, HasMaskedOffOperand = false, + HasPolicy = false, ManualCodegen = [{ { // Builtin: (ptr, index, val0, val1, ..., vl) @@ -1213,35 +1257,6 @@ multiclass RVVIndexedSegStore { } } -multiclass RVVAMOBuiltinSet { - defvar type_list = !if(has_fp, ["i","l","f","d"], ["i","l"]); - foreach type = type_list in - foreach eew_list = EEWList in { - defvar eew = eew_list[0]; - defvar eew_index = eew_list[1]; - let Name = NAME # "ei" # eew # "_" # "v", - IRName = NAME, - IRNameMask = NAME # "_mask", - HasMaskedOffOperand = false, - ManualCodegen = [{ - // base, bindex, value, vl - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()}; - Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo()); - }], - ManualCodegenMask = [{ - std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); - IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[4]->getType()}; - Ops[0] = Builder.CreateBitCast(Ops[0], ResultType->getPointerTo()); - }] in { - if has_signed then - def : RVVBuiltin<"v", "vPe" # eew_index # "Uvv", type>; - if !and(!not(IsFloat.val), has_unsigned) then - def : RVVBuiltin<"Uv", "UvPUe" # eew_index # "UvUv", type>; - } - } -} - multiclass RVVPseudoUnaryBuiltin { let Name = NAME, IRName = IR, @@ -1259,6 +1274,7 @@ multiclass RVVPseudoUnaryBuiltin { ManualCodegenMask = [{ { std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); // maskedoff, op1, mask, vl IntrinsicTypes = {ResultType, cast(ResultType)->getElementType(), @@ -1289,6 +1305,7 @@ multiclass RVVPseudoVNotBuiltin { ManualCodegenMask = [{ { std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); // maskedoff, op1, mask, vl IntrinsicTypes = {ResultType, cast(ResultType)->getElementType(), @@ -1336,6 +1353,7 @@ multiclass RVVPseudoVFUnaryBuiltin { ManualCodegenMask = [{ { std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1); + Ops.push_back(ConstantInt::get(Ops.back()->getType(), TAIL_UNDISTURBED)); // maskedoff, op1, mask, vl IntrinsicTypes = {ResultType, Ops[1]->getType(), @@ -1368,6 +1386,7 @@ multiclass RVVPseudoVWCVTBuiltingetType(), TAIL_UNDISTURBED)); // maskedoff, op1, mask, vl IntrinsicTypes = {ResultType, Ops[1]->getType(), @@ -1403,6 +1422,7 @@ multiclass RVVPseudoVNCVTBuiltingetType(), TAIL_UNDISTURBED)); // maskedoff, op1, mask, vl IntrinsicTypes = {ResultType, Ops[1]->getType(), @@ -1422,7 +1442,7 @@ multiclass RVVPseudoVNCVTBuiltin; defm vle16: RVVVLEBuiltin<["s","x"]>; defm vle32: RVVVLEBuiltin<["i","f"]>; defm vle64: RVVVLEBuiltin<["l","d"]>; -def vse1 : RVVVSEMaskBuiltin; +def vsm : RVVVSEMaskBuiltin; defm vse8 : RVVVSEBuiltin<["c"]>; defm vse16: RVVVSEBuiltin<["s","x"]>; defm vse32: RVVVSEBuiltin<["i","f"]>; @@ -1541,19 +1561,6 @@ defm : RVVIndexedSegStore<"vsuxseg">; defm : RVVIndexedSegStore<"vsoxseg">; } -// 8. Vector AMO Operations -let RequiredExtension = "Zvamo" in { -defm vamoswap : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true, /* hasFP */ true>; -defm vamoadd : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true>; -defm vamoxor : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true>; -defm vamoand : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true>; -defm vamoor : RVVAMOBuiltinSet< /* hasSigned */ true, /* hasUnsigned */ true>; -defm vamomin : RVVAMOBuiltinSet< /* hasSigned */ true>; -defm vamomax : RVVAMOBuiltinSet< /* hasSigned */ true>; -defm vamominu : RVVAMOBuiltinSet< /* hasSigned */ false, /* hasUnsigned */ true>; -defm vamomaxu : RVVAMOBuiltinSet< /* hasSigned */ false, /* hasUnsigned */ true>; -} - // 12. Vector Integer Arithmetic Instructions // 12.1. Vector Single-Width Integer Add and Subtract defm vadd : RVVIntBinBuiltinSet; @@ -1596,7 +1603,7 @@ let Log2LMUL = [-3, -2, -1, 0] in { } // 12.4. Vector Integer Add-with-Carry / Subtract-with-Borrow Instructions -let HasMask = false in { +let HasMask = false, HasPolicy = false in { defm vadc : RVVCarryinBuiltinSet; defm vmadc : RVVCarryOutInBuiltinSet<"vmadc_carry_in">; defm vmadc : RVVIntMaskOutBuiltinSet; @@ -1624,6 +1631,7 @@ defm vncvt_x_x_w : RVVPseudoVNCVTBuiltin<"vnsrl", "vncvt_x", "csi", ["Uv", "UvUw"]]>; // 12.8. Vector Integer Comparison Instructions +let HasPolicy = false in { defm vmseq : RVVIntMaskOutBuiltinSet; defm vmsne : RVVIntMaskOutBuiltinSet; defm vmsltu : RVVUnsignedMaskOutBuiltinSet; @@ -1634,6 +1642,7 @@ defm vmsgtu : RVVUnsignedMaskOutBuiltinSet; defm vmsgt : RVVSignedMaskOutBuiltinSet; defm vmsgeu : RVVUnsignedMaskOutBuiltinSet; defm vmsge : RVVSignedMaskOutBuiltinSet; +} // 12.9. Vector Integer Min/Max Instructions defm vminu : RVVUnsignedBinBuiltinSet; @@ -1669,6 +1678,7 @@ defm vwmulsu : RVVOutOp0Op1BuiltinSet<"vwmulsu", "csi", } // 12.13. Vector Single-Width Integer Multiply-Add Instructions +let HasPolicy = false in { defm vmacc : RVVIntTerBuiltinSet; defm vnmsac : RVVIntTerBuiltinSet; defm vmadd : RVVIntTerBuiltinSet; @@ -1689,10 +1699,11 @@ defm vwmaccsu : RVVOutOp1Op2BuiltinSet<"vwmaccsu", "csi", defm vwmaccus : RVVOutOp1Op2BuiltinSet<"vwmaccus", "csi", [["vx", "w", "wwUev"]]>; } +} // 12.15. Vector Integer Merge Instructions // C/C++ Operand: (mask, op1, op2, vl), Intrinsic: (op1, op2, mask, vl) -let HasMask = false, +let HasMask = false, HasPolicy = false, ManualCodegen = [{ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3); IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()}; @@ -1705,7 +1716,7 @@ let HasMask = false, } // 12.16. Vector Integer Move Instructions -let HasMask = false in { +let HasMask = false, HasPolicy = false in { let MangledName = "vmv_v" in { defm vmv_v : RVVOutBuiltinSet<"vmv_v_v", "csil", [["v", "Uv", "UvUv"]]>; @@ -1769,6 +1780,7 @@ let Log2LMUL = [-2, -1, 0, 1, 2] in { } // 14.6. Vector Single-Width Floating-Point Fused Multiply-Add Instructions +let HasPolicy = false in { defm vfmacc : RVVFloatingTerBuiltinSet; defm vfnmacc : RVVFloatingTerBuiltinSet; defm vfmsac : RVVFloatingTerBuiltinSet; @@ -1783,6 +1795,7 @@ defm vfwmacc : RVVFloatingWidenTerBuiltinSet; defm vfwnmacc : RVVFloatingWidenTerBuiltinSet; defm vfwmsac : RVVFloatingWidenTerBuiltinSet; defm vfwnmsac : RVVFloatingWidenTerBuiltinSet; +} // 14.8. Vector Floating-Point Square-Root Instruction def vfsqrt : RVVFloatingUnaryVVBuiltin; @@ -1805,32 +1818,34 @@ defm vfneg_v : RVVPseudoVFUnaryBuiltin<"vfsgnjn", "xfd">; defm vfabs_v : RVVPseudoVFUnaryBuiltin<"vfsgnjx", "xfd">; // 14.13. Vector Floating-Point Compare Instructions +let HasPolicy = false in { defm vmfeq : RVVFloatingMaskOutBuiltinSet; defm vmfne : RVVFloatingMaskOutBuiltinSet; defm vmflt : RVVFloatingMaskOutBuiltinSet; defm vmfle : RVVFloatingMaskOutBuiltinSet; defm vmfgt : RVVFloatingMaskOutBuiltinSet; defm vmfge : RVVFloatingMaskOutBuiltinSet; +} // 14.14. Vector Floating-Point Classify Instruction -let Name = "vfclass_v" in +let Name = "vfclass_v", HasPolicy = false in def vfclass : RVVOp0Builtin<"Uv", "Uvv", "xfd">; // 14.15. Vector Floating-Point Merge Instructio // C/C++ Operand: (mask, op1, op2, vl), Builtin: (op1, op2, mask, vl) -let HasMask = false, +let HasMask = false, HasPolicy = false, ManualCodegen = [{ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3); IntrinsicTypes = {ResultType, Ops[1]->getType(), Ops[3]->getType()}; }] in { - defm vmerge : RVVOutOp1BuiltinSet<"vfmerge", "xfd", + defm vmerge : RVVOutOp1BuiltinSet<"vmerge", "xfd", [["vvm", "v", "vmvv"]]>; defm vfmerge : RVVOutOp1BuiltinSet<"vfmerge", "xfd", [["vfm", "v", "vmve"]]>; } // 14.16. Vector Floating-Point Move Instruction -let HasMask = false, HasNoMaskedOverloaded = false in +let HasMask = false, HasNoMaskedOverloaded = false, HasPolicy = false in defm vfmv_v : RVVOutBuiltinSet<"vfmv_v_f", "xfd", [["f", "v", "ve"]]>; @@ -1867,6 +1882,7 @@ let Log2LMUL = [-3, -2, -1, 0, 1, 2] in { // 15. Vector Reduction Operations // 15.1. Vector Single-Width Integer Reduction Instructions +let HasPolicy = false in { defm vredsum : RVVIntReductionBuiltinSet; defm vredmaxu : RVVUnsignedReductionBuiltin; defm vredmax : RVVSignedReductionBuiltin; @@ -1888,22 +1904,23 @@ let HasMaskedOffOperand = false in { // 15.3. Vector Single-Width Floating-Point Reduction Instructions defm vfredmax : RVVFloatingReductionBuiltin; defm vfredmin : RVVFloatingReductionBuiltin; -defm vfredsum : RVVFloatingReductionBuiltin; +defm vfredusum : RVVFloatingReductionBuiltin; defm vfredosum : RVVFloatingReductionBuiltin; // 15.4. Vector Widening Floating-Point Reduction Instructions -defm vfwredsum : RVVFloatingWidenReductionBuiltin; +defm vfwredusum : RVVFloatingWidenReductionBuiltin; defm vfwredosum : RVVFloatingWidenReductionBuiltin; +} // 16. Vector Mask Instructions // 16.1. Vector Mask-Register Logical Instructions def vmand : RVVMaskBinBuiltin; def vmnand : RVVMaskBinBuiltin; -def vmandnot : RVVMaskBinBuiltin; +def vmandn : RVVMaskBinBuiltin; def vmxor : RVVMaskBinBuiltin; def vmor : RVVMaskBinBuiltin; def vmnor : RVVMaskBinBuiltin; -def vmornot : RVVMaskBinBuiltin; +def vmorn : RVVMaskBinBuiltin; def vmxnor : RVVMaskBinBuiltin; // pseudoinstructions def vmclr : RVVMaskNullaryBuiltin; @@ -1911,8 +1928,9 @@ def vmset : RVVMaskNullaryBuiltin; defm vmmv_m : RVVPseudoMaskBuiltin<"vmand", "c">; defm vmnot_m : RVVPseudoMaskBuiltin<"vmnand", "c">; -// 16.2. Vector mask population count vpopc -def vpopc : RVVMaskOp0Builtin<"um">; +let HasPolicy = false in { +// 16.2. Vector count population in mask vcpop.m +def vcpop : RVVMaskOp0Builtin<"um">; // 16.3. vfirst find-first-set mask bit def vfirst : RVVMaskOp0Builtin<"lm">; @@ -1934,10 +1952,11 @@ let HasNoMaskedOverloaded = false in { defm vid : RVVOutBuiltinSet<"vid", "csil", [["v", "v", "v"], ["v", "Uv", "Uv"]]>; } +} // 17. Vector Permutation Instructions // 17.1. Integer Scalar Move Instructions -let HasMask = false in { +let HasMask = false, HasPolicy = false in { let HasVL = false, MangledName = "vmv_x" in defm vmv_x : RVVOp0BuiltinSet<"vmv_x_s", "csil", [["s", "ve", "ev"], @@ -1949,7 +1968,7 @@ let HasMask = false in { } // 17.2. Floating-Point Scalar Move Instructions -let HasMask = false in { +let HasMask = false, HasPolicy = false in { let HasVL = false, MangledName = "vfmv_f" in defm vfmv_f : RVVOp0BuiltinSet<"vfmv_f_s", "xfd", [["s", "ve", "ev"]]>; @@ -1960,10 +1979,12 @@ let HasMask = false in { } // 17.3. Vector Slide Instructions +let HasPolicy = false in { // 17.3.1. Vector Slideup Instructions defm vslideup : RVVSlideBuiltinSet; // 17.3.2. Vector Slidedown Instructions defm vslidedown : RVVSlideBuiltinSet; +} // 17.3.3. Vector Slide1up Instructions defm vslide1up : RVVSlideOneBuiltinSet; @@ -1990,7 +2011,7 @@ defm vrgatherei16 : RVVOutBuiltinSet<"vrgatherei16_vv", "csil", [["vv", "Uv", "UvUv(Log2EEW:4)Uv"]]>; // 17.5. Vector Compress Instruction -let HasMask = false, +let HasMask = false, HasPolicy = false, ManualCodegen = [{ std::rotate(Ops.begin(), Ops.begin() + 1, Ops.begin() + 3); IntrinsicTypes = {ResultType, Ops[3]->getType()}; @@ -2005,7 +2026,7 @@ let HasMask = false, // Miscellaneous let HasMask = false, HasVL = false, IRName = "" in { - let Name = "vreinterpret_v", + let Name = "vreinterpret_v", HasPolicy = false, ManualCodegen = [{ return Builder.CreateBitCast(Ops[0], ResultType); }] in { @@ -2027,7 +2048,7 @@ let HasMask = false, HasVL = false, IRName = "" in { } } - let Name = "vundefined", HasNoMaskedOverloaded = false, + let Name = "vundefined", HasNoMaskedOverloaded = false, HasPolicy = false, ManualCodegen = [{ return llvm::UndefValue::get(ResultType); }] in { @@ -2037,7 +2058,7 @@ let HasMask = false, HasVL = false, IRName = "" in { // LMUL truncation // C/C++ Operand: VecTy, IR Operand: VecTy, Index - let Name = "vlmul_trunc_v", MangledName = "vlmul_trunc", + let Name = "vlmul_trunc_v", MangledName = "vlmul_trunc", HasPolicy = false, ManualCodegen = [{ { ID = Intrinsic::experimental_vector_extract; IntrinsicTypes = {ResultType, Ops[0]->getType()}; @@ -2055,7 +2076,7 @@ let HasMask = false, HasVL = false, IRName = "" in { // LMUL extension // C/C++ Operand: SubVecTy, IR Operand: VecTy, SubVecTy, Index - let Name = "vlmul_ext_v", MangledName = "vlmul_ext", + let Name = "vlmul_ext_v", MangledName = "vlmul_ext", HasPolicy = false, ManualCodegen = [{ ID = Intrinsic::experimental_vector_insert; IntrinsicTypes = {ResultType, Ops[0]->getType()}; @@ -2073,11 +2094,16 @@ let HasMask = false, HasVL = false, IRName = "" in { } } - let Name = "vget_v", + let Name = "vget_v", HasPolicy = false, ManualCodegen = [{ { ID = Intrinsic::experimental_vector_extract; - ScalableVectorType *VecTy = cast(ResultType); + auto *VecTy = cast(ResultType); + auto *OpVecTy = cast(Ops[0]->getType()); + // Mask to only valid indices. + unsigned MaxIndex = OpVecTy->getMinNumElements() / VecTy->getMinNumElements(); + assert(isPowerOf2_32(MaxIndex)); + Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1); Ops[1] = Builder.CreateMul(Ops[1], ConstantInt::get(Ops[1]->getType(), VecTy->getMinNumElements())); @@ -2086,17 +2112,22 @@ let HasMask = false, HasVL = false, IRName = "" in { } }] in { foreach dst_lmul = ["(SFixedLog2LMUL:0)", "(SFixedLog2LMUL:1)", "(SFixedLog2LMUL:2)"] in { - def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilfd", dst_lmul # "v">; + def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "vvKz", "csilxfd", dst_lmul # "v">; def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "UvUvKz", "csil", dst_lmul # "Uv">; } } - let Name = "vset_v", Log2LMUL = [0, 1, 2], + let Name = "vset_v", Log2LMUL = [0, 1, 2], HasPolicy = false, ManualCodegen = [{ { ID = Intrinsic::experimental_vector_insert; IntrinsicTypes = {ResultType, Ops[2]->getType()}; - ScalableVectorType *VecTy = cast(Ops[2]->getType()); + auto *ResVecTy = cast(ResultType); + auto *VecTy = cast(Ops[2]->getType()); + // Mask to only valid indices. + unsigned MaxIndex = ResVecTy->getMinNumElements() / VecTy->getMinNumElements(); + assert(isPowerOf2_32(MaxIndex)); + Ops[1] = Builder.CreateAnd(Ops[1], MaxIndex - 1); Ops[1] = Builder.CreateMul(Ops[1], ConstantInt::get(Ops[1]->getType(), VecTy->getMinNumElements())); @@ -2105,8 +2136,14 @@ let HasMask = false, HasVL = false, IRName = "" in { } }] in { foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in { - def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilfd">; + def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfd">; def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "Uv" # dst_lmul #"UvKzUv", "csil">; } } } + +let HeaderCode = [{ +#define VE_TAIL_UNDISTURBED 0 +#define VE_TAIL_AGNOSTIC 1 +}] in +def policy : RVVHeader; diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h index f9d056ed8b1..26587e73bf6 100644 --- a/clang/include/clang/CodeGen/ModuleBuilder.h +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -74,6 +74,10 @@ public: /// This may return null if there was no matching declaration. const Decl *GetDeclForMangledName(llvm::StringRef MangledName); + /// Given a global declaration, return a mangled name for this declaration + /// which has been added to this code generator via a Handle method. + llvm::StringRef GetMangledName(GlobalDecl GD); + /// Return the LLVM address of the given global entity. /// /// \param isForDefinition If true, the caller intends to define the diff --git a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h index 4475807dfce..d879b6411c9 100644 --- a/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h +++ b/clang/include/clang/DirectoryWatcher/DirectoryWatcher.h @@ -20,7 +20,7 @@ namespace clang { /// Provides notifications for file changes in a directory. /// /// Invokes client-provided function on every filesystem event in the watched -/// directory. Initially the the watched directory is scanned and for every file +/// directory. Initially the watched directory is scanned and for every file /// found, an event is synthesized as if the file was added. /// /// This is not a general purpose directory monitoring tool - list of diff --git a/clang/include/clang/Driver/Distro.h b/clang/include/clang/Driver/Distro.h index 0d2a0939639..2723f75e894 100644 --- a/clang/include/clang/Driver/Distro.h +++ b/clang/include/clang/Driver/Distro.h @@ -37,6 +37,7 @@ public: DebianStretch, DebianBuster, DebianBullseye, + DebianBookworm, Exherbo, RHEL5, RHEL6, @@ -72,6 +73,7 @@ public: UbuntuGroovy, UbuntuHirsute, UbuntuImpish, + UbuntuJammy, UnknownDistro }; @@ -119,11 +121,11 @@ public: bool IsOpenSUSE() const { return DistroVal == OpenSUSE; } bool IsDebian() const { - return DistroVal >= DebianLenny && DistroVal <= DebianBullseye; + return DistroVal >= DebianLenny && DistroVal <= DebianBookworm; } bool IsUbuntu() const { - return DistroVal >= UbuntuHardy && DistroVal <= UbuntuImpish; + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuJammy; } bool IsAlpineLinux() const { return DistroVal == AlpineLinux; } diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index da7e8386a15..8b1f7091e70 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -253,6 +253,14 @@ public: /// or when using the -gen-reproducer driver flag. unsigned GenReproducer : 1; + // getFinalPhase - Determine which compilation mode we are in and record + // which option we used to determine the final phase. + // TODO: Much of what getFinalPhase returns are not actually true compiler + // modes. Fold this functionality into Types::getCompilationPhases and + // handleArguments. + phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, + llvm::opt::Arg **FinalPhaseArg = nullptr) const; + private: /// Certain options suppress the 'no input files' warning. unsigned SuppressMissingInputWarning : 1; @@ -270,14 +278,6 @@ private: llvm::opt::DerivedArgList * TranslateInputArgs(const llvm::opt::InputArgList &Args) const; - // getFinalPhase - Determine which compilation mode we are in and record - // which option we used to determine the final phase. - // TODO: Much of what getFinalPhase returns are not actually true compiler - // modes. Fold this functionality into Types::getCompilationPhases and - // handleArguments. - phases::ID getFinalPhase(const llvm::opt::DerivedArgList &DAL, - llvm::opt::Arg **FinalPhaseArg = nullptr) const; - // handleArguments - All code related to claiming and printing diagnostics // related to arguments to the driver are done here. void handleArguments(Compilation &C, llvm::opt::DerivedArgList &Args, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 5a9fd078390..9bde64cf49f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -272,7 +272,7 @@ class MigratorOpts // Args.hasArg(OPT_ffoo) can be used to check that the flag is enabled. // This is useful if the option is usually disabled. // Use this only when the option cannot be declared via BoolFOption. -multiclass OptInFFlag flags=[]> { def f#NAME : Flag<["-"], "f"#name>, Flags<[CC1Option] # flags>, Group, HelpText; @@ -283,7 +283,7 @@ multiclass OptInFFlag flags=[]> { def f#NAME : Flag<["-"], "f"#name>, Flags, Group, HelpText; @@ -291,6 +291,27 @@ multiclass OptOutFFlag, HelpText; } +// A boolean option which is opt-in in FC1. The positive option exists in FC1 and +// Args.hasArg(OPT_ffoo) can be used to check that the flag is enabled. +// This is useful if the option is usually disabled. +multiclass OptInFC1FFlag flags=[]> { + def f#NAME : Flag<["-"], "f"#name>, Flags<[FC1Option] # flags>, + Group, HelpText; + def fno_#NAME : Flag<["-"], "fno-"#name>, Flags, + Group, HelpText; +} + +// A boolean option which is opt-out in FC1. The negative option exists in FC1 and +// Args.hasArg(OPT_fno_foo) can be used to check that the flag is disabled. +multiclass OptOutFC1FFlag flags=[]> { + def f#NAME : Flag<["-"], "f"#name>, Flags, + Group, HelpText; + def fno_#NAME : Flag<["-"], "fno-"#name>, Flags<[FC1Option] # flags>, + Group, HelpText; +} + // Creates a positive and negative flags where both of them are prefixed with // "m", have help text specified for positive and negative option, and a Group // optionally specified by the opt_group argument, otherwise Group. @@ -386,8 +407,7 @@ class MarshalledFlagRec : Flag<["-"], flag.Spelling>, Flags, HelpText, MarshallingInfoBooleanFlag, + other.ValueAsCode, other.RecordName>, ImpliedByAnyOf {} // Generates TableGen records for two command line flags that control the same @@ -467,7 +487,6 @@ defvar render_script = LangOpts<"RenderScript">; defvar hip = LangOpts<"HIP">; defvar gnu_mode = LangOpts<"GNUMode">; defvar asm_preprocessor = LangOpts<"AsmPreprocessor">; -defvar cpp_modules = LangOpts<"CPlusPlusModules">; defvar std = !strconcat("LangStandard::getLangStandardForKind(", lang_std.KeyPath, ")"); @@ -598,12 +617,15 @@ def objcmt_migrate_designated_init : Flag<["-"], "objcmt-migrate-designated-init HelpText<"Enable migration to infer NS_DESIGNATED_INITIALIZER for initializer methods">, MarshallingInfoBitfieldFlag, "FrontendOptions::ObjCMT_DesignatedInitializer">; -def objcmt_whitelist_dir_path: Joined<["-"], "objcmt-whitelist-dir-path=">, Flags<[CC1Option]>, +def objcmt_allowlist_dir_path: Joined<["-"], "objcmt-allowlist-dir-path=">, Flags<[CC1Option]>, HelpText<"Only modify files with a filename contained in the provided directory path">, - MarshallingInfoString>; + MarshallingInfoString>; +def : Joined<["-"], "objcmt-whitelist-dir-path=">, Flags<[CC1Option]>, + HelpText<"Alias for -objcmt-allowlist-dir-path">, + Alias; // The misspelt "white-list" [sic] alias is due for removal. def : Joined<["-"], "objcmt-white-list-dir-path=">, Flags<[CC1Option]>, - Alias; + Alias; // Make sure all other -ccc- options are rejected. def ccc_ : Joined<["-"], "ccc-">, Group, Flags<[Unsupported]>; @@ -701,7 +723,7 @@ def ObjC : Flag<["-"], "ObjC">, Flags<[NoXarchOption]>, def O : Joined<["-"], "O">, Group, Flags<[CC1Option]>; def O_flag : Flag<["-"], "O">, Flags<[CC1Option]>, Alias, AliasArgs<["1"]>; def Ofast : Joined<["-"], "Ofast">, Group, Flags<[CC1Option]>; -def P : Flag<["-"], "P">, Flags<[CC1Option]>, Group, +def P : Flag<["-"], "P">, Flags<[CC1Option,FlangOption,FC1Option]>, Group, HelpText<"Disable linemarker output in -E mode">, MarshallingInfoNegativeFlag>; def Qy : Flag<["-"], "Qy">, Flags<[CC1Option]>, @@ -815,7 +837,9 @@ def autocomplete : Joined<["--"], "autocomplete=">; def bind__at__load : Flag<["-"], "bind_at_load">; def bundle__loader : Separate<["-"], "bundle_loader">; def bundle : Flag<["-"], "bundle">; -def b : JoinedOrSeparate<["-"], "b">, Flags<[Unsupported]>; +def b : JoinedOrSeparate<["-"], "b">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass -b to the linker on AIX (only).">, MetaVarName<"">, + Group; def cl_opt_disable : Flag<["-"], "cl-opt-disable">, Group, Flags<[CC1Option]>, HelpText<"OpenCL only. This option disables all optimizations. By default optimizations are enabled.">; def cl_strict_aliasing : Flag<["-"], "cl-strict-aliasing">, Group, Flags<[CC1Option]>, @@ -843,7 +867,8 @@ def cl_no_signed_zeros : Flag<["-"], "cl-no-signed-zeros">, Group, HelpText<"OpenCL only. Allow use of less precise no signed zeros computations in the generated binary.">, MarshallingInfoFlag>; def cl_std_EQ : Joined<["-"], "cl-std=">, Group, Flags<[CC1Option]>, - HelpText<"OpenCL language standard to compile for.">, Values<"cl,CL,cl1.0,CL1.0,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,cl3.0,CL3.0,clc++,CLC++">; + HelpText<"OpenCL language standard to compile for.">, + Values<"cl,CL,cl1.0,CL1.0,cl1.1,CL1.1,cl1.2,CL1.2,cl2.0,CL2.0,cl3.0,CL3.0,clc++,CLC++,clc++1.0,CLC++1.0,clc++2021,CLC++2021">; def cl_denorms_are_zero : Flag<["-"], "cl-denorms-are-zero">, Group, HelpText<"OpenCL only. Allow denormals to be flushed to zero.">; def cl_fp32_correctly_rounded_divide_sqrt : Flag<["-"], "cl-fp32-correctly-rounded-divide-sqrt">, Group, Flags<[CC1Option]>, @@ -1004,7 +1029,7 @@ def fuse_cuid_EQ : Joined<["-"], "fuse-cuid=">, "offloading languages CUDA and HIP: 'hash' (ID's generated by hashing " "file path and command line options) | 'random' (ID's generated as " "random numbers) | 'none' (disabled). Default is 'hash'. This option " - "will be overriden by option '-cuid=[ID]' if it is specified." >; + "will be overridden by option '-cuid=[ID]' if it is specified." >; def libomptarget_amdgcn_bc_path_EQ : Joined<["--"], "libomptarget-amdgcn-bc-path=">, Group, HelpText<"Path to libomptarget-amdgcn bitcode library">; def libomptarget_nvptx_bc_path_EQ : Joined<["--"], "libomptarget-nvptx-bc-path=">, Group, @@ -1064,6 +1089,9 @@ defm access_control : BoolFOption<"access-control", PosFlag>; def falign_functions : Flag<["-"], "falign-functions">, Group; def falign_functions_EQ : Joined<["-"], "falign-functions=">, Group; +def falign_loops_EQ : Joined<["-"], "falign-loops=">, Group, Flags<[CC1Option]>, MetaVarName<"">, + HelpText<"N must be a power of two. Align loops to the boundary">, + MarshallingInfoInt>; def fno_align_functions: Flag<["-"], "fno-align-functions">, Group; defm allow_editor_placeholders : BoolFOption<"allow-editor-placeholders", LangOpts<"AllowEditorPlaceholders">, DefaultFalse, @@ -1250,12 +1278,19 @@ def fprofile_list_EQ : Joined<["-"], "fprofile-list=">, Group, Flags<[CC1Option, CoreOption]>, HelpText<"Filename defining the list of functions/files to instrument">, MarshallingInfoStringVector>; +def fswift_async_fp_EQ : Joined<["-"], "fswift-async-fp=">, + Group, Flags<[CC1Option, CC1AsOption, CoreOption]>, MetaVarName<"">, HelpText<"Specify where to find the compiled intrinsic modules">, - DocBrief<[{This option specifies the location of pre-compiled intrinsic modules, + DocBrief<[{This option specifies the location of pre-compiled intrinsic modules, if they are not in the default location expected by the compiler.}]>; + +defm backslash : OptInFC1FFlag<"backslash", "Specify that backslash in string introduces an escape character">; +defm xor_operator : OptInFC1FFlag<"xor-operator", "Enable .XOR. as a synonym of .NEQV.">; +defm logical_abbreviations : OptInFC1FFlag<"logical-abbreviations", "Enable logical abbreviations">; +defm implicit_none : OptInFC1FFlag<"implicit-none", "No implicit typing allowed unless overridden by IMPLICIT statements">; } def J : JoinedOrSeparate<["-"], "J">, @@ -4562,18 +4663,16 @@ def fdebug_measure_parse_tree : Flag<["-"], "fdebug-measure-parse-tree">, Group< HelpText<"Measure the parse tree">; def fdebug_pre_fir_tree : Flag<["-"], "fdebug-pre-fir-tree">, Group, HelpText<"Dump the pre-FIR tree">; -def fdebug_module_writer : Flag<["-"],"fdebug-module-writer">, +def fdebug_module_writer : Flag<["-"],"fdebug-module-writer">, HelpText<"Enable debug messages while writing module files">; def fget_symbols_sources : Flag<["-"], "fget-symbols-sources">, Group, HelpText<"Dump symbols and their source code locations">; def module_suffix : Separate<["-"], "module-suffix">, Group, MetaVarName<"">, HelpText<"Use as the suffix for module files (the default value is `.mod`)">; -def fanalyzed_objects_for_unparse : Flag<["-"], - "fanalyzed-objects-for-unparse">, Group; -def fno_analyzed_objects_for_unparse : Flag<["-"], - "fno-analyzed-objects-for-unparse">, Group, - HelpText<"Do not use the analyzed objects when unparsing">; +def fno_reformat : Flag<["-"], "fno-reformat">, Group, + HelpText<"Dump the cooked character stream in -E mode">; +defm analyzed_objects_for_unparse : OptOutFC1FFlag<"analyzed-objects-for-unparse", "", "Do not use the analyzed objects when unparsing">; } @@ -4957,9 +5056,9 @@ def mregparm : Separate<["-"], "mregparm">, def msmall_data_limit : Separate<["-"], "msmall-data-limit">, HelpText<"Put global and static data smaller than the limit into a special section">, MarshallingInfoInt>; -def munwind_tables : Flag<["-"], "munwind-tables">, +def funwind_tables_EQ : Joined<["-"], "funwind-tables=">, HelpText<"Generate unwinding tables for all functions">, - MarshallingInfoFlag>; + MarshallingInfoInt>; def mconstructor_aliases : Flag<["-"], "mconstructor-aliases">, HelpText<"Emit complete constructors and destructors as aliases when possible">, MarshallingInfoFlag>; @@ -5037,6 +5136,14 @@ def fsanitize_coverage_stack_depth : Flag<["-"], "fsanitize-coverage-stack-depth">, HelpText<"Enable max stack depth tracing">, MarshallingInfoFlag>; +def fsanitize_coverage_trace_loads + : Flag<["-"], "fsanitize-coverage-trace-loads">, + HelpText<"Enable tracing of loads">, + MarshallingInfoFlag>; +def fsanitize_coverage_trace_stores + : Flag<["-"], "fsanitize-coverage-trace-stores">, + HelpText<"Enable tracing of stores">, + MarshallingInfoFlag>; def fpatchable_function_entry_offset_EQ : Joined<["-"], "fpatchable-function-entry-offset=">, MetaVarName<"">, HelpText<"Generate M NOPs before function entry">, @@ -5231,16 +5338,19 @@ def code_completion_with_fixits : Flag<["-"], "code-completion-with-fixits">, def disable_free : Flag<["-"], "disable-free">, HelpText<"Disable freeing of memory on exit">, MarshallingInfoFlag>; +defm clear_ast_before_backend : BoolOption<"", + "clear-ast-before-backend", + CodeGenOpts<"ClearASTBeforeBackend">, + DefaultFalse, + PosFlag, + NegFlag, + BothFlags<[], " the Clang AST before running backend code generation">>; def enable_noundef_analysis : Flag<["-"], "enable-noundef-analysis">, Group, HelpText<"Enable analyzing function argument and return types for mandatory definedness">, MarshallingInfoFlag>; def discard_value_names : Flag<["-"], "discard-value-names">, HelpText<"Discard value names in LLVM IR">, MarshallingInfoFlag>; -def load : Separate<["-"], "load">, MetaVarName<"">, - HelpText<"Load the named plugin (dynamic shared object)">; -def plugin : Separate<["-"], "plugin">, MetaVarName<"">, - HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; def plugin_arg : JoinedAndSeparate<["-"], "plugin-arg-">, MetaVarName<" ">, HelpText<"Pass to plugin ">; @@ -5253,6 +5363,8 @@ def ast_dump_filter : Separate<["-"], "ast-dump-filter">, " nodes having a certain substring in a qualified name. Use" " -ast-list to list all filterable declaration node names.">, MarshallingInfoString>; +def ast_dump_filter_EQ : Joined<["-"], "ast-dump-filter=">, + Alias; def fno_modules_global_index : Flag<["-"], "fno-modules-global-index">, HelpText<"Do not automatically generate or update the global module index">, MarshallingInfoNegativeFlag>; @@ -5276,6 +5388,12 @@ def fmodules_embed_all_files : Joined<["-"], "fmodules-embed-all-files">, HelpText<"Embed the contents of all files read by this compilation into " "the produced module file.">, MarshallingInfoFlag>; +defm fimplicit_modules_use_lock : BoolOption<"f", "implicit-modules-use-lock", + FrontendOpts<"BuildingImplicitModuleUsesLock">, DefaultTrue, + NegFlag, + PosFlag>; // FIXME: We only need this in C++ modules / Modules TS if we might textually // enter a different module (eg, when building a header unit). def fmodules_local_submodule_visibility : @@ -5283,7 +5401,7 @@ def fmodules_local_submodule_visibility : HelpText<"Enforce name visibility rules across submodules of the same " "top-level module.">, MarshallingInfoFlag>, - ImpliedByAnyOf<[fmodules_ts.KeyPath, cpp_modules.KeyPath]>; + ImpliedByAnyOf<[fmodules_ts.KeyPath, fcxx_modules.KeyPath]>; def fmodules_codegen : Flag<["-"], "fmodules-codegen">, HelpText<"Generate code for uses of this module that assumes an explicit " @@ -5807,6 +5925,12 @@ def init_only : Flag<["-"], "init-only">, HelpText<"Only execute frontend initialization">; } // let Group = Action_Group + +def load : Separate<["-"], "load">, MetaVarName<"">, + HelpText<"Load the named plugin (dynamic shared object)">; +def plugin : Separate<["-"], "plugin">, MetaVarName<"">, + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; + } // let Flags = [CC1Option, FC1Option, NoDriverOption] //===----------------------------------------------------------------------===// @@ -6030,16 +6154,7 @@ def _SLASH_WX_ : CLFlag<"WX-">, HelpText<"Do not treat warnings as errors (default)">, Alias, AliasArgs<["no-error"]>; def _SLASH_w_flag : CLFlag<"w">, HelpText<"Disable all warnings">, Alias; -def _SLASH_wd4005 : CLFlag<"wd4005">, Alias, - AliasArgs<["no-macro-redefined"]>; -def _SLASH_wd4018 : CLFlag<"wd4018">, Alias, - AliasArgs<["no-sign-compare"]>; -def _SLASH_wd4100 : CLFlag<"wd4100">, Alias, - AliasArgs<["no-unused-parameter"]>; -def _SLASH_wd4910 : CLFlag<"wd4910">, Alias, - AliasArgs<["no-dllexport-explicit-instantiation-decl"]>; -def _SLASH_wd4996 : CLFlag<"wd4996">, Alias, - AliasArgs<["no-deprecated-declarations"]>; +def _SLASH_wd : CLCompileJoined<"wd">; def _SLASH_vd : CLJoined<"vd">, HelpText<"Control vtordisp placement">, Alias; def _SLASH_X : CLFlag<"X">, @@ -6175,6 +6290,8 @@ def _SLASH_TC : CLCompileFlag<"TC">, HelpText<"Treat all source files as C">; def _SLASH_Tp : CLCompileJoinedOrSeparate<"Tp">, HelpText<"Treat as C++ source file">, MetaVarName<"">; def _SLASH_TP : CLCompileFlag<"TP">, HelpText<"Treat all source files as C++">; +def _SLASH_diasdkdir : CLJoinedOrSeparate<"diasdkdir">, + HelpText<"Path to the DIA SDK">, MetaVarName<"">; def _SLASH_vctoolsdir : CLJoinedOrSeparate<"vctoolsdir">, HelpText<"Path to the VCToolChain">, MetaVarName<"">; def _SLASH_vctoolsversion : CLJoinedOrSeparate<"vctoolsversion">, @@ -6184,7 +6301,7 @@ def _SLASH_winsdkdir : CLJoinedOrSeparate<"winsdkdir">, def _SLASH_winsdkversion : CLJoinedOrSeparate<"winsdkversion">, HelpText<"Full version of the Windows SDK, defaults to newest found">; def _SLASH_winsysroot : CLJoinedOrSeparate<"winsysroot">, - HelpText<"Same as /vctoolsdir /VC/Tools/MSVC/ /winsdkdir /Windows Kits/10">, + HelpText<"Same as \"/diasdkdir /DIA SDK\" /vctoolsdir /VC/Tools/MSVC/ \"/winsdkdir /Windows Kits/10\"">, MetaVarName<"">; def _SLASH_volatile_iso : Option<["/", "-"], "volatile:iso", KIND_FLAG>, Group<_SLASH_volatile_Group>, Flags<[CLOption, NoXarchOption]>, diff --git a/clang/include/clang/Driver/Phases.h b/clang/include/clang/Driver/Phases.h index ce914dd7051..9003c585735 100644 --- a/clang/include/clang/Driver/Phases.h +++ b/clang/include/clang/Driver/Phases.h @@ -22,11 +22,10 @@ namespace phases { Assemble, Link, IfsMerge, - LastPhase = IfsMerge, }; enum { - MaxNumberOfPhases = LastPhase + 1 + MaxNumberOfPhases = IfsMerge + 1 }; const char *getPhaseName(ID Id); diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index e9e329e7cb5..84bb324775d 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -65,7 +65,8 @@ class SanitizerArgs { public: /// Parses the sanitizer arguments from an argument list. - SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args); + SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + bool DiagnoseErrors = true); bool needsSharedRt() const { return SharedRuntime; } diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 882ae40086c..dad861d586c 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -113,6 +113,13 @@ public: RM_Disabled, }; + struct BitCodeLibraryInfo { + std::string Path; + bool ShouldInternalize; + BitCodeLibraryInfo(StringRef Path, bool ShouldInternalize = true) + : Path(Path), ShouldInternalize(ShouldInternalize) {} + }; + enum FileType { FT_Object, FT_Static, FT_Shared }; private: @@ -155,7 +162,7 @@ private: Tool *getOffloadBundler() const; Tool *getOffloadWrapper() const; - mutable std::unique_ptr SanitizerArguments; + mutable bool SanitizerArgsChecked = false; mutable std::unique_ptr XRayArguments; /// The effective clang triple for the current Job. @@ -259,7 +266,7 @@ public: const Multilib &getMultilib() const { return SelectedMultilib; } - const SanitizerArgs& getSanitizerArgs() const; + SanitizerArgs getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const; const XRayArgs& getXRayArgs() const; @@ -478,15 +485,12 @@ public: virtual bool isPICDefault() const = 0; /// Test whether this toolchain defaults to PIE. - virtual bool isPIEDefault() const = 0; - - /// Test whether this toolchaind defaults to non-executable stacks. - virtual bool isNoExecStackDefault() const; + virtual bool isPIEDefault(const llvm::opt::ArgList &Args) const = 0; /// Tests whether this toolchain forces its default for PIC, PIE or /// non-PIC. If this returns true, any PIC related flags should be ignored - /// and instead the results of \c isPICDefault() and \c isPIEDefault() are - /// used exclusively. + /// and instead the results of \c isPICDefault() and \c isPIEDefault(const + /// llvm::opt::ArgList &Args) are used exclusively. virtual bool isPICDefaultForced() const = 0; /// SupportsProfiling - Does this tool chain support -pg. @@ -681,7 +685,7 @@ public: const llvm::opt::ArgList &Args) const; /// Get paths of HIP device libraries. - virtual llvm::SmallVector + virtual llvm::SmallVector getHIPDeviceLibs(const llvm::opt::ArgList &Args) const; /// Return sanitizers which are available in this toolchain. diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h index c9d63551090..4aecf7ee1e5 100644 --- a/clang/include/clang/Driver/Types.h +++ b/clang/include/clang/Driver/Types.h @@ -111,7 +111,7 @@ namespace types { /// getCompilationPhases - Get the list of compilation phases ('Phases') to be /// done for type 'Id' up until including LastPhase. llvm::SmallVector - getCompilationPhases(ID Id, phases::ID LastPhase = phases::LastPhase); + getCompilationPhases(ID Id, phases::ID LastPhase = phases::IfsMerge); llvm::SmallVector getCompilationPhases(const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, ID Id); diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index c424e79a971..d38bc6e3f0e 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -40,7 +40,11 @@ enum class ParseError { Success = 0, Error, Unsuitable, - BinPackTrailingCommaConflict + BinPackTrailingCommaConflict, + InvalidQualifierSpecified, + DuplicateQualifierSpecified, + MissingQualifierType, + MissingQualifierOrder }; class ParseErrorCategory final : public std::error_category { public: @@ -59,6 +63,7 @@ struct FormatStyle { bool InheritsParentConfig; /// The extra indent or outdent of access modifiers, e.g. ``public:``. + /// \version 3.3 int AccessModifierOffset; /// Different styles for aligning after open brackets. @@ -88,6 +93,7 @@ struct FormatStyle { /// /// This applies to round brackets (parentheses), angle brackets and square /// brackets. + /// \version 3.8 BracketAlignmentStyle AlignAfterOpenBracket; /// Different style for aligning array initializers. @@ -117,6 +123,7 @@ struct FormatStyle { }; /// if not ``None``, when using initialization for an array of structs /// aligns the fields into columns. + /// \version 13 ArrayInitializerAlignmentStyle AlignArrayOfStructures; /// Styles for alignment of consecutive tokens. Tokens can be assignment signs @@ -201,6 +208,7 @@ struct FormatStyle { /// /* some comment */ /// #define bar(y, z) (y + z) /// \endcode + /// \version 9 AlignConsecutiveStyle AlignConsecutiveMacros; /// Style of aligning consecutive assignments. @@ -269,6 +277,7 @@ struct FormatStyle { /// /* A comment. */ /// double e = 4; /// \endcode + /// \version 3.8 AlignConsecutiveStyle AlignConsecutiveAssignments; /// Style of aligning consecutive bit field. @@ -338,6 +347,7 @@ struct FormatStyle { /// /* A comment. */ /// int ee : 3; /// \endcode + /// \version 11 AlignConsecutiveStyle AlignConsecutiveBitFields; /// Style of aligning consecutive declarations. @@ -407,6 +417,7 @@ struct FormatStyle { /// /* A comment. */ /// bool c = false; /// \endcode + /// \version 3.8 AlignConsecutiveStyle AlignConsecutiveDeclarations; /// Different styles for aligning escaped newlines. @@ -441,6 +452,7 @@ struct FormatStyle { }; /// Options for aligning backslashes in escaped newlines. + /// \version 5 EscapedNewlineAlignmentStyle AlignEscapedNewlines; /// Different styles for aligning operands. @@ -479,6 +491,7 @@ struct FormatStyle { /// If ``true``, horizontally align operands of binary and ternary /// expressions. + /// \version 12 OperandAlignmentStyle AlignOperands; /// If ``true``, aligns trailing comments. @@ -487,6 +500,7 @@ struct FormatStyle { /// int a; // My comment a vs. int a; // My comment a /// int b = 2; // comment b int b = 2; // comment about b /// \endcode + /// \version 3.7 bool AlignTrailingComments; /// \brief If a function call or braced initializer list doesn't fit on a @@ -503,22 +517,12 @@ struct FormatStyle { /// c, /// d); /// \endcode + /// \version 9 bool AllowAllArgumentsOnNextLine; - /// \brief If a constructor definition with a member initializer list doesn't - /// fit on a single line, allow putting all member initializers onto the next - /// line, if ```ConstructorInitializerAllOnOneLineOrOnePerLine``` is true. - /// Note that this parameter has no effect if - /// ```ConstructorInitializerAllOnOneLineOrOnePerLine``` is false. - /// \code - /// true: - /// MyClass::MyClass() : - /// member0(0), member1(2) {} - /// - /// false: - /// MyClass::MyClass() : - /// member0(0), - /// member1(2) {} + /// This option is **deprecated**. See ``NextLine`` of + /// ``PackConstructorInitializers``. + /// \version 9 bool AllowAllConstructorInitializersOnNextLine; /// If the function declaration doesn't fit on a line, @@ -536,6 +540,7 @@ struct FormatStyle { /// int d, /// int e); /// \endcode + /// \version 3.3 bool AllowAllParametersOfDeclarationOnNextLine; /// Allow short enums on a single line. @@ -544,12 +549,12 @@ struct FormatStyle { /// enum { A, B } myEnum; /// /// false: - /// enum - /// { + /// enum { /// A, /// B /// } myEnum; /// \endcode + /// \version 12 bool AllowShortEnumsOnASingleLine; /// Different styles for merging short blocks containing at most one @@ -582,6 +587,7 @@ struct FormatStyle { /// Dependent on the value, ``while (true) { continue; }`` can be put on a /// single line. + /// \version 11 ShortBlockStyle AllowShortBlocksOnASingleLine; /// If ``true``, short case labels will be contracted to a single line. @@ -595,6 +601,7 @@ struct FormatStyle { /// return; /// } /// \endcode + /// \version 3.6 bool AllowShortCaseLabelsOnASingleLine; /// Different styles for merging short functions containing at most one @@ -647,6 +654,7 @@ struct FormatStyle { /// Dependent on the value, ``int f() { return 0; }`` can be put on a /// single line. + /// \version 3.5 ShortFunctionStyle AllowShortFunctionsOnASingleLine; /// Different styles for handling short if statements. @@ -717,6 +725,7 @@ struct FormatStyle { }; /// Dependent on the value, ``if (a) return;`` can be put on a single line. + /// \version 9 ShortIfStyle AllowShortIfStatementsOnASingleLine; /// Different styles for merging short lambdas containing at most one @@ -750,10 +759,12 @@ struct FormatStyle { /// Dependent on the value, ``auto lambda []() { return 0; }`` can be put on a /// single line. + /// \version 9 ShortLambdaStyle AllowShortLambdasOnASingleLine; /// If ``true``, ``while (true) continue;`` can be put on a single /// line. + /// \version 3.7 bool AllowShortLoopsOnASingleLine; /// Different ways to break after the function definition return type. @@ -841,9 +852,11 @@ struct FormatStyle { /// The function definition return type breaking style to use. This /// option is **deprecated** and is retained for backwards compatibility. + /// \version 3.7 DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType; /// The function declaration return type breaking style to use. + /// \version 3.8 ReturnTypeBreakingStyle AlwaysBreakAfterReturnType; /// If ``true``, always break before multiline string literals. @@ -858,6 +871,7 @@ struct FormatStyle { /// "bbbb" "cccc"; /// "cccc"; /// \endcode + /// \version 3.4 bool AlwaysBreakBeforeMultilineStrings; /// Different ways to break after the template declaration. @@ -897,6 +911,7 @@ struct FormatStyle { }; /// The template declaration breaking style to use. + /// \version 7 BreakTemplateDeclarationsStyle AlwaysBreakTemplateDeclarations; /// A vector of strings that should be interpreted as attributes/qualifiers @@ -915,6 +930,7 @@ struct FormatStyle { /// AttributeMacros: ['__capability', '__output', '__ununsed'] /// \endcode /// + /// \version 12 std::vector AttributeMacros; /// If ``false``, a function call's arguments will either be all on the @@ -933,6 +949,7 @@ struct FormatStyle { /// aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa); /// } /// \endcode + /// \version 3.7 bool BinPackArguments; /// The style of inserting trailing commas into container literals. @@ -962,6 +979,7 @@ struct FormatStyle { /// // ^ inserted /// ] /// \endcode + /// \version 12 TrailingCommaStyle InsertTrailingCommas; /// If ``false``, a function declaration's or function definition's @@ -976,6 +994,7 @@ struct FormatStyle { /// int aaaaaaaaaaaaaaaaaaaa, /// int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {} /// \endcode + /// \version 3.7 bool BinPackParameters; /// The style of wrapping parameters on the same line (bin-packed) or @@ -1030,6 +1049,7 @@ struct FormatStyle { }; /// The way to wrap binary operators. + /// \version 3.6 BinaryOperatorStyle BreakBeforeBinaryOperators; /// Different ways to attach braces to their surrounding context. @@ -1464,6 +1484,7 @@ struct FormatStyle { }; /// The brace breaking style to use. + /// \version 3.7 BraceBreakingStyle BreakBeforeBraces; /// Different ways to wrap braces after control statements. @@ -1738,6 +1759,7 @@ struct FormatStyle { /// AfterStruct: false /// SplitEmptyFunction: false /// \endcode + /// \version 3.8 BraceWrappingFlags BraceWrapping; /// If ``true``, concept will be placed on a new line. @@ -1749,6 +1771,7 @@ struct FormatStyle { /// false: /// template concept ... /// \endcode + /// \version 13 bool BreakBeforeConceptDeclarations; /// If ``true``, ternary operators will be placed after line breaks. @@ -1763,6 +1786,7 @@ struct FormatStyle { /// firstValue : /// SecondValueVeryVeryVeryVeryLong; /// \endcode + /// \version 3.7 bool BreakBeforeTernaryOperators; /// Different ways to break initializers. @@ -1791,7 +1815,8 @@ struct FormatStyle { BCIS_AfterColon }; - /// The constructor initializers style to use. + /// The break constructor initializers style to use. + /// \version 5 BreakConstructorInitializersStyle BreakConstructorInitializers; /// Break after each annotation on a field in Java files. @@ -1801,6 +1826,7 @@ struct FormatStyle { /// @Mock /// DataLoad loader; /// \endcode + /// \version 3.8 bool BreakAfterJavaFieldAnnotations; /// Allow breaking string literals when formatting. @@ -1814,6 +1840,7 @@ struct FormatStyle { /// const char* x = /// "veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongString"; /// \endcode + /// \version 3.9 bool BreakStringLiterals; /// The column limit. @@ -1821,6 +1848,7 @@ struct FormatStyle { /// A column limit of ``0`` means that there is no column limit. In this case, /// clang-format will respect the input's line breaking decisions within /// statements unless they contradict other rules. + /// \version 3.7 unsigned ColumnLimit; /// A regular expression that describes comments with special meaning, @@ -1830,8 +1858,77 @@ struct FormatStyle { /// // Will leave the following line unaffected /// #include // FOOBAR pragma: keep /// \endcode + /// \version 3.7 std::string CommentPragmas; + /// Different specifiers and qualifiers alignment styles. + enum QualifierAlignmentStyle { + /// Don't change specifiers/qualifiers to either Left or Right alignment + /// (default). + /// \code + /// int const a; + /// const int *a; + /// \endcode + QAS_Leave, + /// Change specifiers/qualifiers to be left-aligned. + /// \code + /// const int a; + /// const int *a; + /// \endcode + QAS_Left, + /// Change specifiers/qualifiers to be right-aligned. + /// \code + /// int const a; + /// int const *a; + /// \endcode + QAS_Right, + /// Change specifiers/qualifiers to be aligned based on ``QualifierOrder``. + /// With: + /// \code{.yaml} + /// QualifierOrder: ['inline', 'static' , 'type', 'const'] + /// \endcode + /// + /// \code + /// + /// int const a; + /// int const *a; + /// \endcode + QAS_Custom + }; + + /// Different ways to arrange specifiers and qualifiers (e.g. const/volatile). + /// \warning + /// Setting ``QualifierAlignment`` to something other than `Leave`, COULD + /// lead to incorrect code formatting due to incorrect decisions made due to + /// clang-formats lack of complete semantic information. + /// As such extra care should be taken to review code changes made by the use + /// of this option. + /// \endwarning + /// \version 14 + QualifierAlignmentStyle QualifierAlignment; + + /// The order in which the qualifiers appear. + /// Order is an array that can contain any of the following: + /// + /// * const + /// * inline + /// * static + /// * constexpr + /// * volatile + /// * restrict + /// * type + /// + /// Note: it MUST contain 'type'. + /// Items to the left of 'type' will be placed to the left of the type and + /// aligned in the order supplied. Items to the right of 'type' will be placed + /// to the right of the type and aligned in the order supplied. + /// + /// \code{.yaml} + /// QualifierOrder: ['inline', 'static', 'type', 'const', 'volatile' ] + /// \endcode + /// \version 14 + std::vector QualifierOrder; + /// Different ways to break inheritance list. enum BreakInheritanceListStyle : unsigned char { /// Break inheritance list before the colon and after the commas. @@ -1869,6 +1966,7 @@ struct FormatStyle { }; /// The inheritance list style to use. + /// \version 7 BreakInheritanceListStyle BreakInheritanceList; /// If ``true``, consecutive namespace declarations will be on the same @@ -1892,30 +1990,17 @@ struct FormatStyle { /// namespace Extra { /// }}} /// \endcode + /// \version 5 bool CompactNamespaces; - // clang-format off - /// If the constructor initializers don't fit on a line, put each - /// initializer on its own line. - /// \code - /// true: - /// SomeClass::Constructor() - /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) { - /// return 0; - /// } - /// - /// false: - /// SomeClass::Constructor() - /// : aaaaaaaa(aaaaaaaa), aaaaaaaa(aaaaaaaa), - /// aaaaaaaa(aaaaaaaaaaaaaaaaaaaaaaaaa) { - /// return 0; - /// } - /// \endcode + /// This option is **deprecated**. See ``CurrentLine`` of + /// ``PackConstructorInitializers``. + /// \version 3.7 bool ConstructorInitializerAllOnOneLineOrOnePerLine; - // clang-format on /// The number of characters to use for indentation of constructor /// initializer lists as well as inheritance lists. + /// \version 3.7 unsigned ConstructorInitializerIndentWidth; /// Indent width for line continuations. @@ -1926,6 +2011,7 @@ struct FormatStyle { /// longFunction( // Again a long comment /// arg); /// \endcode + /// \version 3.7 unsigned ContinuationIndentWidth; /// If ``true``, format braced lists as best suited for C++11 braced @@ -1948,10 +2034,12 @@ struct FormatStyle { /// f(MyMap[{composite, key}]); f(MyMap[{ composite, key }]); /// new int[3]{1, 2, 3}; new int[3]{ 1, 2, 3 }; /// \endcode + /// \version 3.4 bool Cpp11BracedListStyle; /// \brief Analyze the formatted file for the most used line ending (``\r\n`` /// or ``\n``). ``UseCRLF`` is only used as a fallback if none can be derived. + /// \version 11 bool DeriveLineEnding; /// If ``true``, analyze the formatted file for the most common @@ -1959,9 +2047,11 @@ struct FormatStyle { /// Pointer and reference alignment styles are going to be updated according /// to the preferences found in the file. /// ``PointerAlignment`` is then used only as fallback. + /// \version 3.7 bool DerivePointerAlignment; /// Disables formatting completely. + /// \version 3.7 bool DisableFormat; /// Different styles for empty line after access modifiers. @@ -2012,6 +2102,7 @@ struct FormatStyle { /// Defines when to put an empty line after access modifiers. /// ``EmptyLineBeforeAccessModifier`` configuration handles the number of /// empty lines between two access modifiers. + /// \version 14 EmptyLineAfterAccessModifierStyle EmptyLineAfterAccessModifier; /// Different styles for empty line before access modifiers. @@ -2074,6 +2165,7 @@ struct FormatStyle { }; /// Defines in which cases to put empty line before access modifiers. + /// \version 13 EmptyLineBeforeAccessModifierStyle EmptyLineBeforeAccessModifier; /// If ``true``, clang-format detects whether function calls and @@ -2086,8 +2178,56 @@ struct FormatStyle { /// /// NOTE: This is an experimental flag, that might go away or be renamed. Do /// not use this in config files, etc. Use at your own risk. + /// \version 3.7 bool ExperimentalAutoDetectBinPacking; + /// Different ways to try to fit all constructor initializers on a line. + enum PackConstructorInitializersStyle : unsigned char { + /// Always put each constructor initializer on its own line. + /// \code + /// Constructor() + /// : a(), + /// b() + /// \endcode + PCIS_Never, + /// Bin-pack constructor initializers. + /// \code + /// Constructor() + /// : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), + /// cccccccccccccccccccc() + /// \endcode + PCIS_BinPack, + /// Put all constructor initializers on the current line if they fit. + /// Otherwise, put each one on its own line. + /// \code + /// Constructor() : a(), b() + /// + /// Constructor() + /// : aaaaaaaaaaaaaaaaaaaa(), + /// bbbbbbbbbbbbbbbbbbbb(), + /// ddddddddddddd() + /// \endcode + PCIS_CurrentLine, + /// Same as ``PCIS_CurrentLine`` except that if all constructor initializers + /// do not fit on the current line, try to fit them on the next line. + /// \code + /// Constructor() : a(), b() + /// + /// Constructor() + /// : aaaaaaaaaaaaaaaaaaaa(), bbbbbbbbbbbbbbbbbbbb(), ddddddddddddd() + /// + /// Constructor() + /// : aaaaaaaaaaaaaaaaaaaa(), + /// bbbbbbbbbbbbbbbbbbbb(), + /// cccccccccccccccccccc() + /// \endcode + PCIS_NextLine, + }; + + /// The pack constructor initializers style to use. + /// \version 14; + PackConstructorInitializersStyle PackConstructorInitializers; + /// If ``true``, clang-format adds missing namespace end comments for /// short namespaces and fixes invalid existing ones. Short ones are /// controlled by "ShortNamespaceLines". @@ -2098,6 +2238,7 @@ struct FormatStyle { /// bar(); bar(); /// } // namespace a } /// \endcode + /// \version 5 bool FixNamespaceComments; /// A vector of macros that should be interpreted as foreach loops @@ -2115,6 +2256,7 @@ struct FormatStyle { /// \endcode /// /// For example: BOOST_FOREACH. + /// \version 3.7 std::vector ForEachMacros; /// A vector of macros that should be interpreted as conditionals @@ -2135,6 +2277,7 @@ struct FormatStyle { /// /// For example: `KJ_IF_MAYBE /// `_ + /// \version 14 std::vector IfMacros; /// \brief A vector of macros that should be interpreted as type declarations @@ -2151,6 +2294,7 @@ struct FormatStyle { /// \endcode /// /// For example: OpenSSL STACK_OF, BSD LIST_ENTRY. + /// \version 9 std::vector TypenameMacros; /// A vector of macros that should be interpreted as complete @@ -2161,6 +2305,7 @@ struct FormatStyle { /// clang-format aware of such cases. /// /// For example: Q_UNUSED + /// \version 8 std::vector StatementMacros; /// A vector of macros which are used to open namespace blocks. @@ -2173,6 +2318,7 @@ struct FormatStyle { /// \endcode /// /// For example: TESTSUITE + /// \version 9 std::vector NamespaceMacros; /// A vector of macros which are whitespace-sensitive and should not @@ -2189,6 +2335,7 @@ struct FormatStyle { /// \endcode /// /// For example: BOOST_PP_STRINGIZE + /// \version 12 std::vector WhitespaceSensitiveMacros; tooling::IncludeStyle IncludeStyle; @@ -2217,6 +2364,7 @@ struct FormatStyle { /// return 1; return 1; /// } } /// \endcode + /// \version 13 bool IndentAccessModifiers; /// Indent case labels one level from the switch statement. @@ -2235,6 +2383,7 @@ struct FormatStyle { /// plop(); plop(); /// } } /// \endcode + /// \version 3.3 bool IndentCaseLabels; /// Indent case label blocks one level from the case label. @@ -2257,6 +2406,7 @@ struct FormatStyle { /// } /// } /// \endcode + /// \version 11 bool IndentCaseBlocks; /// Indent goto labels. @@ -2273,6 +2423,7 @@ struct FormatStyle { /// return 1; return 1; /// } } /// \endcode + /// \version 10 bool IndentGotoLabels; /// Options for indenting preprocessor directives. @@ -2307,6 +2458,7 @@ struct FormatStyle { }; /// The preprocessor directive indenting style to use. + /// \version 6 PPDirectiveIndentStyle IndentPPDirectives; /// Indents extern blocks @@ -2346,6 +2498,7 @@ struct FormatStyle { }; /// IndentExternBlockStyle is the type of indenting of extern blocks. + /// \version 12 IndentExternBlockStyle IndentExternBlock; /// Indent the requires clause in a template @@ -2364,6 +2517,7 @@ struct FormatStyle { /// //.... /// } /// \endcode + /// \version 13 bool IndentRequires; /// The number of columns to use for indentation. @@ -2377,6 +2531,7 @@ struct FormatStyle { /// } /// } /// \endcode + /// \version 3.7 unsigned IndentWidth; /// Indent if a function definition or declaration is wrapped after the @@ -2390,6 +2545,7 @@ struct FormatStyle { /// LoooooooooooooooooooooooooooooooooooooooongReturnType /// LoooooooooooooooooooooooooooooooongFunctionDeclaration(); /// \endcode + /// \version 3.7 bool IndentWrappedFunctionNames; /// A vector of prefixes ordered by the desired groups for Java imports. @@ -2423,6 +2579,7 @@ struct FormatStyle { /// /// import org.example.ClassD; /// \endcode + /// \version 8 std::vector JavaImportGroups; /// Quotation styles for JavaScript strings. Does not affect template @@ -2449,6 +2606,7 @@ struct FormatStyle { }; /// The JavaScriptQuoteStyle to use for JavaScript strings. + /// \version 3.9 JavaScriptQuoteStyle JavaScriptQuotes; // clang-format off @@ -2464,6 +2622,7 @@ struct FormatStyle { /// false: /// import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,} from "some/module.js" /// \endcode + /// \version 3.9 bool JavaScriptWrapImports; // clang-format on @@ -2475,6 +2634,7 @@ struct FormatStyle { /// bar(); } /// } /// \endcode + /// \version 3.7 bool KeepEmptyLinesAtTheStartOfBlocks; /// Supported languages. @@ -2511,6 +2671,7 @@ struct FormatStyle { bool isJson() const { return Language == LK_Json; } /// Language, this format style is targeted at. + /// \version 3.5 LanguageKind Language; /// Indentation logic for lambda bodies. @@ -2543,16 +2704,17 @@ struct FormatStyle { /// ``OuterScope``. The KJ style guide requires ``OuterScope``. /// `KJ style guide /// `_ + /// \version 13 LambdaBodyIndentationKind LambdaBodyIndentation; /// A regular expression matching macros that start a block. /// \code /// # With: /// MacroBlockBegin: "^NS_MAP_BEGIN|\ - /// NS_TABLE_HEAD$" + /// NS_TABLE_HEAD$" /// MacroBlockEnd: "^\ - /// NS_MAP_END|\ - /// NS_TABLE_.*_END$" + /// NS_MAP_END|\ + /// NS_TABLE_.*_END$" /// /// NS_MAP_BEGIN /// foo(); @@ -2571,9 +2733,11 @@ struct FormatStyle { /// bar(); /// NS_TABLE_FOO_END /// \endcode + /// \version 3.7 std::string MacroBlockBegin; /// A regular expression matching macros that end a block. + /// \version 3.7 std::string MacroBlockEnd; /// The maximum number of consecutive empty lines to keep. @@ -2587,6 +2751,7 @@ struct FormatStyle { /// return i; /// } /// \endcode + /// \version 3.7 unsigned MaxEmptyLinesToKeep; /// Different ways to indent namespace contents. @@ -2624,6 +2789,7 @@ struct FormatStyle { }; /// The indentation used for namespaces. + /// \version 3.7 NamespaceIndentationKind NamespaceIndentation; /// Controls bin-packing Objective-C protocol conformance list @@ -2656,6 +2822,7 @@ struct FormatStyle { /// ddddddddddddd> { /// } /// \endcode + /// \version 7 BinPackStyle ObjCBinPackProtocolList; /// The number of characters to use for indentation of ObjC blocks. @@ -2666,10 +2833,12 @@ struct FormatStyle { /// [self onOperationDone]; /// }]; /// \endcode + /// \version 3.7 unsigned ObjCBlockIndentWidth; /// Add a space after ``@property`` in Objective-C, i.e. use /// ``@property (readonly)`` instead of ``@property(readonly)``. + /// \version 3.7 bool ObjCSpaceAfterProperty; /// Break parameters list into lines when there is nested block @@ -2693,39 +2862,50 @@ struct FormatStyle { /// }] /// } /// \endcode + /// \version 12 bool ObjCBreakBeforeNestedBlockParam; /// Add a space in front of an Objective-C protocol list, i.e. use /// ``Foo `` instead of ``Foo``. + /// \version 3.7 bool ObjCSpaceBeforeProtocolList; /// The penalty for breaking around an assignment operator. + /// \version 5 unsigned PenaltyBreakAssignment; /// The penalty for breaking a function call after ``call(``. + /// \version 3.7 unsigned PenaltyBreakBeforeFirstCallParameter; /// The penalty for each line break introduced inside a comment. + /// \version 3.7 unsigned PenaltyBreakComment; /// The penalty for breaking before the first ``<<``. + /// \version 3.7 unsigned PenaltyBreakFirstLessLess; /// The penalty for each line break introduced inside a string literal. + /// \version 3.7 unsigned PenaltyBreakString; /// The penalty for breaking after template declaration. + /// \version 7 unsigned PenaltyBreakTemplateDeclaration; /// The penalty for each character outside of the column limit. + /// \version 3.7 unsigned PenaltyExcessCharacter; /// Penalty for putting the return type of a function onto its own /// line. + /// \version 3.7 unsigned PenaltyReturnTypeOnItsOwnLine; /// Penalty for each character of whitespace indentation /// (counted relative to leading non-whitespace column). + /// \version 12 unsigned PenaltyIndentedWhitespace; /// The ``&``, ``&&`` and ``*`` alignment style. @@ -2748,6 +2928,7 @@ struct FormatStyle { }; /// Pointer and reference alignment style. + /// \version 3.7 PointerAlignmentStyle PointerAlignment; /// The number of columns to use for indentation of preprocessor statements. @@ -2762,6 +2943,7 @@ struct FormatStyle { /// # define BAR /// #endif /// \endcode + /// \version 14 int PPIndentWidth; /// See documentation of ``RawStringFormats``. @@ -2821,6 +3003,7 @@ struct FormatStyle { /// BasedOnStyle: llvm /// CanonicalDelimiter: 'cc' /// \endcode + /// \version 6 std::vector RawStringFormats; /// \brief The ``&`` and ``&&`` alignment style. @@ -2846,6 +3029,7 @@ struct FormatStyle { /// \brief Reference alignment style (overrides ``PointerAlignment`` for /// references). + /// \version 14 ReferenceAlignmentStyle ReferenceAlignment; // clang-format off @@ -2861,6 +3045,7 @@ struct FormatStyle { /// /* second veryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongComment with plenty of /// * information */ /// \endcode + /// \version 4 bool ReflowComments; // clang-format on @@ -2883,6 +3068,7 @@ struct FormatStyle { /// int bar; int bar; /// } // namespace b } // namespace b /// \endcode + /// \version 14 unsigned ShortNamespaceLines; /// Include sorting options. @@ -2922,6 +3108,7 @@ struct FormatStyle { /// insensitive fashion. /// If ``CaseSensitive``, includes are sorted in an alphabetical or case /// sensitive fashion. + /// \version 4 SortIncludesOptions SortIncludes; /// Position for Java Static imports. @@ -2945,6 +3132,7 @@ struct FormatStyle { /// When sorting Java imports, by default static imports are placed before /// non-static imports. If ``JavaStaticImportAfterImport`` is ``After``, /// static imports are placed after non-static imports. + /// \version 12 SortJavaStaticImportOptions SortJavaStaticImport; /// If ``true``, clang-format will sort using declarations. @@ -2961,6 +3149,7 @@ struct FormatStyle { /// using std::cout; vs. using std::cin; /// using std::cin; using std::cout; /// \endcode + /// \version 5 bool SortUsingDeclarations; /// If ``true``, a space is inserted after C style casts. @@ -2968,6 +3157,7 @@ struct FormatStyle { /// true: false: /// (int) i; vs. (int)i; /// \endcode + /// \version 3.5 bool SpaceAfterCStyleCast; /// If ``true``, a space is inserted after the logical not operator (``!``). @@ -2975,6 +3165,7 @@ struct FormatStyle { /// true: false: /// ! someExpression(); vs. !someExpression(); /// \endcode + /// \version 9 bool SpaceAfterLogicalNot; /// If \c true, a space will be inserted after the 'template' keyword. @@ -2982,6 +3173,7 @@ struct FormatStyle { /// true: false: /// template void foo(); vs. template void foo(); /// \endcode + /// \version 4 bool SpaceAfterTemplateKeyword; /// Different ways to put a space before opening parentheses. @@ -3014,6 +3206,7 @@ struct FormatStyle { }; /// Defines in which cases to put a space before or after pointer qualifiers + /// \version 12 SpaceAroundPointerQualifiersStyle SpaceAroundPointerQualifiers; /// If ``false``, spaces will be removed before assignment operators. @@ -3022,6 +3215,7 @@ struct FormatStyle { /// int a = 5; vs. int a= 5; /// a += 42; a+= 42; /// \endcode + /// \version 3.7 bool SpaceBeforeAssignmentOperators; /// If ``false``, spaces will be removed before case colon. @@ -3031,6 +3225,7 @@ struct FormatStyle { /// case 1 : break; case 1: break; /// } } /// \endcode + /// \version 12 bool SpaceBeforeCaseColon; /// If ``true``, a space will be inserted before a C++11 braced list @@ -3042,6 +3237,7 @@ struct FormatStyle { /// vector { 1, 2, 3 }; vector{ 1, 2, 3 }; /// new int[3] { 1, 2, 3 }; new int[3]{ 1, 2, 3 }; /// \endcode + /// \version 7 bool SpaceBeforeCpp11BracedList; /// If ``false``, spaces will be removed before constructor initializer @@ -3050,6 +3246,7 @@ struct FormatStyle { /// true: false: /// Foo::Foo() : a(a) {} Foo::Foo(): a(a) {} /// \endcode + /// \version 7 bool SpaceBeforeCtorInitializerColon; /// If ``false``, spaces will be removed before inheritance colon. @@ -3057,10 +3254,11 @@ struct FormatStyle { /// true: false: /// class Foo : Bar {} vs. class Foo: Bar {} /// \endcode + /// \version 7 bool SpaceBeforeInheritanceColon; /// Different ways to put a space before opening parentheses. - enum SpaceBeforeParensOptions : unsigned char { + enum SpaceBeforeParensStyle : unsigned char { /// Never put a space before opening parentheses. /// \code /// void f() { @@ -3084,7 +3282,7 @@ struct FormatStyle { /// ForEach and If macros. This is useful in projects where ForEach/If /// macros are treated as function calls instead of control statements. /// ``SBPO_ControlStatementsExceptForEachMacros`` remains an alias for - /// backward compatability. + /// backward compatibility. /// \code /// void f() { /// Q_FOREACH(...) { @@ -3115,11 +3313,100 @@ struct FormatStyle { /// } /// } /// \endcode - SBPO_Always + SBPO_Always, + /// Configure each individual space before parentheses in + /// `SpaceBeforeParensOptions`. + SBPO_Custom, }; /// Defines in which cases to put a space before opening parentheses. - SpaceBeforeParensOptions SpaceBeforeParens; + /// \version 3.5 + SpaceBeforeParensStyle SpaceBeforeParens; + + /// Precise control over the spacing before parentheses. + /// \code + /// # Should be declared this way: + /// SpaceBeforeParens: Custom + /// SpaceBeforeParensOptions: + /// AfterControlStatements: true + /// AfterFunctionDefinitionName: true + /// \endcode + struct SpaceBeforeParensCustom { + /// If ``true``, put space betwee control statement keywords + /// (for/if/while...) and opening parentheses. + /// \code + /// true: false: + /// if (...) {} vs. if(...) {} + /// \endcode + bool AfterControlStatements; + /// If ``true``, put space between foreach macros and opening parentheses. + /// \code + /// true: false: + /// FOREACH (...) vs. FOREACH(...) + /// + /// \endcode + bool AfterForeachMacros; + /// If ``true``, put a space between function declaration name and opening + /// parentheses. + /// \code + /// true: false: + /// void f (); vs. void f(); + /// \endcode + bool AfterFunctionDeclarationName; + /// If ``true``, put a space between function definition name and opening + /// parentheses. + /// \code + /// true: false: + /// void f () {} vs. void f() {} + /// \endcode + bool AfterFunctionDefinitionName; + /// If ``true``, put space between if macros and opening parentheses. + /// \code + /// true: false: + /// IF (...) vs. IF(...) + /// + /// \endcode + bool AfterIfMacros; + /// If ``true``, put a space before opening parentheses only if the + /// parentheses are not empty. + /// \code + /// true: false: + /// void f (int a); vs. void f(); + /// f (a); f(); + /// \endcode + bool BeforeNonEmptyParentheses; + + SpaceBeforeParensCustom() + : AfterControlStatements(false), AfterForeachMacros(false), + AfterFunctionDeclarationName(false), + AfterFunctionDefinitionName(false), AfterIfMacros(false), + BeforeNonEmptyParentheses(false) {} + + bool operator==(const SpaceBeforeParensCustom &Other) const { + return AfterControlStatements == Other.AfterControlStatements && + AfterForeachMacros == Other.AfterForeachMacros && + AfterFunctionDeclarationName == + Other.AfterFunctionDeclarationName && + AfterFunctionDefinitionName == Other.AfterFunctionDefinitionName && + AfterIfMacros == Other.AfterIfMacros && + BeforeNonEmptyParentheses == Other.BeforeNonEmptyParentheses; + } + }; + + /// Control of individual space before parentheses. + /// + /// If ``SpaceBeforeParens`` is set to ``Custom``, use this to specify + /// how each individual space before parentheses case should be handled. + /// Otherwise, this is ignored. + /// \code{.yaml} + /// # Example of usage: + /// SpaceBeforeParens: Custom + /// SpaceBeforeParensOptions: + /// AfterControlStatements: true + /// AfterFunctionDefinitionName: true + /// \endcode + /// \version 14 + SpaceBeforeParensCustom SpaceBeforeParensOptions; /// If ``false``, spaces will be removed before range-based for loop /// colon. @@ -3127,6 +3414,7 @@ struct FormatStyle { /// true: false: /// for (auto v : values) {} vs. for(auto v: values) {} /// \endcode + /// \version 7 bool SpaceBeforeRangeBasedForLoopColon; /// If ``true``, spaces will be inserted into ``{}``. @@ -3135,6 +3423,7 @@ struct FormatStyle { /// void f() { } vs. void f() {} /// while (true) { } while (true) {} /// \endcode + /// \version 11 bool SpaceInEmptyBlock; /// If ``true``, spaces may be inserted into ``()``. @@ -3147,6 +3436,7 @@ struct FormatStyle { /// } } /// } } /// \endcode + /// \version 3.7 bool SpaceInEmptyParentheses; /// The number of spaces before trailing line comments @@ -3163,6 +3453,7 @@ struct FormatStyle { /// } // foo /// } /// \endcode + /// \version 3.7 unsigned SpacesBeforeTrailingComments; /// Styles for adding spacing after ``<`` and before ``>` @@ -3185,6 +3476,7 @@ struct FormatStyle { SIAS_Leave }; /// The SpacesInAnglesStyle to use for template argument lists. + /// \version 14 SpacesInAnglesStyle SpacesInAngles; /// If ``true``, spaces will be inserted around if/for/switch/while @@ -3194,6 +3486,7 @@ struct FormatStyle { /// if ( a ) { ... } vs. if (a) { ... } /// while ( i < 5 ) { ... } while (i < 5) { ... } /// \endcode + /// \version 11 bool SpacesInConditionalStatement; /// If ``true``, spaces are inserted inside container literals (e.g. @@ -3203,6 +3496,7 @@ struct FormatStyle { /// var arr = [ 1, 2, 3 ]; vs. var arr = [1, 2, 3]; /// f({a : 1, b : 2, c : 3}); f({a: 1, b: 2, c: 3}); /// \endcode + /// \version 3.7 bool SpacesInContainerLiterals; /// If ``true``, spaces may be inserted into C style casts. @@ -3210,6 +3504,7 @@ struct FormatStyle { /// true: false: /// x = ( int32 )y vs. x = (int32)y /// \endcode + /// \version 3.7 bool SpacesInCStyleCastParentheses; /// Control of spaces within a single line comment @@ -3223,30 +3518,33 @@ struct FormatStyle { /// How many spaces are allowed at the start of a line comment. To disable the /// maximum set it to ``-1``, apart from that the maximum takes precedence /// over the minimum. - /// \code Minimum = 1 Maximum = -1 - /// // One space is forced + /// \code + /// Minimum = 1 + /// Maximum = -1 + /// // One space is forced /// - /// // but more spaces are possible + /// // but more spaces are possible /// - /// Minimum = 0 - /// Maximum = 0 - /// //Forces to start every comment directly after the slashes + /// Minimum = 0 + /// Maximum = 0 + /// //Forces to start every comment directly after the slashes /// \endcode /// /// Note that in line comment sections the relative indent of the subsequent /// lines is kept, that means the following: /// \code - /// before: after: - /// Minimum: 1 - /// //if (b) { // if (b) { - /// // return true; // return true; - /// //} // } + /// before: after: + /// Minimum: 1 + /// //if (b) { // if (b) { + /// // return true; // return true; + /// //} // } /// - /// Maximum: 0 - /// /// List: ///List: - /// /// - Foo /// - Foo - /// /// - Bar /// - Bar + /// Maximum: 0 + /// /// List: ///List: + /// /// - Foo /// - Foo + /// /// - Bar /// - Bar /// \endcode + /// \version 14 SpacesInLineComment SpacesInLineCommentPrefix; /// If ``true``, spaces will be inserted after ``(`` and before ``)``. @@ -3254,6 +3552,7 @@ struct FormatStyle { /// true: false: /// t f( Deleted & ) & = delete; vs. t f(Deleted &) & = delete; /// \endcode + /// \version 3.7 bool SpacesInParentheses; /// If ``true``, spaces will be inserted after ``[`` and before ``]``. @@ -3264,6 +3563,7 @@ struct FormatStyle { /// int a[ 5 ]; vs. int a[5]; /// std::unique_ptr foo() {} // Won't be affected /// \endcode + /// \version 3.7 bool SpacesInSquareBrackets; /// If ``true``, spaces will be before ``[``. @@ -3273,6 +3573,7 @@ struct FormatStyle { /// int a [5]; vs. int a[5]; /// int a [5][5]; vs. int a[5][5]; /// \endcode + /// \version 11 bool SpaceBeforeSquareBrackets; /// Styles for adding spacing around ``:`` in bitfield definitions. @@ -3301,6 +3602,7 @@ struct FormatStyle { BFCS_After }; /// The BitFieldColonSpacingStyle to use for bitfields. + /// \version 12 BitFieldColonSpacingStyle BitFieldColonSpacing; /// Supported language standards for parsing and formatting C++ constructs. @@ -3335,6 +3637,7 @@ struct FormatStyle { /// c++03: latest: /// vector > x; vs. vector> x; /// \endcode + /// \version 3.7 LanguageStandard Standard; /// Macros which are ignored in front of a statement, as if they were an @@ -3351,9 +3654,11 @@ struct FormatStyle { /// unsigned char data = 'x'; /// emit signal(data); // Now it's fine again. /// \endcode + /// \version 12 std::vector StatementAttributeLikeMacros; /// The number of columns used for tab stops. + /// \version 3.7 unsigned TabWidth; /// Different ways to use tab in formatting. @@ -3375,9 +3680,11 @@ struct FormatStyle { /// \brief Use ``\r\n`` instead of ``\n`` for line breaks. /// Also used as fallback if ``DeriveLineEnding`` is true. + /// \version 11 bool UseCRLF; /// The way to use tab characters in the resulting file. + /// \version 3.7 UseTabStyle UseTab; bool operator==(const FormatStyle &R) const { @@ -3392,8 +3699,6 @@ struct FormatStyle { AlignOperands == R.AlignOperands && AlignTrailingComments == R.AlignTrailingComments && AllowAllArgumentsOnNextLine == R.AllowAllArgumentsOnNextLine && - AllowAllConstructorInitializersOnNextLine == - R.AllowAllConstructorInitializersOnNextLine && AllowAllParametersOfDeclarationOnNextLine == R.AllowAllParametersOfDeclarationOnNextLine && AllowShortEnumsOnASingleLine == R.AllowShortEnumsOnASingleLine && @@ -3424,8 +3729,6 @@ struct FormatStyle { BreakStringLiterals == R.BreakStringLiterals && ColumnLimit == R.ColumnLimit && CommentPragmas == R.CommentPragmas && BreakInheritanceList == R.BreakInheritanceList && - ConstructorInitializerAllOnOneLineOrOnePerLine == - R.ConstructorInitializerAllOnOneLineOrOnePerLine && ConstructorInitializerIndentWidth == R.ConstructorInitializerIndentWidth && ContinuationIndentWidth == R.ContinuationIndentWidth && @@ -3437,6 +3740,7 @@ struct FormatStyle { EmptyLineBeforeAccessModifier == R.EmptyLineBeforeAccessModifier && ExperimentalAutoDetectBinPacking == R.ExperimentalAutoDetectBinPacking && + PackConstructorInitializers == R.PackConstructorInitializers && FixNamespaceComments == R.FixNamespaceComments && ForEachMacros == R.ForEachMacros && IncludeStyle.IncludeBlocks == R.IncludeStyle.IncludeBlocks && @@ -3482,6 +3786,8 @@ struct FormatStyle { PenaltyBreakTemplateDeclaration == R.PenaltyBreakTemplateDeclaration && PointerAlignment == R.PointerAlignment && + QualifierAlignment == R.QualifierAlignment && + QualifierOrder == R.QualifierOrder && RawStringFormats == R.RawStringFormats && ReferenceAlignment == R.ReferenceAlignment && ShortNamespaceLines == R.ShortNamespaceLines && @@ -3497,6 +3803,7 @@ struct FormatStyle { R.SpaceBeforeCtorInitializerColon && SpaceBeforeInheritanceColon == R.SpaceBeforeInheritanceColon && SpaceBeforeParens == R.SpaceBeforeParens && + SpaceBeforeParensOptions == R.SpaceBeforeParensOptions && SpaceAroundPointerQualifiers == R.SpaceAroundPointerQualifiers && SpaceBeforeRangeBasedForLoopColon == R.SpaceBeforeRangeBasedForLoopColon && diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 861b1502032..74e152ea595 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -219,6 +219,9 @@ public: // of the context or else not CompilerInstance specific. bool ExecuteAction(FrontendAction &Act); + /// Load the list of plugins requested in the \c FrontendOptions. + void LoadRequestedPlugins(); + /// } /// @name Compiler Invocation and Options /// { diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 2245439d063..922c84a3bee 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -50,6 +50,11 @@ class HeaderSearchOptions; class PreprocessorOptions; class TargetOptions; +// This lets us create the DiagnosticsEngine with a properly-filled-out +// DiagnosticOptions instance. +std::unique_ptr +CreateAndPopulateDiagOpts(ArrayRef Argv); + /// Fill out Opts based on the options given in Args. /// /// Args must have been created from the OptTable returned by diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h index dfefddfb452..039f6f247b6 100644 --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -270,17 +270,18 @@ public: const std::vector &arg) = 0; enum ActionType { - Cmdline, ///< Action is determined by the cc1 command-line - ReplaceAction, ///< Replace the main action - AddBeforeMainAction, ///< Execute the action before the main action - AddAfterMainAction ///< Execute the action after the main action + CmdlineBeforeMainAction, ///< Execute the action before the main action if + ///< on the command line + CmdlineAfterMainAction, ///< Execute the action after the main action if on + ///< the command line + ReplaceAction, ///< Replace the main action + AddBeforeMainAction, ///< Execute the action before the main action + AddAfterMainAction ///< Execute the action after the main action }; /// Get the action type for this plugin /// - /// \return The action type. If the type is Cmdline then by default the - /// plugin does nothing and what it does is determined by the cc1 - /// command-line. - virtual ActionType getActionType() { return Cmdline; } + /// \return The action type. By default we use CmdlineAfterMainAction. + virtual ActionType getActionType() { return CmdlineAfterMainAction; } }; /// Abstract base class to use for preprocessor-based frontend actions. diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index ff8d4417eaa..545a7e842c4 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -299,6 +299,15 @@ protected: bool hasPCHSupport() const override { return true; } }; +class GetDependenciesByModuleNameAction : public PreprocessOnlyAction { + StringRef ModuleName; + void ExecuteAction() override; + +public: + GetDependenciesByModuleNameAction(StringRef ModuleName) + : ModuleName(ModuleName) {} +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 15c905d712a..1d9d89a28c6 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -289,6 +289,9 @@ public: /// Whether we are performing an implicit module build. unsigned BuildingImplicitModule : 1; + /// Whether to use a filesystem lock when building implicit modules. + unsigned BuildingImplicitModuleUsesLock : 1; + /// Whether we should embed all used files into the PCM file. unsigned ModulesEmbedAllFiles : 1; @@ -370,7 +373,7 @@ public: ObjCMT_MigrateDecls | ObjCMT_PropertyDotSyntax) }; unsigned ObjCMTAction = ObjCMT_None; - std::string ObjCMTWhiteListPath; + std::string ObjCMTAllowListPath; std::string MTMigrateDir; std::string ARCMTMigrateReportOut; @@ -461,9 +464,9 @@ public: SkipFunctionBodies(false), UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false), BuildingImplicitModule(false), - ModulesEmbedAllFiles(false), IncludeTimestamps(true), - UseTemporary(true), AllowPCMWithCompilerErrors(false), - TimeTraceGranularity(500) {} + BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false), + IncludeTimestamps(true), UseTemporary(true), + AllowPCMWithCompilerErrors(false), TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 020cbe2db3d..2dc0fd5963a 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -16,6 +16,9 @@ #include "clang/Interpreter/PartialTranslationUnit.h" +#include "clang/AST/GlobalDecl.h" + +#include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/Support/Error.h" #include @@ -65,6 +68,20 @@ public: return Execute(*PTU); return llvm::Error::success(); } + + /// \returns the \c JITTargetAddress of a \c GlobalDecl. This interface uses + /// the CodeGenModule's internal mangling cache to avoid recomputing the + /// mangled name. + llvm::Expected getSymbolAddress(GlobalDecl GD) const; + + /// \returns the \c JITTargetAddress of a given name as written in the IR. + llvm::Expected + getSymbolAddress(llvm::StringRef IRName) const; + + /// \returns the \c JITTargetAddress of a given name as written in the object + /// file. + llvm::Expected + getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const; }; } // namespace clang diff --git a/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h b/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h index 9bb820156c2..121ca893e31 100644 --- a/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h +++ b/clang/include/clang/Lex/DependencyDirectivesSourceMinimizer.h @@ -39,6 +39,9 @@ enum TokenKind { pp_import, pp_pragma_import, pp_pragma_once, + pp_pragma_push_macro, + pp_pragma_pop_macro, + pp_pragma_include_alias, pp_include_next, pp_if, pp_ifdef, diff --git a/clang/include/clang/Lex/HeaderMap.h b/clang/include/clang/Lex/HeaderMap.h index 53108b00bd1..ca6a49bae3b 100644 --- a/clang/include/clang/Lex/HeaderMap.h +++ b/clang/include/clang/Lex/HeaderMap.h @@ -77,13 +77,6 @@ public: static std::unique_ptr Create(const FileEntry *FE, FileManager &FM); - /// Check to see if the specified relative filename is located in this - /// HeaderMap. If so, open it and return its FileEntry. If RawPath is not - /// NULL and the file is found, RawPath will be set to the raw path at which - /// the file was found in the file system. For example, for a search path - /// ".." and a filename "../file.h" this would be "../../file.h". - Optional LookupFile(StringRef Filename, FileManager &FM) const; - using HeaderMapImpl::dump; using HeaderMapImpl::getFileName; using HeaderMapImpl::lookupFilename; diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 93d6ea72270..b3445703f78 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -20,9 +20,12 @@ #include "clang/Lex/ModuleMap.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Allocator.h" #include #include @@ -48,7 +51,7 @@ class TargetInfo; /// The preprocessor keeps track of this information for each /// file that is \#included. struct HeaderFileInfo { - /// True if this is a \#import'd or \#pragma once file. + /// True if this is a \#import'd file. unsigned isImport : 1; /// True if this is a \#pragma once file. @@ -110,6 +113,14 @@ struct HeaderFileInfo { /// of the framework. StringRef Framework; + /// List of aliases that this header is known as. + /// Most headers should only have at most one alias, but a handful + /// have two. + llvm::SetVector, + llvm::SmallVector, 2>, + llvm::SmallSet, 2>> + Aliases; + HeaderFileInfo() : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), External(false), isModuleHeader(false), isCompilingModuleHeader(false), @@ -119,13 +130,6 @@ struct HeaderFileInfo { /// any. const IdentifierInfo * getControllingMacro(ExternalPreprocessorSource *External); - - /// Determine whether this is a non-default header file info, e.g., - /// it corresponds to an actual header we've included or tried to include. - bool isNonDefault() const { - return isImport || isPragmaOnce || NumIncludes || ControllingMacro || - ControllingMacroID; - } }; /// An external source of header file information, which may supply @@ -161,6 +165,9 @@ class HeaderSearch { /// Header-search options used to initialize this header search. std::shared_ptr HSOpts; + /// Mapping from SearchDir to HeaderSearchOptions::UserEntries indices. + llvm::DenseMap SearchDirToHSEntry; + DiagnosticsEngine &Diags; FileManager &FileMgr; @@ -171,6 +178,9 @@ class HeaderSearch { /// NoCurDirSearch is true, then the check for the file in the current /// directory is suppressed. std::vector SearchDirs; + /// Whether the DirectoryLookup at the corresponding index in SearchDirs has + /// been successfully used to lookup a file. + std::vector SearchDirsUsage; unsigned AngledDirIdx = 0; unsigned SystemDirIdx = 0; bool NoCurDirSearch = false; @@ -269,15 +279,17 @@ public: DiagnosticsEngine &getDiags() const { return Diags; } /// Interface for setting the file search paths. - void SetSearchPaths(const std::vector &dirs, - unsigned angledDirIdx, unsigned systemDirIdx, - bool noCurDirSearch) { + void SetSearchPaths(std::vector dirs, unsigned angledDirIdx, + unsigned systemDirIdx, bool noCurDirSearch, + llvm::DenseMap searchDirToHSEntry) { assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() && "Directory indices are unordered"); - SearchDirs = dirs; + SearchDirs = std::move(dirs); + SearchDirsUsage.assign(SearchDirs.size(), false); AngledDirIdx = angledDirIdx; SystemDirIdx = systemDirIdx; NoCurDirSearch = noCurDirSearch; + SearchDirToHSEntry = std::move(searchDirToHSEntry); //LookupFileCache.clear(); } @@ -285,6 +297,7 @@ public: void AddSearchPath(const DirectoryLookup &dir, bool isAngled) { unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx; SearchDirs.insert(SearchDirs.begin() + idx, dir); + SearchDirsUsage.insert(SearchDirsUsage.begin() + idx, false); if (!isAngled) AngledDirIdx++; SystemDirIdx++; @@ -430,8 +443,8 @@ public: /// \return false if \#including the file will have no effect or true /// if we should include it. bool ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, - bool isImport, bool ModulesEnabled, - Module *M); + bool isImport, bool ModulesEnabled, Module *M, + bool &IsFirstIncludeOfFile); /// Return whether the specified file is a normal header, /// a system header, or a C++ friendly system header. @@ -439,11 +452,10 @@ public: return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; } - /// Mark the specified file as a "once only" file, e.g. due to + /// Mark the specified file as a "once only" file due to /// \#pragma once. void MarkFileIncludeOnce(const FileEntry *File) { HeaderFileInfo &FI = getFileInfo(File); - FI.isImport = true; FI.isPragmaOnce = true; } @@ -453,6 +465,10 @@ public: getFileInfo(File).DirInfo = SrcMgr::C_System; } + void AddFileAlias(const FileEntry *File, StringRef Alias) { + getFileInfo(File).Aliases.insert(Alias); + } + /// Mark the specified file as part of a module. void MarkFileModuleHeader(const FileEntry *FE, ModuleMap::ModuleHeaderRole Role, @@ -473,11 +489,6 @@ public: getFileInfo(File).ControllingMacro = ControllingMacro; } - /// Return true if this is the first time encountering this header. - bool FirstTimeLexingFile(const FileEntry *File) { - return getFileInfo(File).NumIncludes == 1; - } - /// Determine whether this file is intended to be safe from /// multiple inclusions, e.g., it has \#pragma once or a controlling /// macro. @@ -485,13 +496,16 @@ public: /// This routine does not consider the effect of \#import bool isFileMultipleIncludeGuarded(const FileEntry *File); - /// Determine whether the given file is known to have ever been \#imported - /// (or if it has been \#included and we've encountered a \#pragma once). + /// Determine whether the given file is known to have ever been \#imported. bool hasFileBeenImported(const FileEntry *File) { const HeaderFileInfo *FI = getExistingFileInfo(File); return FI && FI->isImport; } + /// Determine which HeaderSearchOptions::UserEntries have been successfully + /// used so far and mark their index with 'true' in the resulting bit vector. + std::vector computeUserEntryUsage() const; + /// This method returns a HeaderMap for the specified /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. const HeaderMap *CreateHeaderMap(const FileEntry *FE); @@ -547,6 +561,8 @@ public: /// /// \param ModuleName The name of the module we're looking for. /// + /// \param ImportLoc Location of the module include/import. + /// /// \param AllowSearch Whether we are allowed to search in the various /// search directories to produce a module definition. If not, this lookup /// will only return an already-known module. @@ -555,7 +571,9 @@ public: /// in subdirectories. /// /// \returns The module with the given name. - Module *lookupModule(StringRef ModuleName, bool AllowSearch = true, + Module *lookupModule(StringRef ModuleName, + SourceLocation ImportLoc = SourceLocation(), + bool AllowSearch = true, bool AllowExtraModuleMapSearch = false); /// Try to find a module map file in the given directory, returning @@ -625,11 +643,14 @@ private: /// but for compatibility with some buggy frameworks, additional attempts /// may be made to find the module under a related-but-different search-name. /// + /// \param ImportLoc Location of the module include/import. + /// /// \param AllowExtraModuleMapSearch Whether we allow to search modulemaps /// in subdirectories. /// /// \returns The module named ModuleName. Module *lookupModule(StringRef ModuleName, StringRef SearchName, + SourceLocation ImportLoc, bool AllowExtraModuleMapSearch = false); /// Retrieve the name of the (to-be-)cached module file that should @@ -694,6 +715,14 @@ private: Module *RequestingModule, ModuleMap::KnownHeader *SuggestedModule); + /// Cache the result of a successful lookup at the given include location + /// using the search path at index `HitIdx`. + void cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, unsigned HitIdx, + SourceLocation IncludeLoc); + /// Note that a lookup at the given include location was successful using the + /// search path at index `HitIdx`. + void noteLookupUsage(unsigned HitIdx, SourceLocation IncludeLoc); + public: /// Retrieve the module map. ModuleMap &getModuleMap() { return ModMap; } @@ -743,6 +772,9 @@ public: search_dir_iterator system_dir_end() const { return SearchDirs.end(); } + /// Get the index of the given search directory. + Optional searchDirIdx(const DirectoryLookup &DL) const; + /// Retrieve a uniqued framework name. StringRef getUniqueFrameworkName(StringRef Framework); diff --git a/clang/include/clang/Lex/HeaderSearchOptions.h b/clang/include/clang/Lex/HeaderSearchOptions.h index 42f3cff8c57..4efdfc26c3c 100644 --- a/clang/include/clang/Lex/HeaderSearchOptions.h +++ b/clang/include/clang/Lex/HeaderSearchOptions.h @@ -14,10 +14,11 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/HashBuilder.h" #include +#include #include #include -#include namespace clang { @@ -256,11 +257,23 @@ inline llvm::hash_code hash_value(const HeaderSearchOptions::Entry &E) { return llvm::hash_combine(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); } +template +inline void addHash(llvm::HashBuilderImpl &HBuilder, + const HeaderSearchOptions::Entry &E) { + HBuilder.add(E.Path, E.Group, E.IsFramework, E.IgnoreSysRoot); +} + inline llvm::hash_code hash_value(const HeaderSearchOptions::SystemHeaderPrefix &SHP) { return llvm::hash_combine(SHP.Prefix, SHP.IsSystemHeader); } +template +inline void addHash(llvm::HashBuilderImpl &HBuilder, + const HeaderSearchOptions::SystemHeaderPrefix &SHP) { + HBuilder.add(SHP.Prefix, SHP.IsSystemHeader); +} + } // namespace clang #endif // LLVM_CLANG_LEX_HEADERSEARCHOPTIONS_H diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index a291520ae5c..ba1706b1d13 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -128,6 +128,9 @@ class Lexer : public PreprocessorLexer { bool HasLeadingEmptyMacro; + /// True if this is the first time we're lexing the input file. + bool IsFirstTimeLexingFile; + // NewLinePtr - A pointer to new line character '\n' being lexed. For '\r\n', // it also points to '\n.' const char *NewLinePtr; @@ -142,19 +145,22 @@ public: /// with the specified preprocessor managing the lexing process. This lexer /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. - Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP); + Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, Preprocessor &PP, + bool IsFirstIncludeOfFile = true); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the /// text range will outlive it, so it doesn't take ownership of it. Lexer(SourceLocation FileLoc, const LangOptions &LangOpts, - const char *BufStart, const char *BufPtr, const char *BufEnd); + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile = true); /// Lexer constructor - Create a new raw lexer object. This object is only /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the /// text range will outlive it, so it doesn't take ownership of it. Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, - const SourceManager &SM, const LangOptions &LangOpts); + const SourceManager &SM, const LangOptions &LangOpts, + bool IsFirstIncludeOfFile = true); Lexer(const Lexer &) = delete; Lexer &operator=(const Lexer &) = delete; @@ -536,7 +542,8 @@ public: bool SkipTrailingWhitespaceAndNewLine); /// Returns true if the given character could appear in an identifier. - static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts); + static bool isAsciiIdentifierContinueChar(char c, + const LangOptions &LangOpts); /// Checks whether new line pointed by Str is preceded by escape /// sequence. @@ -562,6 +569,9 @@ public: static StringRef getIndentationForLine(SourceLocation Loc, const SourceManager &SM); + /// Check if this is the first time we're lexing the input file. + bool isFirstTimeLexingFile() const { return IsFirstTimeLexingFile; } + private: //===--------------------------------------------------------------------===// // Internal implementation interfaces. @@ -573,10 +583,7 @@ private: bool CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr); - /// Given that a token begins with the Unicode character \p C, figure out - /// what kind of token it is and dispatch to the appropriate lexing helper - /// function. - bool LexUnicode(Token &Result, uint32_t C, const char *CurPtr); + bool LexUnicodeIdentifierStart(Token &Result, uint32_t C, const char *CurPtr); /// FormTokenWithChars - When we lex a token, we have identified a span /// starting at BufferPtr, going to TokEnd that forms the token. This method @@ -701,7 +708,11 @@ private: bool IsStringLiteral); // Helper functions to lex the remainder of a token of the specific type. - bool LexIdentifier (Token &Result, const char *CurPtr); + + // This function handles both ASCII and Unicode identifiers after + // the first codepoint of the identifyier has been parsed. + bool LexIdentifierContinue(Token &Result, const char *CurPtr); + bool LexNumericConstant (Token &Result, const char *CurPtr); bool LexStringLiteral (Token &Result, const char *CurPtr, tok::TokenKind Kind); diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h index f131f045a73..32471969f59 100644 --- a/clang/include/clang/Lex/LiteralSupport.h +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -224,7 +224,7 @@ class StringLiteralParser { unsigned UDSuffixOffset; public: StringLiteralParser(ArrayRef StringToks, - Preprocessor &PP, bool Complain = true); + Preprocessor &PP); StringLiteralParser(ArrayRef StringToks, const SourceManager &sm, const LangOptions &features, const TargetInfo &target, diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h index bcf49c57773..76a74f20cc3 100644 --- a/clang/include/clang/Lex/PPCallbacks.h +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -252,9 +252,20 @@ public: } /// Callback invoked when a \#pragma warning directive is read. - virtual void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, - ArrayRef Ids) { - } + enum PragmaWarningSpecifier { + PWS_Default, + PWS_Disable, + PWS_Error, + PWS_Once, + PWS_Suppress, + PWS_Level1, + PWS_Level2, + PWS_Level3, + PWS_Level4, + }; + virtual void PragmaWarning(SourceLocation Loc, + PragmaWarningSpecifier WarningSpec, + ArrayRef Ids) {} /// Callback invoked when a \#pragma warning(push) directive is read. virtual void PragmaWarningPush(SourceLocation Loc, int Level) { @@ -492,6 +503,11 @@ public: Second->PragmaComment(Loc, Kind, Str); } + void PragmaMark(SourceLocation Loc, StringRef Trivia) override { + First->PragmaMark(Loc, Trivia); + Second->PragmaMark(Loc, Trivia); + } + void PragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value) override { First->PragmaDetectMismatch(Loc, Name, Value); @@ -535,7 +551,7 @@ public: Second->PragmaOpenCLExtension(NameLoc, Name, StateLoc, State); } - void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, + void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec, ArrayRef Ids) override { First->PragmaWarning(Loc, WarningSpec, Ids); Second->PragmaWarning(Loc, WarningSpec, Ids); diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 7ab13640ce2..ea96bb12bec 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LEX_PREPROCESSOR_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" @@ -786,6 +787,42 @@ private: using WarnUnusedMacroLocsTy = llvm::SmallDenseSet; WarnUnusedMacroLocsTy WarnUnusedMacroLocs; + /// This is a pair of an optional message and source location used for pragmas + /// that annotate macros like pragma clang restrict_expansion and pragma clang + /// deprecated. This pair stores the optional message and the location of the + /// annotation pragma for use producing diagnostics and notes. + using MsgLocationPair = std::pair; + + struct MacroAnnotationInfo { + SourceLocation Location; + std::string Message; + }; + + struct MacroAnnotations { + llvm::Optional DeprecationInfo; + llvm::Optional RestrictExpansionInfo; + llvm::Optional FinalAnnotationLoc; + + static MacroAnnotations makeDeprecation(SourceLocation Loc, + std::string Msg) { + return MacroAnnotations{MacroAnnotationInfo{Loc, std::move(Msg)}, + llvm::None, llvm::None}; + } + + static MacroAnnotations makeRestrictExpansion(SourceLocation Loc, + std::string Msg) { + return MacroAnnotations{ + llvm::None, MacroAnnotationInfo{Loc, std::move(Msg)}, llvm::None}; + } + + static MacroAnnotations makeFinal(SourceLocation Loc) { + return MacroAnnotations{llvm::None, llvm::None, Loc}; + } + }; + + /// Warning information for macro annotations. + llvm::DenseMap AnnotationInfos; + /// A "freelist" of MacroArg objects that can be /// reused for quick allocation. MacroArgs *MacroArgCache = nullptr; @@ -1331,7 +1368,7 @@ public: /// /// Emits a diagnostic, doesn't enter the file, and returns true on error. bool EnterSourceFile(FileID FID, const DirectoryLookup *Dir, - SourceLocation Loc); + SourceLocation Loc, bool IsFirstIncludeOfFile = true); /// Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. @@ -1953,7 +1990,8 @@ public: /// This either returns the EOF token and returns true, or /// pops a level off the include stack and returns false, at which point the /// client should call lex again. - bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); + bool HandleEndOfFile(Token &Result, SourceLocation Loc, + bool isEndOfMacro = false); /// Callback invoked when the current TokenLexer hits the end of its /// token stream. @@ -2363,12 +2401,14 @@ private: // Pragmas. void HandlePragmaDirective(PragmaIntroducer Introducer); + void ResolvePragmaIncludeInstead(SourceLocation Location) const; public: void HandlePragmaOnce(Token &OnceTok); void HandlePragmaMark(Token &MarkTok); void HandlePragmaPoison(); void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaIncludeInstead(Token &Tok); void HandlePragmaDependency(Token &DependencyTok); void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); @@ -2385,7 +2425,57 @@ public: /// warnings. void markMacroAsUsed(MacroInfo *MI); + void addMacroDeprecationMsg(const IdentifierInfo *II, std::string Msg, + SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert(std::make_pair( + II, + MacroAnnotations::makeDeprecation(AnnotationLoc, std::move(Msg)))); + else + Annotations->second.DeprecationInfo = + MacroAnnotationInfo{AnnotationLoc, std::move(Msg)}; + } + + void addRestrictExpansionMsg(const IdentifierInfo *II, std::string Msg, + SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert( + std::make_pair(II, MacroAnnotations::makeRestrictExpansion( + AnnotationLoc, std::move(Msg)))); + else + Annotations->second.RestrictExpansionInfo = + MacroAnnotationInfo{AnnotationLoc, std::move(Msg)}; + } + + void addFinalLoc(const IdentifierInfo *II, SourceLocation AnnotationLoc) { + auto Annotations = AnnotationInfos.find(II); + if (Annotations == AnnotationInfos.end()) + AnnotationInfos.insert( + std::make_pair(II, MacroAnnotations::makeFinal(AnnotationLoc))); + else + Annotations->second.FinalAnnotationLoc = AnnotationLoc; + } + + const MacroAnnotations &getMacroAnnotations(const IdentifierInfo *II) const { + return AnnotationInfos.find(II)->second; + } + + void emitMacroExpansionWarnings(const Token &Identifier) const { + if (Identifier.getIdentifierInfo()->isDeprecatedMacro()) + emitMacroDeprecationWarning(Identifier); + + if (Identifier.getIdentifierInfo()->isRestrictExpansion() && + !SourceMgr.isInMainFile(Identifier.getLocation())) + emitRestrictExpansionWarning(Identifier); + } + private: + void emitMacroDeprecationWarning(const Token &Identifier) const; + void emitRestrictExpansionWarning(const Token &Identifier) const; + void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const; + Optional getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc); diff --git a/clang/include/clang/Lex/PreprocessorLexer.h b/clang/include/clang/Lex/PreprocessorLexer.h index 03b1cc2c10e..b43197a6031 100644 --- a/clang/include/clang/Lex/PreprocessorLexer.h +++ b/clang/include/clang/Lex/PreprocessorLexer.h @@ -14,11 +14,13 @@ #ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H #define LLVM_CLANG_LEX_PREPROCESSORLEXER_H +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MultipleIncludeOpt.h" #include "clang/Lex/Token.h" -#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" #include namespace clang { @@ -74,6 +76,13 @@ protected: /// we are currently in. SmallVector ConditionalStack; + struct IncludeInfo { + const FileEntry *File; + SourceLocation Location; + }; + // A complete history of all the files included by the current file. + llvm::StringMap IncludeHistory; + PreprocessorLexer() : FID() {} PreprocessorLexer(Preprocessor *pp, FileID fid); virtual ~PreprocessorLexer() = default; @@ -175,6 +184,15 @@ public: ConditionalStack.clear(); ConditionalStack.append(CL.begin(), CL.end()); } + + void addInclude(StringRef Filename, const FileEntry &File, + SourceLocation Location) { + IncludeHistory.insert({Filename, {&File, Location}}); + } + + const llvm::StringMap &getIncludeHistory() const { + return IncludeHistory; + } }; } // namespace clang diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index 99085b98fc7..a7aabc3e1df 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -199,9 +199,6 @@ public: /// build it again. std::shared_ptr FailedModules; - /// A prefix map for __FILE__ and __BASE_FILE__. - std::map> MacroPrefixMap; - /// Contains the currently active skipped range mappings for skipping excluded /// conditional directives. /// diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 8eb3f9029d9..92a703b4217 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -196,6 +196,7 @@ class Parser : public CodeCompletionHandler { std::unique_ptr MSRuntimeChecks; std::unique_ptr MSIntrinsic; std::unique_ptr MSOptimize; + std::unique_ptr MSFenvAccess; std::unique_ptr CUDAForceHostDeviceHandler; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; @@ -1977,6 +1978,9 @@ private: Sema::ConditionKind CK, ForRangeInfo *FRI = nullptr, bool EnterForConditionScope = false); + DeclGroupPtrTy + ParseAliasDeclarationInInitStatement(DeclaratorContext Context, + ParsedAttributesWithRange &Attrs); //===--------------------------------------------------------------------===// // C++ Coroutines @@ -2396,7 +2400,8 @@ private: if (getLangOpts().OpenMP) Actions.startOpenMPLoop(); if (getLangOpts().CPlusPlus) - return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); + return Tok.is(tok::kw_using) || + isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); return isDeclarationSpecifier(true); } @@ -2834,7 +2839,10 @@ private: SourceLocation ScopeLoc, CachedTokens &OpenMPTokens); - IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); + IdentifierInfo *TryParseCXX11AttributeIdentifier( + SourceLocation &Loc, + Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None, + const IdentifierInfo *EnclosingScope = nullptr); void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, SourceLocation *endLoc = nullptr) { @@ -3197,6 +3205,10 @@ private: /// Parses OpenMP context selectors. bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI); + /// Parse an 'append_args' clause for '#pragma omp declare variant'. + bool parseOpenMPAppendArgs( + SmallVectorImpl &InterOpTypes); + /// Parse a `match` clause for an '#pragma omp declare variant'. Return true /// if there was an error. bool parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index 87646ab9502..6b37e3c50db 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -329,6 +329,9 @@ public: /// Code completion inside the filename part of a #include directive. CCC_IncludedFile, + /// Code completion of an attribute name. + CCC_Attribute, + /// An unknown context, in which we are recovering from a parsing /// error and don't know which completions we should give. CCC_Recovery diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 423f4f4ee7b..ed5be2da3ac 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -275,6 +275,7 @@ public: static const TST TST_accum = clang::TST_Accum; static const TST TST_fract = clang::TST_Fract; static const TST TST_float128 = clang::TST_float128; + static const TST TST_ibm128 = clang::TST_ibm128; static const TST TST_bool = clang::TST_bool; static const TST TST_decimal32 = clang::TST_decimal32; static const TST TST_decimal64 = clang::TST_decimal64; diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index 8feb66995f9..679e12ee22d 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -298,8 +298,8 @@ public: /// Create the initialization entity for the result of a function. static InitializedEntity InitializeResult(SourceLocation ReturnLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_Result, ReturnLoc, Type); } static InitializedEntity InitializeStmtExprResult(SourceLocation ReturnLoc, @@ -308,20 +308,20 @@ public: } static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type); } static InitializedEntity InitializeLambdaToBlock(SourceLocation BlockVarLoc, - QualType Type, bool NRVO) { + QualType Type) { return InitializedEntity(EK_LambdaToBlockConversionBlockElement, - BlockVarLoc, Type, NRVO); + BlockVarLoc, Type); } /// Create the initialization entity for an exception object. static InitializedEntity InitializeException(SourceLocation ThrowLoc, - QualType Type, bool NRVO) { - return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); + QualType Type) { + return InitializedEntity(EK_Exception, ThrowLoc, Type); } /// Create the initialization entity for an object allocated via new. @@ -335,8 +335,15 @@ public: } /// Create the initialization entity for a temporary. - static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) { - return InitializeTemporary(TypeInfo, TypeInfo->getType()); + static InitializedEntity InitializeTemporary(ASTContext &Context, + TypeSourceInfo *TypeInfo) { + QualType Type = TypeInfo->getType(); + if (Context.getLangOpts().OpenCLCPlusPlus) { + assert(!Type.hasAddressSpace() && "Temporary already has address space!"); + Type = Context.getAddrSpaceQualType(Type, LangAS::opencl_private); + } + + return InitializeTemporary(TypeInfo, Type); } /// Create the initialization entity for a temporary. @@ -481,7 +488,7 @@ public: /// Determine whether this is an array new with an unknown bound. bool isVariableLengthArrayNew() const { - return getKind() == EK_New && dyn_cast_or_null( + return getKind() == EK_New && isa_and_nonnull( getType()->getAsArrayTypeUnsafe()); } diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 82661cb3d12..88405a63b73 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -469,7 +469,9 @@ class Sema; unrelated_class, bad_qualifiers, lvalue_ref_to_rvalue, - rvalue_ref_to_lvalue + rvalue_ref_to_lvalue, + too_few_initializers, + too_many_initializers, }; // This can be null, e.g. for implicit object arguments. @@ -533,11 +535,17 @@ class Sema; }; /// ConversionKind - The kind of implicit conversion sequence. - unsigned ConversionKind : 30; + unsigned ConversionKind : 31; - /// Whether the target is really a std::initializer_list, and the - /// sequence only represents the worst element conversion. - unsigned StdInitializerListElement : 1; + // Whether the initializer list was of an incomplete array. + unsigned InitializerListOfIncompleteArray : 1; + + /// When initializing an array or std::initializer_list from an + /// initializer-list, this is the array or std::initializer_list type being + /// initialized. The remainder of the conversion sequence, including ToType, + /// describe the worst conversion of an initializer to an element of the + /// array or std::initializer_list. (Note, 'worst' is not well defined.) + QualType InitializerListContainerType; void setKind(Kind K) { destruct(); @@ -568,13 +576,17 @@ class Sema; }; ImplicitConversionSequence() - : ConversionKind(Uninitialized), StdInitializerListElement(false) { + : ConversionKind(Uninitialized), + InitializerListOfIncompleteArray(false), + InitializerListContainerType() { Standard.setAsIdentityConversion(); } ImplicitConversionSequence(const ImplicitConversionSequence &Other) : ConversionKind(Other.ConversionKind), - StdInitializerListElement(Other.StdInitializerListElement) { + InitializerListOfIncompleteArray( + Other.InitializerListOfIncompleteArray), + InitializerListContainerType(Other.InitializerListContainerType) { switch (ConversionKind) { case Uninitialized: break; case StandardConversion: Standard = Other.Standard; break; @@ -670,14 +682,22 @@ class Sema; Standard.setAllToTypes(T); } - /// Whether the target is really a std::initializer_list, and the - /// sequence only represents the worst element conversion. - bool isStdInitializerListElement() const { - return StdInitializerListElement; + // True iff this is a conversion sequence from an initializer list to an + // array or std::initializer. + bool hasInitializerListContainerType() const { + return !InitializerListContainerType.isNull(); } - - void setStdInitializerListElement(bool V = true) { - StdInitializerListElement = V; + void setInitializerListContainerType(QualType T, bool IA) { + InitializerListContainerType = T; + InitializerListOfIncompleteArray = IA; + } + bool isInitializerListOfIncompleteArray() const { + return InitializerListOfIncompleteArray; + } + QualType getInitializerListContainerType() const { + assert(hasInitializerListContainerType() && + "not initializer list container"); + return InitializerListContainerType; } /// Form an "implicit" conversion sequence from nullptr_t to bool, for a @@ -1184,6 +1204,20 @@ class Sema; return Info; } + // Returns false if signature help is relevant despite number of arguments + // exceeding parameters. Specifically, it returns false when + // PartialOverloading is true and one of the following: + // * Function is variadic + // * Function is template variadic + // * Function is an instantiation of template variadic function + // The last case may seem strange. The idea is that if we added one more + // argument, we'd end up with a function similar to Function. Since, in the + // context of signature help and/or code completion, we do not know what the + // type of the next argument (that the user is typing) will be, this is as + // good candidate as we can get, despite the fact that it takes one less + // parameter. + bool shouldEnforceArgLimit(bool PartialOverloading, FunctionDecl *Function); + } // namespace clang #endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h index f47f557adeb..ff2303c84bd 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -67,6 +67,8 @@ struct ParsedAttrInfo { const char *NormalizedFullName; }; ArrayRef Spellings; + // The names of the known arguments of this attribute. + ArrayRef ArgNames; ParsedAttrInfo(AttributeCommonInfo::Kind AttrKind = AttributeCommonInfo::NoSemaHandlerAttribute) @@ -92,11 +94,9 @@ struct ParsedAttrInfo { const Decl *D) const { return true; } - /// Check if this attribute is allowed by the language we are compiling, and - /// issue a diagnostic if not. - virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) const { - return true; - } + /// Check if this attribute is allowed by the language we are compiling. + virtual bool acceptsLangOpts(const LangOptions &LO) const { return true; } + /// Check if this attribute is allowed when compiling for the given target. virtual bool existsInTarget(const TargetInfo &Target) const { return true; @@ -125,6 +125,7 @@ struct ParsedAttrInfo { } static const ParsedAttrInfo &get(const AttributeCommonInfo &A); + static ArrayRef getAllBuiltin(); }; typedef llvm::Registry ParsedAttrInfoRegistry; @@ -628,7 +629,7 @@ public: /// a Spelling enumeration, the value UINT_MAX is returned. unsigned getSemanticSpelling() const; - /// If this is an OpenCL address space attribute returns its representation + /// If this is an OpenCL address space attribute, returns its representation /// in LangAS, otherwise returns default address space. LangAS asOpenCLLangAS() const { switch (getParsedKind()) { @@ -651,7 +652,7 @@ public: } } - /// If this is an OpenCL address space attribute returns its SYCL + /// If this is an OpenCL address space attribute, returns its SYCL /// representation in LangAS, otherwise returns default address space. LangAS asSYCLLangAS() const { switch (getKind()) { @@ -893,7 +894,7 @@ public: ParsedAttr> { iterator() : iterator_adaptor_base(nullptr) {} iterator(VecTy::iterator I) : iterator_adaptor_base(I) {} - reference operator*() { return **I; } + reference operator*() const { return **I; } friend class ParsedAttributesView; }; struct const_iterator @@ -1118,14 +1119,14 @@ enum AttributeDeclKind { inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const ParsedAttr &At) { - DB.AddTaggedVal(reinterpret_cast(At.getAttrName()), + DB.AddTaggedVal(reinterpret_cast(At.getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const ParsedAttr *At) { - DB.AddTaggedVal(reinterpret_cast(At->getAttrName()), + DB.AddTaggedVal(reinterpret_cast(At->getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } @@ -1140,7 +1141,7 @@ template ::value, int> = 0> inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const ACI &CI) { - DB.AddTaggedVal(reinterpret_cast(CI.getAttrName()), + DB.AddTaggedVal(reinterpret_cast(CI.getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } @@ -1150,7 +1151,7 @@ template ::value, int> = 0> inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, const ACI* CI) { - DB.AddTaggedVal(reinterpret_cast(CI->getAttrName()), + DB.AddTaggedVal(reinterpret_cast(CI->getAttrName()), DiagnosticsEngine::ak_identifierinfo); return DB; } diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h index b499ba1e7c2..872951a0829 100644 --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -337,7 +337,7 @@ public: /// isDeclScope - Return true if this is the scope that the specified decl is /// declared in. - bool isDeclScope(const Decl *D) const { return DeclsInScope.count(D) != 0; } + bool isDeclScope(const Decl *D) const { return DeclsInScope.contains(D); } /// Get the entity corresponding to this scope. DeclContext *getEntity() const { diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 98ed75acd9d..ccd15ea6a81 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -175,8 +175,9 @@ public: /// First 'return' statement in the current function. SourceLocation FirstReturnLoc; - /// First C++ 'try' statement in the current function. - SourceLocation FirstCXXTryLoc; + /// First C++ 'try' or ObjC @try statement in the current function. + SourceLocation FirstCXXOrObjCTryLoc; + enum { TryLocIsCXX, TryLocIsObjC, Unknown } FirstTryType = Unknown; /// First SEH '__try' statement in the current function. SourceLocation FirstSEHTryLoc; @@ -446,7 +447,14 @@ public: void setHasCXXTry(SourceLocation TryLoc) { setHasBranchProtectedScope(); - FirstCXXTryLoc = TryLoc; + FirstCXXOrObjCTryLoc = TryLoc; + FirstTryType = TryLocIsCXX; + } + + void setHasObjCTry(SourceLocation TryLoc) { + setHasBranchProtectedScope(); + FirstCXXOrObjCTryLoc = TryLoc; + FirstTryType = TryLocIsObjC; } void setHasSEHTry(SourceLocation TryLoc) { @@ -1001,10 +1009,7 @@ public: return NonODRUsedCapturingExprs.count(CapturingVarExpr); } void removePotentialCapture(Expr *E) { - PotentiallyCapturingExprs.erase( - std::remove(PotentiallyCapturingExprs.begin(), - PotentiallyCapturingExprs.end(), E), - PotentiallyCapturingExprs.end()); + llvm::erase_value(PotentiallyCapturingExprs, E); } void clearPotentialCaptures() { PotentiallyCapturingExprs.clear(); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 83a2d132bf6..43ce5d98321 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -74,7 +74,6 @@ namespace llvm { class APSInt; - template struct DenseMapInfo; template class DenseSet; class SmallBitVector; struct InlineAsmIdentifierInfo; @@ -396,8 +395,8 @@ public: /// /// This is the greatest alignment value supported by load, store, and alloca /// instructions, and global values. - static const unsigned MaxAlignmentExponent = 29; - static const unsigned MaximumAlignment = 1u << MaxAlignmentExponent; + static const unsigned MaxAlignmentExponent = 32; + static const uint64_t MaximumAlignment = 1ull << MaxAlignmentExponent; typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; @@ -914,10 +913,6 @@ public: OpaqueParser = P; } - // Does the work necessary to deal with a SYCL kernel lambda. At the moment, - // this just marks the list of lambdas required to name the kernel. - void AddSYCLKernelLambda(const FunctionDecl *FD); - class DelayedDiagnostics; class DelayedDiagnosticsState { @@ -1128,6 +1123,10 @@ public: /// The C++ "std::coroutine_traits" template, which is defined in /// \ ClassTemplateDecl *StdCoroutineTraitsCache; + /// The namespace where coroutine components are defined. In standard, + /// they are defined in std namespace. And in the previous implementation, + /// they are defined in std::experimental namespace. + NamespaceDecl *CoroTraitsNamespaceCache; /// The C++ "type_info" declaration, which is defined in \. RecordDecl *CXXTypeInfoDecl; @@ -1218,6 +1217,11 @@ public: /// cases in a switch statement). ConstantEvaluated, + /// In addition of being constant evaluated, the current expression + /// occurs in an immediate function context - either a consteval function + /// or a consteval if function. + ImmediateFunctionContext, + /// The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. @@ -1306,8 +1310,14 @@ public: Context == ExpressionEvaluationContext::UnevaluatedAbstract || Context == ExpressionEvaluationContext::UnevaluatedList; } + bool isConstantEvaluated() const { - return Context == ExpressionEvaluationContext::ConstantEvaluated; + return Context == ExpressionEvaluationContext::ConstantEvaluated || + Context == ExpressionEvaluationContext::ImmediateFunctionContext; + } + + bool isImmediateFunctionContext() const { + return Context == ExpressionEvaluationContext::ImmediateFunctionContext; } }; @@ -1419,8 +1429,22 @@ public: const llvm::MapVector & getMismatchingDeleteExpressions() const; - typedef std::pair GlobalMethods; - typedef llvm::DenseMap GlobalMethodPool; + class GlobalMethodPool { + public: + using Lists = std::pair; + using iterator = llvm::DenseMap::iterator; + iterator begin() { return Methods.begin(); } + iterator end() { return Methods.end(); } + iterator find(Selector Sel) { return Methods.find(Sel); } + std::pair insert(std::pair &&Val) { + return Methods.insert(Val); + } + int count(Selector Sel) const { return Methods.count(Sel); } + bool empty() const { return Methods.empty(); } + + private: + llvm::DenseMap Methods; + }; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures @@ -2334,12 +2358,13 @@ public: const CXXScopeSpec &SS, QualType T, TagDecl *OwnedTagDecl = nullptr); - QualType getDecltypeForParenthesizedExpr(Expr *E); - QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + // Returns the underlying type of a decltype with the given expression. + QualType getDecltypeForExpr(Expr *E); + + QualType BuildTypeofExprType(Expr *E); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). - QualType BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated = true); + QualType BuildDecltypeType(Expr *E, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); @@ -3343,6 +3368,8 @@ public: const AttributeCommonInfo &CI, bool BestCase, MSInheritanceModel Model); + ErrorAttr *mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef NewUserDiagnostic); FormatAttr *mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Format, int FormatIdx, int FirstArg); @@ -3368,6 +3395,7 @@ public: EnforceTCBAttr *mergeEnforceTCBAttr(Decl *D, const EnforceTCBAttr &AL); EnforceTCBLeafAttr *mergeEnforceTCBLeafAttr(Decl *D, const EnforceTCBLeafAttr &AL); + BTFDeclTagAttr *mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); @@ -3475,7 +3503,7 @@ public: bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); - bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); + bool isSameOrCompatibleFunctionType(QualType Param, QualType Arg); bool CanPerformAggregateInitializationForOverloadResolution( const InitializedEntity &Entity, InitListExpr *From); @@ -3504,11 +3532,12 @@ public: /// Contexts in which a converted constant expression is required. enum CCEKind { - CCEK_CaseValue, ///< Expression in a case label. - CCEK_Enumerator, ///< Enumerator value with fixed underlying type. - CCEK_TemplateArg, ///< Value of a non-type template parameter. - CCEK_ArrayBound, ///< Array bound in array declarator or new-expression. - CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier. + CCEK_CaseValue, ///< Expression in a case label. + CCEK_Enumerator, ///< Enumerator value with fixed underlying type. + CCEK_TemplateArg, ///< Value of a non-type template parameter. + CCEK_ArrayBound, ///< Array bound in array declarator or new-expression. + CCEK_ExplicitBool, ///< Condition in an explicit(bool) specifier. + CCEK_Noexcept ///< Condition in a noexcept(bool) specifier. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); @@ -3888,6 +3917,8 @@ public: SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, + Expr *ExecConfig = nullptr, + bool IsExecConfig = false, bool AllowRecovery = false); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, @@ -4690,11 +4721,12 @@ public: Stmt *SubStmt); class ConditionResult; - StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, + + StmtResult ActOnIfStmt(SourceLocation IfLoc, IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); - StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, + StmtResult BuildIfStmt(SourceLocation IfLoc, IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); @@ -4893,7 +4925,7 @@ public: /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. - void DiagnoseUnusedExprResult(const Stmt *S); + void DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID); void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); void DiagnoseUnusedDecl(const NamedDecl *ND); @@ -5082,7 +5114,8 @@ public: /// type -- entities referenced by the type are now referenced. void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E, - bool SkipLocalVariables = false); + bool SkipLocalVariables = false, + ArrayRef StopAt = None); /// Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was @@ -5099,6 +5132,16 @@ public: /// conversion. ExprResult tryConvertExprToType(Expr *E, QualType Ty); + /// Conditionally issue a diagnostic based on the statements's reachability + /// analysis. + /// + /// \param Stmts If Stmts is non-empty, delay reporting the diagnostic until + /// the function body is parsed, and then do a basic reachability analysis to + /// determine if the statement is reachable. If it is unreachable, the + /// diagnostic will not be emitted. + bool DiagIfReachable(SourceLocation Loc, ArrayRef Stmts, + const PartialDiagnostic &PD); + /// Conditionally issue a diagnostic based on the current /// evaluation context. /// @@ -5659,6 +5702,7 @@ public: NamespaceDecl *getOrCreateStdNamespace(); NamespaceDecl *lookupStdExperimentalNamespace(); + NamespaceDecl *getCachedCoroNamespace() { return CoroTraitsNamespaceCache; } CXXRecordDecl *getStdBadAlloc() const; EnumDecl *getStdAlignValT() const; @@ -5909,7 +5953,7 @@ public: /// Check the given noexcept-specifier, convert its expression, and compute /// the appropriate ExceptionSpecificationType. - ExprResult ActOnNoexceptSpec(SourceLocation NoexceptLoc, Expr *NoexceptExpr, + ExprResult ActOnNoexceptSpec(Expr *NoexceptExpr, ExceptionSpecificationType &EST); /// Check the given exception-specification and update the @@ -6105,6 +6149,13 @@ public: // AltiVecPixel and AltiVecBool when -faltivec-src-compat=xl is specified. bool ShouldSplatAltivecScalarInCast(const VectorType *VecTy); + // Checks if the -faltivec-src-compat=gcc option is specified. + // If so, AltiVecVector, AltiVecBool and AltiVecPixel types are + // treated the same way as they are when trying to initialize + // these vectors on gcc (an error is emitted). + bool CheckAltivecInitFromScalar(SourceRange R, QualType VecTy, + QualType SrcTy); + /// ActOnCXXNamedCast - Parse /// {dynamic,static,reinterpret,const,addrspace}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, @@ -7828,8 +7879,7 @@ public: TemplateArgumentLoc &Arg, SmallVectorImpl &Converted); - bool CheckTemplateArgument(TemplateTypeParmDecl *Param, - TypeSourceInfo *Arg); + bool CheckTemplateArgument(TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, @@ -8517,6 +8567,14 @@ public: /// Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); + + // Substitute auto in TypeWithAuto for a Dependent auto type + QualType SubstAutoTypeDependent(QualType TypeWithAuto); + + // Substitute auto in TypeWithAuto for a Dependent auto type + TypeSourceInfo * + SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto); + /// Completely replace the \c auto in \p TypeWithAuto by /// \p Replacement. This does not retain any \c auto type sugar. QualType ReplaceAutoType(QualType TypeWithAuto, QualType Replacement); @@ -9089,6 +9147,19 @@ public: return ExprEvalContexts.back().isUnevaluated(); } + bool isImmediateFunctionContext() const { + assert(!ExprEvalContexts.empty() && + "Must be in an expression evaluation context"); + for (const ExpressionEvaluationContextRecord &context : + llvm::reverse(ExprEvalContexts)) { + if (context.isImmediateFunctionContext()) + return true; + if (context.isUnevaluated()) + return false; + } + return false; + } + /// RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. @@ -9452,9 +9523,9 @@ public: SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); - bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, - TemplateArgumentListInfo &Result, - const MultiLevelTemplateArgumentList &TemplateArgs); + + bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, + const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); @@ -10209,8 +10280,11 @@ public: bool buildCoroutineParameterMoves(SourceLocation Loc); VarDecl *buildCoroutinePromise(SourceLocation Loc); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); + /// Lookup 'coroutine_traits' in std namespace and std::experimental + /// namespace. The namespace found is recorded in Namespace. ClassTemplateDecl *lookupCoroutineTraits(SourceLocation KwLoc, - SourceLocation FuncLoc); + SourceLocation FuncLoc, + NamespaceDecl *&Namespace); /// Check that the expression co_await promise.final_suspend() shall not be /// potentially-throwing. bool checkFinalSuspendNoThrow(const Stmt *FinalSuspend); @@ -10431,6 +10505,12 @@ public: /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); + /// Called on well-formed '\#pragma omp metadirective' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPMetaDirective(ArrayRef Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc); + // OpenMP directives and clauses. /// Called on correct id-expression from the '#pragma omp /// threadprivate'. @@ -10453,7 +10533,7 @@ public: /// Called on well-formed '#pragma omp [begin] assume[s]'. void ActOnOpenMPAssumesDirective(SourceLocation Loc, OpenMPDirectiveKind DKind, - ArrayRef Assumptions, + ArrayRef Assumptions, bool SkippedClauses); /// Check if there is an active global `omp begin assumes` directive. @@ -10563,6 +10643,11 @@ public: /// an OpenMP loop directive. StmtResult ActOnOpenMPCanonicalLoop(Stmt *AStmt); + /// Process a canonical OpenMP loop nest that can either be a canonical + /// literal loop (ForStmt or CXXForRangeStmt), or the generated loop of an + /// OpenMP loop transformation construct. + StmtResult ActOnOpenMPLoopnest(Stmt *AStmt); + /// End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. @@ -10668,7 +10753,8 @@ public: StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskwait'. - StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, + StmtResult ActOnOpenMPTaskwaitDirective(ArrayRef Clauses, + SourceLocation StartLoc, SourceLocation EndLoc); /// Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(ArrayRef Clauses, @@ -10873,6 +10959,12 @@ public: Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); + /// Called on well-formed '\#pragma omp loop' after parsing of the + /// associated statement. + StmtResult ActOnOpenMPGenericLoopDirective( + ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA); + /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); @@ -10897,11 +10989,14 @@ public: /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The trait info object representing the match clause. + /// \param NumAppendArgs The number of omp_interop_t arguments to account for + /// in checking. /// \returns None, if the function/variant function are not compatible with /// the pragma, pair of original function/variant ref expression otherwise. Optional> checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef, - OMPTraitInfo &TI, SourceRange SR); + OMPTraitInfo &TI, unsigned NumAppendArgs, + SourceRange SR); /// Called on well-formed '\#pragma omp declare variant' after parsing of /// the associated method/function. @@ -10910,8 +11005,19 @@ public: /// \param VariantRef Expression that references the variant function, which /// must be used instead of the original one, specified in \p DG. /// \param TI The context traits associated with the function variant. - void ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, Expr *VariantRef, - OMPTraitInfo &TI, SourceRange SR); + /// \param AdjustArgsNothing The list of 'nothing' arguments. + /// \param AdjustArgsNeedDevicePtr The list of 'need_device_ptr' arguments. + /// \param AppendArgs The list of 'append_args' arguments. + /// \param AdjustArgsLoc The Location of an 'adjust_args' clause. + /// \param AppendArgsLoc The Location of an 'append_args' clause. + /// \param SR The SourceRange of the 'declare variant' directive. + void ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, + ArrayRef AdjustArgsNothing, + ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AppendArgs, + SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, + SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, @@ -10939,6 +11045,10 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'align' clause. + OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, @@ -10993,6 +11103,10 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'when' clause. + OMPClause *ActOnOpenMPWhenClause(OMPTraitInfo &TI, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(llvm::omp::DefaultKind Kind, SourceLocation KindLoc, @@ -11243,15 +11357,14 @@ public: SourceLocation ModifierLoc, SourceLocation EndLoc); /// Called on well-formed 'map' clause. - OMPClause * - ActOnOpenMPMapClause(ArrayRef MapTypeModifiers, - ArrayRef MapTypeModifiersLoc, - CXXScopeSpec &MapperIdScopeSpec, - DeclarationNameInfo &MapperId, - OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, - SourceLocation MapLoc, SourceLocation ColonLoc, - ArrayRef VarList, const OMPVarListLocTy &Locs, - ArrayRef UnresolvedMappers = llvm::None); + OMPClause *ActOnOpenMPMapClause( + ArrayRef MapTypeModifiers, + ArrayRef MapTypeModifiersLoc, + CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, + const OMPVarListLocTy &Locs, bool NoDiagnose = false, + ArrayRef UnresolvedMappers = llvm::None); /// Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -11326,6 +11439,12 @@ public: SourceLocation ColonLoc, SourceLocation EndLoc, Expr *Modifier, ArrayRef Locators); + /// Called on a well-formed 'bind' clause. + OMPClause *ActOnOpenMPBindClause(OpenMPBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// The kind of conversion being performed. enum CheckedConversionKind { @@ -12147,9 +12266,9 @@ public: return targetDiag(Loc, PD.getDiagID(), FD) << PD; } - /// Check if the expression is allowed to be used in expressions for the - /// offloading devices. - void checkDeviceDecl(ValueDecl *D, SourceLocation Loc); + /// Check if the type is allowed to be used for the current target. + void checkTypeSupport(QualType Ty, SourceLocation Loc, + ValueDecl *D = nullptr); enum CUDAFunctionTarget { CFT_Device, @@ -12375,6 +12494,15 @@ public: const VirtSpecifiers *VS = nullptr); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); + enum class AttributeCompletion { + Attribute, + Scope, + None, + }; + void CodeCompleteAttribute( + AttributeCommonInfo::Syntax Syntax, + AttributeCompletion Completion = AttributeCompletion::Attribute, + const IdentifierInfo *Scope = nullptr); /// Determines the preferred type of the current function argument, by /// examining the signatures of all possible overloads. /// Returns null if unknown or ambiguous, or if code completion is off. @@ -12626,10 +12754,15 @@ private: int ArgNum, unsigned ExpectedFieldNum, bool AllowName); bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinPPCMMACall(CallExpr *TheCall, const char *TypeDesc); + bool SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeDesc); bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); + bool SemaBuiltinElementwiseMath(CallExpr *TheCall); + bool SemaBuiltinElementwiseMathOneArg(CallExpr *TheCall); + bool SemaBuiltinReduceMath(CallExpr *TheCall); + // Matrix builtin handling. ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult); diff --git a/clang/include/clang/Sema/SemaConcept.h b/clang/include/clang/Sema/SemaConcept.h index c5f9fc45612..dc5f0ec97e8 100644 --- a/clang/include/clang/Sema/SemaConcept.h +++ b/clang/include/clang/Sema/SemaConcept.h @@ -1,9 +1,8 @@ //===-- SemaConcept.h - Semantic Analysis for Constraints and Concepts ----===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 027a981df22..341da5bd1d6 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -402,6 +402,9 @@ enum UnhashedControlBlockRecordTypes { /// Record code for \#pragma diagnostic mappings. DIAG_PRAGMA_MAPPINGS, + + /// Record code for the indices of used header search entries. + HEADER_SEARCH_ENTRY_USAGE, }; /// Record code for extension blocks. @@ -1064,6 +1067,9 @@ enum PredefinedTypeIDs { /// \brief The '__bf16' type PREDEF_TYPE_BFLOAT16_ID = 73, + /// \brief The '__ibm128' type + PREDEF_TYPE_IBM128_ID = 74, + /// OpenCL image types with auto numeration #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ PREDEF_TYPE_##Id##_ID, @@ -1890,6 +1896,7 @@ enum StmtCode { STMT_SEH_TRY, // SEHTryStmt // OpenMP directives + STMT_OMP_META_DIRECTIVE, STMT_OMP_CANONICAL_LOOP, STMT_OMP_PARALLEL_DIRECTIVE, STMT_OMP_SIMD_DIRECTIVE, @@ -1950,6 +1957,7 @@ enum StmtCode { STMT_OMP_INTEROP_DIRECTIVE, STMT_OMP_DISPATCH_DIRECTIVE, STMT_OMP_MASKED_DIRECTIVE, + STMT_OMP_GENERIC_LOOP_DIRECTIVE, EXPR_OMP_ARRAY_SECTION, EXPR_OMP_ARRAY_SHAPING, EXPR_OMP_ITERATOR, diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 242b75baca6..f24ccf579aa 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1162,6 +1162,10 @@ private: /// definitions. Only populated when using modules in C++. llvm::DenseMap EnumDefinitions; + /// A mapping from canonical declarations of records to their canonical + /// definitions. Doesn't cover CXXRecordDecl. + llvm::DenseMap RecordDefinitions; + /// When reading a Stmt tree, Stmt operands are placed in this stack. SmallVector StmtStack; @@ -1320,18 +1324,18 @@ private: ASTReaderListener *Listener, bool ValidateDiagnosticOptions); - ASTReadResult ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities); - ASTReadResult ReadExtensionBlock(ModuleFile &F); + llvm::Error ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities); + llvm::Error ReadExtensionBlock(ModuleFile &F); void ReadModuleOffsetMap(ModuleFile &F) const; - bool ParseLineTable(ModuleFile &F, const RecordData &Record); - bool ReadSourceManagerBlock(ModuleFile &F); + void ParseLineTable(ModuleFile &F, const RecordData &Record); + llvm::Error ReadSourceManagerBlock(ModuleFile &F); llvm::BitstreamCursor &SLocCursorForID(int ID); SourceLocation getImportLocation(ModuleFile *F); ASTReadResult ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities); - ASTReadResult ReadSubmoduleBlock(ModuleFile &F, - unsigned ClientLoadCapabilities); + llvm::Error ReadSubmoduleBlock(ModuleFile &F, + unsigned ClientLoadCapabilities); static bool ParseLanguageOptions(const RecordData &Record, bool Complain, ASTReaderListener &Listener, bool AllowCompatibleDifferences); @@ -1904,8 +1908,9 @@ public: /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the /// specified cursor. Read the abbreviations that are at the top of the block /// and then leave the cursor pointing into the block. - static bool ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID, - uint64_t *StartOfBlockOffset = nullptr); + static llvm::Error ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, + unsigned BlockID, + uint64_t *StartOfBlockOffset = nullptr); /// Finds all the visible declarations with a given name. /// The current implementation of this method just loads the entire diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index b85609bf4e0..36179ec2340 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -350,7 +350,7 @@ struct SavedStreamPosition { ~SavedStreamPosition() { if (llvm::Error Err = Cursor.JumpToBit(Offset)) llvm::report_fatal_error( - "Cursor should always be able to go back, failed: " + + llvm::Twine("Cursor should always be able to go back, failed: ") + toString(std::move(Err))); } diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index ac88cb0a317..978f6d86ea5 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -456,6 +456,9 @@ private: std::vector> ModuleFileExtensionWriters; + /// User ModuleMaps skipped when writing control block. + std::set SkippedModuleMaps; + /// Retrieve or create a submodule ID for this module. unsigned getSubmoduleID(Module *Mod); @@ -475,7 +478,7 @@ private: createSignature(StringRef AllBytes, StringRef ASTBlockBytes); void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOptions &HSOpts, - bool Modules); + std::set &AffectingModuleMaps); void WriteSourceManagerBlock(SourceManager &SourceMgr, const Preprocessor &PP); void WritePreprocessor(const Preprocessor &PP, bool IsModule); diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index b1c8a8c8e72..b275f8b8db5 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -20,6 +20,7 @@ #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/ModuleFileExtension.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SetVector.h" @@ -173,6 +174,9 @@ public: /// unique module files based on AST contents. ASTFileSignature ASTBlockHash; + /// The bit vector denoting usage of each header search entry (true = used). + llvm::BitVector SearchPathUsage; + /// Whether this module has been directly imported by the /// user. bool DirectlyImported = false; diff --git a/clang/include/clang/Serialization/ModuleFileExtension.h b/clang/include/clang/Serialization/ModuleFileExtension.h index 34ea870724a..3e84a65c4b8 100644 --- a/clang/include/clang/Serialization/ModuleFileExtension.h +++ b/clang/include/clang/Serialization/ModuleFileExtension.h @@ -11,13 +11,14 @@ #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/ExtensibleRTTI.h" +#include "llvm/Support/HashBuilder.h" +#include "llvm/Support/MD5.h" #include #include namespace llvm { class BitstreamCursor; class BitstreamWriter; -class hash_code; class raw_ostream; } @@ -74,19 +75,20 @@ public: virtual ModuleFileExtensionMetadata getExtensionMetadata() const = 0; /// Hash information about the presence of this extension into the - /// module hash code. + /// module hash. /// - /// The module hash code is used to distinguish different variants - /// of a module that are incompatible. If the presence, absence, or - /// version of the module file extension should force the creation - /// of a separate set of module files, override this method to - /// combine that distinguishing information into the module hash - /// code. + /// The module hash is used to distinguish different variants of a module that + /// are incompatible. If the presence, absence, or version of the module file + /// extension should force the creation of a separate set of module files, + /// override this method to combine that distinguishing information into the + /// module hash. /// - /// The default implementation of this function simply returns the - /// hash code as given, so the presence/absence of this extension - /// does not distinguish module files. - virtual llvm::hash_code hashExtension(llvm::hash_code c) const; + /// The default implementation of this function simply does nothing, so the + /// presence/absence of this extension does not distinguish module files. + using ExtensionHashBuilder = + llvm::HashBuilderImpl; + virtual void hashExtension(ExtensionHashBuilder &HBuilder) const; /// Create a new module file extension writer, which will be /// responsible for writing the extension contents into a particular diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 444b00d73f0..bd21d7778f9 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -73,6 +73,7 @@ def Taint : Package<"taint">, ParentPackage; def CERT : Package<"cert">, ParentPackage; def POS : Package<"pos">, ParentPackage; +def ENV : Package<"env">, ParentPackage; def Unix : Package<"unix">; def UnixAlpha : Package<"unix">, ParentPackage; @@ -485,7 +486,17 @@ def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">, "allocating and deallocating functions are annotated with " "ownership_holds, ownership_takes and ownership_returns.", "false", - InAlpha> + InAlpha>, + CmdLineOption ]>, Dependencies<[CStringModeling]>, Documentation, @@ -592,6 +603,10 @@ def SmartPtrModeling: Checker<"SmartPtrModeling">, ]>, Hidden; +def StringChecker: Checker<"StringChecker">, + HelpText<"Checks C++ std::string bugs">, + Documentation; + def MoveChecker: Checker<"Move">, HelpText<"Find use-after-move bugs in C++">, CheckerOptions<[ @@ -937,6 +952,14 @@ let ParentPackage = POS in { } // end "alpha.cert.pos" +let ParentPackage = ENV in { + + def InvalidPtrChecker : Checker<"InvalidPtr">, + HelpText<"Finds usages of possibly invalidated pointers">, + Documentation; + +} // end "alpha.cert.env" + let ParentPackage = SecurityAlpha in { def ArrayBoundChecker : Checker<"ArrayBound">, diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def index f0359d2dbb3..aab8e1284bf 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -190,7 +190,13 @@ ANALYZER_OPTION(bool, ShouldReportIssuesInMainSourceFile, false) ANALYZER_OPTION(bool, ShouldWriteStableReportFilename, "stable-report-filename", - "Whether or not the report filename should be random or not.", + "Deprecated: report filenames are now always stable. " + "See also 'verbose-report-filename'.", + false) + +ANALYZER_OPTION(bool, ShouldWriteVerboseReportFilename, "verbose-report-filename", + "Whether or not the report filename should contain extra " + "information about the issue.", false) ANALYZER_OPTION( @@ -314,6 +320,22 @@ ANALYZER_OPTION(bool, ShouldDisplayCheckerNameForText, "display-checker-name", "Display the checker name for textual outputs", true) +ANALYZER_OPTION( + bool, ShouldConsiderSingleElementArraysAsFlexibleArrayMembers, + "consider-single-element-arrays-as-flexible-array-members", + "Consider single element arrays as flexible array member candidates. " + "This will prevent the analyzer from assuming that a single element array " + "holds a single element.", + false) + +ANALYZER_OPTION( + bool, ShouldAssumeControlledEnvironment, "assume-controlled-environment", + "Whether the analyzed application runs in a controlled environment. " + "We will assume that environment variables exist in queries and they hold " + "no malicious data. For instance, if this option is enabled, 'getenv()' " + "might be modeled by the analyzer to never return NULL.", + false) + //===----------------------------------------------------------------------===// // Unsigned analyzer options. //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index ccf35e0a81e..7514eee7244 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -395,7 +395,11 @@ public: return {FullCompilerInvocation, ShouldDisplayMacroExpansions, ShouldSerializeStats, - ShouldWriteStableReportFilename, + // The stable report filename option is deprecated because + // file names are now always stable. Now the old option acts as + // an alias to the new verbose filename option because this + // closely mimics the behavior under the old option. + ShouldWriteStableReportFilename || ShouldWriteVerboseReportFilename, AnalyzerWerror, ShouldApplyFixIts, ShouldDisplayCheckerNameForText}; diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h index 24cae12af24..c42521376af 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -21,6 +21,7 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringRef.h" #include #include @@ -622,8 +623,118 @@ public: PathSensitiveBugReport &R) override; }; -} // namespace ento +class ObjCMethodCall; +class CXXConstructorCall; +/// Put a diagnostic on return statement (or on } in its absence) of all inlined +/// functions for which some property remained unchanged. +/// Resulting diagnostics may read such as "Returning without writing to X". +/// +/// Descendants can define what a "state change is", like a change of value +/// to a memory region, liveness, etc. For function calls where the state did +/// not change as defined, a custom note may be constructed. +/// +/// For a minimal example, check out +/// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp. +class NoStateChangeFuncVisitor : public BugReporterVisitor { +private: + /// Frames modifying the state as defined in \c wasModifiedBeforeCallExit. + /// This visitor generates a note only if a function does *not* change the + /// state that way. This information is not immediately available + /// by looking at the node associated with the exit from the function + /// (usually the return statement). To avoid recomputing the same information + /// many times (going up the path for each node and checking whether the + /// region was written into) we instead lazily compute the stack frames + /// along the path. + // TODO: Can't we just use a map instead? This is likely not as cheap as it + // makes the code difficult to read. + llvm::SmallPtrSet FramesModifying; + llvm::SmallPtrSet FramesModifyingCalculated; + + /// Check and lazily calculate whether the state is modified in the stack + /// frame to which \p CallExitBeginN belongs. + /// The calculation is cached in FramesModifying. + bool isModifiedInFrame(const ExplodedNode *CallExitBeginN); + + void markFrameAsModifying(const StackFrameContext *SCtx); + + /// Write to \c FramesModifying all stack frames along the path in the current + /// stack frame which modifies the state. + void findModifyingFrames(const ExplodedNode *const CallExitBeginN); + +protected: + bugreporter::TrackingKind TKind; + + /// \return Whether the state was modified from the current node, \p CurrN, to + /// the end of the stack frame, at \p CallExitBeginN. \p CurrN and + /// \p CallExitBeginN are always in the same stack frame. + /// Clients should override this callback when a state change is important + /// not only on the entire function call, but inside of it as well. + /// Example: we may want to leave a note about the lack of locking/unlocking + /// on a particular mutex, but not if inside the function its state was + /// changed, but also restored. wasModifiedInFunction() wouldn't know of this + /// change. + virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN, + const ExplodedNode *CallExitBeginN) { + return false; + } + + /// \return Whether the state was modified in the inlined function call in + /// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame + /// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack + /// frame! The inlined function's stack should be retrieved from either the + /// immediate successor to \p CallEnterN or immediate predecessor to + /// \p CallExitEndN. + /// Clients should override this function if a state changes local to the + /// inlined function are not interesting, only the change occuring as a + /// result of it. + /// Example: we want to leave a not about a leaked resource object not being + /// deallocated / its ownership changed inside a function, and we don't care + /// if it was assigned to a local variable (its change in ownership is + /// inconsequential). + virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN, + const ExplodedNode *CallExitEndN) { + return false; + } + + /// Consume the information on the non-modifying stack frame in order to + /// either emit a note or not. May suppress the report entirely. + /// \return Diagnostics piece for the unmodified state in the current + /// function, if it decides to emit one. A good description might start with + /// "Returning without...". + virtual PathDiagnosticPieceRef + maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, + const ObjCMethodCall &Call, + const ExplodedNode *N) = 0; + + /// Consume the information on the non-modifying stack frame in order to + /// either emit a note or not. May suppress the report entirely. + /// \return Diagnostics piece for the unmodified state in the current + /// function, if it decides to emit one. A good description might start with + /// "Returning without...". + virtual PathDiagnosticPieceRef + maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, + const CXXConstructorCall &Call, + const ExplodedNode *N) = 0; + + /// Consume the information on the non-modifying stack frame in order to + /// either emit a note or not. May suppress the report entirely. + /// \return Diagnostics piece for the unmodified state in the current + /// function, if it decides to emit one. A good description might start with + /// "Returning without...". + virtual PathDiagnosticPieceRef + maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, + const ExplodedNode *N) = 0; + +public: + NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {} + + PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, + BugReporterContext &BR, + PathSensitiveBugReport &R) override final; +}; + +} // namespace ento } // namespace clang #endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h new file mode 100644 index 00000000000..396c9a4de44 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h @@ -0,0 +1,173 @@ +//===- CallDescription.h - function/method call matching --*- 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 defines a generic mechanism for matching for function and +/// method calls of C, C++, and Objective-C languages. Instances of these +/// classes are frequently used together with the CallEvent classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H +#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compiler.h" +#include + +namespace clang { +class IdentifierInfo; +} // namespace clang + +namespace clang { +namespace ento { + +enum CallDescriptionFlags : unsigned { + CDF_None = 0, + + /// Describes a C standard function that is sometimes implemented as a macro + /// that expands to a compiler builtin with some __builtin prefix. + /// The builtin may as well have a few extra arguments on top of the requested + /// number of arguments. + CDF_MaybeBuiltin = 1 << 0, +}; + +/// This class represents a description of a function call using the number of +/// arguments and the name of the function. +class CallDescription { + friend class CallEvent; + using MaybeCount = Optional; + + mutable Optional II; + // The list of the qualified names used to identify the specified CallEvent, + // e.g. "{a, b}" represent the qualified names, like "a::b". + std::vector QualifiedName; + MaybeCount RequiredArgs; + MaybeCount RequiredParams; + int Flags; + +public: + /// Constructs a CallDescription object. + /// + /// @param QualifiedName The list of the name qualifiers of the function that + /// will be matched. The user is allowed to skip any of the qualifiers. + /// For example, {"std", "basic_string", "c_str"} would match both + /// std::basic_string<...>::c_str() and std::__1::basic_string<...>::c_str(). + /// + /// @param RequiredArgs The number of arguments that is expected to match a + /// call. Omit this parameter to match every occurrence of call with a given + /// name regardless the number of arguments. + CallDescription(CallDescriptionFlags Flags, + ArrayRef QualifiedName, + MaybeCount RequiredArgs = None, + MaybeCount RequiredParams = None); + + /// Construct a CallDescription with default flags. + CallDescription(ArrayRef QualifiedName, + MaybeCount RequiredArgs = None, + MaybeCount RequiredParams = None); + + CallDescription(std::nullptr_t) = delete; + + /// Get the name of the function that this object matches. + StringRef getFunctionName() const { return QualifiedName.back(); } + + /// Get the qualified name parts in reversed order. + /// E.g. { "std", "vector", "data" } -> "vector", "std" + auto begin_qualified_name_parts() const { + return std::next(QualifiedName.rbegin()); + } + auto end_qualified_name_parts() const { return QualifiedName.rend(); } + + /// It's false, if and only if we expect a single identifier, such as + /// `getenv`. It's true for `std::swap`, or `my::detail::container::data`. + bool hasQualifiedNameParts() const { return QualifiedName.size() > 1; } + + /// @name Matching CallDescriptions against a CallEvent + /// @{ + + /// Returns true if the CallEvent is a call to a function that matches + /// the CallDescription. + /// + /// \note This function is not intended to be used to match Obj-C method + /// calls. + bool matches(const CallEvent &Call) const; + + /// Returns true whether the CallEvent matches on any of the CallDescriptions + /// supplied. + /// + /// \note This function is not intended to be used to match Obj-C method + /// calls. + friend bool matchesAny(const CallEvent &Call, const CallDescription &CD1) { + return CD1.matches(Call); + } + + /// \copydoc clang::ento::matchesAny(const CallEvent &, const CallDescription &) + template + friend bool matchesAny(const CallEvent &Call, const CallDescription &CD1, + const Ts &...CDs) { + return CD1.matches(Call) || matchesAny(Call, CDs...); + } + /// @} +}; + +/// An immutable map from CallDescriptions to arbitrary data. Provides a unified +/// way for checkers to react on function calls. +template class CallDescriptionMap { + friend class CallDescriptionSet; + + // Some call descriptions aren't easily hashable (eg., the ones with qualified + // names in which some sections are omitted), so let's put them + // in a simple vector and use linear lookup. + // TODO: Implement an actual map for fast lookup for "hashable" call + // descriptions (eg., the ones for C functions that just match the name). + std::vector> LinearMap; + +public: + CallDescriptionMap( + std::initializer_list> &&List) + : LinearMap(List) {} + + ~CallDescriptionMap() = default; + + // These maps are usually stored once per checker, so let's make sure + // we don't do redundant copies. + CallDescriptionMap(const CallDescriptionMap &) = delete; + CallDescriptionMap &operator=(const CallDescription &) = delete; + + LLVM_NODISCARD const T *lookup(const CallEvent &Call) const { + // Slow path: linear lookup. + // TODO: Implement some sort of fast path. + for (const std::pair &I : LinearMap) + if (I.first.matches(Call)) + return &I.second; + + return nullptr; + } +}; + +/// An immutable set of CallDescriptions. +/// Checkers can efficiently decide if a given CallEvent matches any +/// CallDescription in the set. +class CallDescriptionSet { + CallDescriptionMap Impl = {}; + +public: + CallDescriptionSet(std::initializer_list &&List); + + CallDescriptionSet(const CallDescriptionSet &) = delete; + CallDescriptionSet &operator=(const CallDescription &) = delete; + + LLVM_NODISCARD bool contains(const CallEvent &Call) const; +}; + +} // namespace ento +} // namespace clang + +#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CALLDESCRIPTION_H diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 060fff1a740..d135e70dd75 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -257,20 +257,6 @@ public: return false; } - /// Returns true if the CallEvent is a call to a function that matches - /// the CallDescription. - /// - /// Note that this function is not intended to be used to match Obj-C method - /// calls. - bool isCalled(const CallDescription &CD) const; - - /// Returns true whether the CallEvent is any of the CallDescriptions supplied - /// as a parameter. - template - bool isCalled(const FirstCallDesc &First, const CallDescs &... Rest) const { - return isCalled(First) || isCalled(Rest...); - } - /// Returns a source range for the entire call, suitable for /// outputting in diagnostics. virtual SourceRange getSourceRange() const { @@ -1225,99 +1211,6 @@ public: } }; -enum CallDescriptionFlags : int { - /// Describes a C standard function that is sometimes implemented as a macro - /// that expands to a compiler builtin with some __builtin prefix. - /// The builtin may as well have a few extra arguments on top of the requested - /// number of arguments. - CDF_MaybeBuiltin = 1 << 0, -}; - -/// This class represents a description of a function call using the number of -/// arguments and the name of the function. -class CallDescription { - friend CallEvent; - - mutable IdentifierInfo *II = nullptr; - mutable bool IsLookupDone = false; - // The list of the qualified names used to identify the specified CallEvent, - // e.g. "{a, b}" represent the qualified names, like "a::b". - std::vector QualifiedName; - Optional RequiredArgs; - Optional RequiredParams; - int Flags; - - // A constructor helper. - static Optional readRequiredParams(Optional RequiredArgs, - Optional RequiredParams) { - if (RequiredParams) - return RequiredParams; - if (RequiredArgs) - return static_cast(*RequiredArgs); - return None; - } - -public: - /// Constructs a CallDescription object. - /// - /// @param QualifiedName The list of the name qualifiers of the function that - /// will be matched. The user is allowed to skip any of the qualifiers. - /// For example, {"std", "basic_string", "c_str"} would match both - /// std::basic_string<...>::c_str() and std::__1::basic_string<...>::c_str(). - /// - /// @param RequiredArgs The number of arguments that is expected to match a - /// call. Omit this parameter to match every occurrence of call with a given - /// name regardless the number of arguments. - CallDescription(int Flags, ArrayRef QualifiedName, - Optional RequiredArgs = None, - Optional RequiredParams = None) - : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs), - RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)), - Flags(Flags) {} - - /// Construct a CallDescription with default flags. - CallDescription(ArrayRef QualifiedName, - Optional RequiredArgs = None, - Optional RequiredParams = None) - : CallDescription(0, QualifiedName, RequiredArgs, RequiredParams) {} - - /// Get the name of the function that this object matches. - StringRef getFunctionName() const { return QualifiedName.back(); } -}; - -/// An immutable map from CallDescriptions to arbitrary data. Provides a unified -/// way for checkers to react on function calls. -template class CallDescriptionMap { - // Some call descriptions aren't easily hashable (eg., the ones with qualified - // names in which some sections are omitted), so let's put them - // in a simple vector and use linear lookup. - // TODO: Implement an actual map for fast lookup for "hashable" call - // descriptions (eg., the ones for C functions that just match the name). - std::vector> LinearMap; - -public: - CallDescriptionMap( - std::initializer_list> &&List) - : LinearMap(List) {} - - ~CallDescriptionMap() = default; - - // These maps are usually stored once per checker, so let's make sure - // we don't do redundant copies. - CallDescriptionMap(const CallDescriptionMap &) = delete; - CallDescriptionMap &operator=(const CallDescription &) = delete; - - const T *lookup(const CallEvent &Call) const { - // Slow path: linear lookup. - // TODO: Implement some sort of fast path. - for (const std::pair &I : LinearMap) - if (Call.isCalled(I.first)) - return &I.second; - - return nullptr; - } -}; - /// Manages the lifetime of CallEvent objects. /// /// CallEventManager provides a way to create arbitrary CallEvents "on the diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h index c67df1e51b4..a8048461013 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h @@ -48,6 +48,7 @@ public: ID.AddPointer(&To()); } void dump(raw_ostream &OS) const; + void dump() const; // In order to keep non-overlapping ranges sorted, we can compare only From // points. @@ -281,7 +282,27 @@ public: /// where N = size(this) bool contains(llvm::APSInt Point) const { return containsImpl(Point); } + bool containsZero() const { + APSIntType T{getMinValue()}; + return contains(T.getZeroValue()); + } + + /// Test if the range is the [0,0] range. + /// + /// Complexity: O(1) + bool encodesFalseRange() const { + const llvm::APSInt *Constant = getConcreteValue(); + return Constant && Constant->isZero(); + } + + /// Test if the range doesn't contain zero. + /// + /// Complexity: O(logN) + /// where N = size(this) + bool encodesTrueRange() const { return !containsZero(); } + void dump(raw_ostream &OS) const; + void dump() const; bool operator==(const RangeSet &Other) const { return *Impl == *Other.Impl; } bool operator!=(const RangeSet &Other) const { return !(*this == Other); } @@ -387,11 +408,22 @@ private: static void computeAdjustment(SymbolRef &Sym, llvm::APSInt &Adjustment); }; -/// Try to simplify a given symbolic expression's associated value based on the -/// constraints in State. This is needed because the Environment bindings are -/// not getting updated when a new constraint is added to the State. +/// Try to simplify a given symbolic expression based on the constraints in +/// State. This is needed because the Environment bindings are not getting +/// updated when a new constraint is added to the State. If the symbol is +/// simplified to a non-symbol (e.g. to a constant) then the original symbol +/// is returned. We use this function in the family of assumeSymNE/EQ/LT/../GE +/// functions where we can work only with symbols. Use the other function +/// (simplifyToSVal) if you are interested in a simplification that may yield +/// a concrete constant value. SymbolRef simplify(ProgramStateRef State, SymbolRef Sym); +/// Try to simplify a given symbolic expression's associated `SVal` based on the +/// constraints in State. This is very similar to `simplify`, but this function +/// always returns the simplified SVal. The simplified SVal might be a single +/// constant (i.e. `ConcreteInt`). +SVal simplifyToSVal(ProgramStateRef State, SymbolRef Sym); + } // namespace ento } // namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h index 87a49cf4ffe..61dfdbb0688 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -33,6 +33,7 @@ namespace clang { +class AnalyzerOptions; class BlockDecl; class CXXBoolLiteralExpr; class CXXMethodDecl; @@ -66,6 +67,8 @@ protected: ProgramStateManager &StateMgr; + const AnalyzerOptions &AnOpts; + /// The scalar type to use for array indices. const QualType ArrayIndexTy; @@ -96,11 +99,7 @@ protected: public: SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, - ProgramStateManager &stateMgr) - : Context(context), BasicVals(context, alloc), - SymMgr(context, BasicVals, alloc), MemMgr(context, alloc), - StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy), - ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} + ProgramStateManager &stateMgr); virtual ~SValBuilder() = default; @@ -188,6 +187,8 @@ public: MemRegionManager &getRegionManager() { return MemMgr; } const MemRegionManager &getRegionManager() const { return MemMgr; } + const AnalyzerOptions &getAnalyzerOptions() const { return AnOpts; } + // Forwarding methods to SymbolManager. const SymbolConjured* conjureSymbol(const Stmt *stmt, diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h index 76edf150dbe..d58e736ab6a 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -48,7 +48,8 @@ class DependencyScanningService { public: DependencyScanningService(ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager = true, - bool SkipExcludedPPRanges = true); + bool SkipExcludedPPRanges = true, + bool OptimizeArgs = false); ScanningMode getMode() const { return Mode; } @@ -58,6 +59,8 @@ public: bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; } + bool canOptimizeArgs() const { return OptimizeArgs; } + DependencyScanningFilesystemSharedCache &getSharedCache() { return SharedCache; } @@ -70,6 +73,8 @@ private: /// ranges by bumping the buffer pointer in the lexer instead of lexing the /// tokens in the range until reaching the corresponding directive. const bool SkipExcludedPPRanges; + /// Whether to optimize the modules' command-line arguments. + const bool OptimizeArgs; /// The global file system cache. DependencyScanningFilesystemSharedCache SharedCache; }; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h index f88dc472c80..9e2ff82f561 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -77,16 +77,18 @@ public: /// Print out the dependency information into a string using the dependency /// file format that is specified in the options (-MD is the default) and - /// return it. + /// return it. If \p ModuleName isn't empty, this function returns the + /// dependency information of module \p ModuleName. /// /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, dependency file contents otherwise. llvm::Expected - getDependencyFile(const tooling::CompilationDatabase &Compilations, - StringRef CWD); + getDependencyFile(const std::vector &CommandLine, StringRef CWD, + llvm::Optional ModuleName = None); /// Collect the full module dependency graph for the input, ignoring any - /// modules which have already been seen. + /// modules which have already been seen. If \p ModuleName isn't empty, this + /// function returns the full dependency information of module \p ModuleName. /// /// \param AlreadySeen This stores modules which have previously been /// reported. Use the same instance for all calls to this @@ -97,8 +99,9 @@ public: /// \returns a \c StringError with the diagnostic output if clang errors /// occurred, \c FullDependencies otherwise. llvm::Expected - getFullDependencies(const tooling::CompilationDatabase &Compilations, - StringRef CWD, const llvm::StringSet<> &AlreadySeen); + getFullDependencies(const std::vector &CommandLine, + StringRef CWD, const llvm::StringSet<> &AlreadySeen, + llvm::Optional ModuleName = None); private: DependencyScanningWorker Worker; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h index 5903ad13c1d..0f3a5369a02 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -14,7 +14,6 @@ #include "clang/Basic/LLVM.h" #include "clang/Frontend/PCHContainerOperations.h" #include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h" -#include "clang/Tooling/CompilationDatabase.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "llvm/Support/Error.h" @@ -56,31 +55,36 @@ class DependencyScanningWorker { public: DependencyScanningWorker(DependencyScanningService &Service); - /// Run the dependency scanning tool for a given clang driver invocation (as - /// specified for the given Input in the CDB), and report the discovered - /// dependencies to the provided consumer. + /// Run the dependency scanning tool for a given clang driver command-line, + /// and report the discovered dependencies to the provided consumer. If \p + /// ModuleName isn't empty, this function reports the dependencies of module + /// \p ModuleName. /// /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, success otherwise. - llvm::Error computeDependencies(const std::string &Input, - StringRef WorkingDirectory, - const CompilationDatabase &CDB, - DependencyConsumer &Consumer); + llvm::Error computeDependencies(StringRef WorkingDirectory, + const std::vector &CommandLine, + DependencyConsumer &Consumer, + llvm::Optional ModuleName = None); private: - IntrusiveRefCntPtr DiagOpts; std::shared_ptr PCHContainerOps; std::unique_ptr PPSkipMappings; + /// The physical filesystem overlaid by `InMemoryFS`. llvm::IntrusiveRefCntPtr RealFS; + /// The in-memory filesystem laid on top the physical filesystem in `RealFS`. + llvm::IntrusiveRefCntPtr InMemoryFS; /// The file system that is used by each worker when scanning for - /// dependencies. This filesystem persists accross multiple compiler + /// dependencies. This filesystem persists across multiple compiler /// invocations. llvm::IntrusiveRefCntPtr DepFS; - /// The file manager that is reused accross multiple invocations by this + /// The file manager that is reused across multiple invocations by this /// worker. If null, the file manager will not be reused. llvm::IntrusiveRefCntPtr Files; ScanningOutputFormat Format; + /// Whether to optimize the modules' command-line arguments. + bool OptimizeArgs; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h index a9f2b4d0c6f..e61147d6f2b 100644 --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -1,9 +1,8 @@ //===- ModuleDepCollector.h - Callbacks to collect deps ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -102,7 +101,7 @@ struct ModuleDeps { bool ImportedByMainFile = false; /// Compiler invocation that can be used to build this module (without paths). - CompilerInvocation Invocation; + CompilerInvocation BuildInvocation; /// Gets the canonical command line suitable for passing to clang. /// @@ -142,8 +141,7 @@ class ModuleDepCollector; /// \c DependencyConsumer of the parent \c ModuleDepCollector. class ModuleDepCollectorPP final : public PPCallbacks { public: - ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC) - : Instance(I), MDC(MDC) {} + ModuleDepCollectorPP(ModuleDepCollector &MDC) : MDC(MDC) {} void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, @@ -160,8 +158,6 @@ public: void EndOfMainFile() override; private: - /// The compiler instance for the current translation unit. - CompilerInstance &Instance; /// The parent dependency collector. ModuleDepCollector &MDC; /// Working set of direct modular dependencies. @@ -173,7 +169,11 @@ private: /// Adds direct modular dependencies that have already been built to the /// ModuleDeps instance. - void addDirectPrebuiltModuleDeps(const Module *M, ModuleDeps &MD); + void + addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD, + llvm::DenseSet &SeenSubmodules); + void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD, + llvm::DenseSet &SeenSubmodules); /// Traverses the previously collected direct modular dependencies to discover /// transitive modular dependencies and fills the parent \c ModuleDepCollector @@ -190,8 +190,8 @@ private: class ModuleDepCollector final : public DependencyCollector { public: ModuleDepCollector(std::unique_ptr Opts, - CompilerInstance &I, DependencyConsumer &C, - CompilerInvocation &&OriginalCI); + CompilerInstance &ScanInstance, DependencyConsumer &C, + CompilerInvocation &&OriginalCI, bool OptimizeArgs); void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; @@ -199,8 +199,8 @@ public: private: friend ModuleDepCollectorPP; - /// The compiler instance for the current translation unit. - CompilerInstance &Instance; + /// The compiler instance for scanning the current translation unit. + CompilerInstance &ScanInstance; /// The consumer of collected dependency information. DependencyConsumer &Consumer; /// Path to the main source file. @@ -216,6 +216,8 @@ private: std::unique_ptr Opts; /// The original Clang invocation passed to dependency scanner. CompilerInvocation OriginalInvocation; + /// Whether to optimize the modules' command-line arguments. + bool OptimizeArgs; /// Checks whether the module is known as being prebuilt. bool isPrebuiltModule(const Module *M); @@ -223,8 +225,9 @@ private: /// Constructs a CompilerInvocation that can be used to build the given /// module, excluding paths to discovered modular dependencies that are yet to /// be built. - CompilerInvocation - makeInvocationForModuleBuildWithoutPaths(const ModuleDeps &Deps) const; + CompilerInvocation makeInvocationForModuleBuildWithoutPaths( + const ModuleDeps &Deps, + llvm::function_ref Optimize) const; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h index 02fb2875671..c1b7baec7ec 100644 --- a/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h +++ b/clang/include/clang/Tooling/Inclusions/HeaderIncludes.h @@ -84,7 +84,7 @@ private: // An include header quoted with either <> or "". std::string Name; - // The range of the whole line of include directive including any eading + // The range of the whole line of include directive including any leading // whitespaces and trailing comment. tooling::Range R; }; @@ -127,7 +127,6 @@ private: llvm::Regex IncludeRegex; }; - } // namespace tooling } // namespace clang diff --git a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h index 4caaf4121f1..d54f8a402e2 100644 --- a/clang/include/clang/Tooling/Inclusions/IncludeStyle.h +++ b/clang/include/clang/Tooling/Inclusions/IncludeStyle.h @@ -50,6 +50,7 @@ struct IncludeStyle { /// Dependent on the value, multiple ``#include`` blocks can be sorted /// as one and divided based on category. + /// \version 7 IncludeBlocksStyle IncludeBlocks; /// See documentation of ``IncludeCategories``. @@ -113,6 +114,7 @@ struct IncludeStyle { /// Priority: 1 /// SortPriority: 0 /// \endcode + /// \version 7 std::vector IncludeCategories; /// Specify a regular expression of suffixes that are allowed in the @@ -126,6 +128,7 @@ struct IncludeStyle { /// /// For example, if configured to "(_test)?$", then a header a.h would be seen /// as the "main" include in both a.cc and a_test.cc. + /// \version 7 std::string IncludeIsMainRegex; /// Specify a regular expression for files being formatted @@ -146,6 +149,7 @@ struct IncludeStyle { /// also being respected in later phase). Without this option set, /// ``ClassImpl.hpp`` would not have the main include file put on top /// before any other include. + /// \version 7 std::string IncludeIsMainSourceRegex; }; diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h index 73d09662562..c9c6a2ffb7b 100644 --- a/clang/include/clang/Tooling/Tooling.h +++ b/clang/include/clang/Tooling/Tooling.h @@ -115,7 +115,7 @@ public: /// T must derive from clang::FrontendAction. /// /// Example: -/// FrontendActionFactory *Factory = +/// std::unique_ptr Factory = /// newFrontendActionFactory(); template std::unique_ptr newFrontendActionFactory(); @@ -145,7 +145,7 @@ public: /// /// Example: /// struct ProvidesASTConsumers { -/// clang::ASTConsumer *newASTConsumer(); +/// std::unique_ptr newASTConsumer(); /// } Factory; /// std::unique_ptr FactoryAdapter( /// newFrontendActionFactory(&Factory)); @@ -268,11 +268,17 @@ public: ~ToolInvocation(); - /// Set a \c DiagnosticConsumer to use during parsing. + /// Set a \c DiagnosticConsumer to use during driver command-line parsing and + /// the action invocation itself. void setDiagnosticConsumer(DiagnosticConsumer *DiagConsumer) { this->DiagConsumer = DiagConsumer; } + /// Set a \c DiagnosticOptions to use during driver command-line parsing. + void setDiagnosticOptions(DiagnosticOptions *DiagOpts) { + this->DiagOpts = DiagOpts; + } + /// Run the clang invocation. /// /// \returns True if there were no errors during execution. @@ -290,6 +296,7 @@ public: FileManager *Files; std::shared_ptr PCHContainerOps; DiagnosticConsumer *DiagConsumer = nullptr; + DiagnosticOptions *DiagOpts = nullptr; }; /// Utility to run a FrontendAction over a set of files. diff --git a/clang/include/clang/Tooling/Transformer/RangeSelector.h b/clang/include/clang/Tooling/Transformer/RangeSelector.h index 8ff31f7a034..38ec24efec6 100644 --- a/clang/include/clang/Tooling/Transformer/RangeSelector.h +++ b/clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -50,7 +50,7 @@ inline RangeSelector range(std::string BeginID, std::string EndID) { /// Selects the (empty) range [B,B) when \p Selector selects the range [B,E). RangeSelector before(RangeSelector Selector); -/// Selects the the point immediately following \p Selector. That is, the +/// Selects the point immediately following \p Selector. That is, the /// (empty) range [E,E), when \p Selector selects either /// * the CharRange [B,E) or /// * the TokenRange [B,E'] where the token at E' spans the range [E',E). diff --git a/clang/include/clang/Tooling/Transformer/Stencil.h b/clang/include/clang/Tooling/Transformer/Stencil.h index 1b7495eb026..249f95b7391 100644 --- a/clang/include/clang/Tooling/Transformer/Stencil.h +++ b/clang/include/clang/Tooling/Transformer/Stencil.h @@ -117,6 +117,38 @@ inline Stencil ifBound(llvm::StringRef Id, llvm::StringRef TrueText, detail::makeStencil(FalseText)); } +/// Chooses between multiple stencils, based on the presence of bound nodes. \p +/// CaseStencils takes a vector of (ID, \c Stencil) pairs and checks each ID in +/// order to see if it's bound to a node. If so, the associated \c Stencil is +/// run and all other cases are ignored. An optional \p DefaultStencil can be +/// provided to be run if all cases are exhausted beacause none of the provided +/// IDs are bound. If no default case is provided and all cases are exhausted, +/// the stencil will fail with error `llvm::errc::result_out_of_range`. +/// +/// For example, say one matches a statement's type with: +/// anyOf( +/// qualType(isInteger()).bind("int"), +/// qualType(realFloatingPointType()).bind("float"), +/// qualType(isAnyCharacter()).bind("char"), +/// booleanType().bind("bool")) +/// +/// Then, one can decide in a stencil how to construct a literal. +/// cat("a = ", +/// selectBound( +/// {{"int", cat("0")}, +/// {"float", cat("0.0")}, +/// {"char", cat("'\\0'")}, +/// {"bool", cat("false")}})) +/// +/// In addition, one could supply a default case for all other types: +/// selectBound( +/// {{"int", cat("0")}, +/// ... +/// {"bool", cat("false")}}, +/// cat("{}")) +Stencil selectBound(std::vector> CaseStencils, + Stencil DefaultStencil = nullptr); + /// Wraps a \c MatchConsumer in a \c Stencil, so that it can be used in a \c /// Stencil. This supports user-defined extensions to the \c Stencil language. Stencil run(MatchConsumer C); diff --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap index 33fcf9dc757..e850a1cd4b9 100644 --- a/clang/include/clang/module.modulemap +++ b/clang/include/clang/module.modulemap @@ -45,6 +45,7 @@ module Clang_Basic { textual header "Basic/BuiltinsNVPTX.def" textual header "Basic/BuiltinsPPC.def" textual header "Basic/BuiltinsRISCV.def" + textual header "Basic/BuiltinsRISCVVector.def" textual header "Basic/BuiltinsSVE.def" textual header "Basic/BuiltinsSystemZ.def" textual header "Basic/BuiltinsWebAssembly.def" @@ -67,7 +68,6 @@ module Clang_Basic { textual header "Basic/Sanitizers.def" textual header "Basic/TargetCXXABI.def" textual header "Basic/TokenKinds.def" - textual header "Basic/X86Target.def" module * { export * } } diff --git a/clang/lib/ARCMigrate/ARCMT.cpp b/clang/lib/ARCMigrate/ARCMT.cpp index 36fbe90e1e3..4851c434d76 100644 --- a/clang/lib/ARCMigrate/ARCMT.cpp +++ b/clang/lib/ARCMigrate/ARCMT.cpp @@ -65,7 +65,7 @@ bool CapturedDiagList::hasDiagnostic(ArrayRef IDs, while (I != List.end()) { FullSourceLoc diagLoc = I->getLocation(); if ((IDs.empty() || // empty means any diagnostic in the range. - llvm::find(IDs, I->getID()) != IDs.end()) && + llvm::is_contained(IDs, I->getID())) && !diagLoc.isBeforeInTranslationUnitThan(range.getBegin()) && (diagLoc == range.getEnd() || diagLoc.isBeforeInTranslationUnitThan(range.getEnd()))) { diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index c8069b51567..3dfa9a0218a 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -104,7 +104,7 @@ public: bool FoundationIncluded; llvm::SmallPtrSet ObjCProtocolDecls; llvm::SmallVector CFFunctionIBCandidates; - llvm::StringSet<> WhiteListFilenames; + llvm::StringSet<> AllowListFilenames; RetainSummaryManager &getSummaryManager(ASTContext &Ctx) { if (!Summaries) @@ -118,14 +118,14 @@ public: FileRemapper &remapper, FileManager &fileMgr, const PPConditionalDirectiveRecord *PPRec, Preprocessor &PP, bool isOutputFile, - ArrayRef WhiteList) + ArrayRef AllowList) : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions), NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr), Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), IsOutputFile(isOutputFile), FoundationIncluded(false) { // FIXME: StringSet should have insert(iter, iter) to use here. - for (const std::string &Val : WhiteList) - WhiteListFilenames.insert(Val); + for (const std::string &Val : AllowList) + AllowListFilenames.insert(Val); } protected: @@ -151,10 +151,10 @@ protected: void HandleTranslationUnit(ASTContext &Ctx) override; bool canModifyFile(StringRef Path) { - if (WhiteListFilenames.empty()) + if (AllowListFilenames.empty()) return true; - return WhiteListFilenames.find(llvm::sys::path::filename(Path)) - != WhiteListFilenames.end(); + return AllowListFilenames.find(llvm::sys::path::filename(Path)) != + AllowListFilenames.end(); } bool canModifyFile(Optional FE) { if (!FE) @@ -487,9 +487,8 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, // Short circuit 'delegate' properties that contain the name "delegate" or // "dataSource", or have exact name "target" to have 'assign' attribute. - if (PropertyName.equals("target") || - (PropertyName.find("delegate") != StringRef::npos) || - (PropertyName.find("dataSource") != StringRef::npos)) { + if (PropertyName.equals("target") || PropertyName.contains("delegate") || + PropertyName.contains("dataSource")) { QualType QT = Getter->getReturnType(); if (!QT->isRealType()) append_attr(PropertyString, "assign", LParenAdded); @@ -1144,7 +1143,7 @@ static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2, static bool IsValidIdentifier(ASTContext &Ctx, const char *Name) { - if (!isIdentifierHead(Name[0])) + if (!isAsciiIdentifierStart(Name[0])) return false; std::string NameString = Name; NameString[0] = toLowercase(NameString[0]); @@ -1987,7 +1986,7 @@ bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) { return true; } -static std::vector getWhiteListFilenames(StringRef DirPath) { +static std::vector getAllowListFilenames(StringRef DirPath) { using namespace llvm::sys::fs; using namespace llvm::sys::path; @@ -2018,16 +2017,16 @@ MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { if (ObjCMTOpts == FrontendOptions::ObjCMT_None) { // If no specific option was given, enable literals+subscripting transforms // by default. - ObjCMTAction |= FrontendOptions::ObjCMT_Literals | - FrontendOptions::ObjCMT_Subscripting; + ObjCMTAction |= + FrontendOptions::ObjCMT_Literals | FrontendOptions::ObjCMT_Subscripting; } CI.getPreprocessor().addPPCallbacks(std::unique_ptr(PPRec)); - std::vector WhiteList = - getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath); + std::vector AllowList = + getAllowListFilenames(CI.getFrontendOpts().ObjCMTAllowListPath); return std::make_unique( CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper, CI.getFileManager(), PPRec, CI.getPreprocessor(), - /*isOutputFile=*/true, WhiteList); + /*isOutputFile=*/true, AllowList); } namespace { diff --git a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp index e767ad5346c..40220a2eef4 100644 --- a/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp +++ b/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp @@ -146,9 +146,8 @@ private: ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); - if (fname.endswith("Retain") || - fname.find("Create") != StringRef::npos || - fname.find("Copy") != StringRef::npos) { + if (fname.endswith("Retain") || fname.contains("Create") || + fname.contains("Copy")) { // Do not migrate to couple of bridge transfer casts which // cancel each other out. Leave it unchanged so error gets user // attention instead. @@ -168,7 +167,7 @@ private: return; } - if (fname.find("Get") != StringRef::npos) { + if (fname.contains("Get")) { castToObjCObject(E, /*retained=*/false); return; } @@ -253,7 +252,8 @@ private: SourceManager &SM = Pass.Ctx.getSourceManager(); char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1)); - if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts())) + if (Lexer::isAsciiIdentifierContinueChar(PrevChar, + Pass.Ctx.getLangOpts())) BridgeCall += ' '; if (Kind == OBC_BridgeTransfer) diff --git a/clang/lib/ARCMigrate/Transforms.cpp b/clang/lib/ARCMigrate/Transforms.cpp index e274a540e40..ca48160d9c8 100644 --- a/clang/lib/ARCMigrate/Transforms.cpp +++ b/clang/lib/ARCMigrate/Transforms.cpp @@ -95,11 +95,9 @@ bool trans::isPlusOne(const Expr *E) { ento::cocoa::isRefType(callE->getType(), "CF", FD->getIdentifier()->getName())) { StringRef fname = FD->getIdentifier()->getName(); - if (fname.endswith("Retain") || - fname.find("Create") != StringRef::npos || - fname.find("Copy") != StringRef::npos) { + if (fname.endswith("Retain") || fname.contains("Create") || + fname.contains("Copy")) return true; - } } } } diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 9a9233bc1ea..ef333c77116 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -700,7 +700,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, if (!hasLValuePath()) { // No lvalue path: just print the offset. CharUnits O = getLValueOffset(); - CharUnits S = Ctx ? Ctx->getTypeSizeInChars(InnerTy) : CharUnits::Zero(); + CharUnits S = Ctx ? Ctx->getTypeSizeInCharsIfKnown(InnerTy).getValueOr( + CharUnits::Zero()) + : CharUnits::Zero(); if (!O.isZero()) { if (IsReference) Out << "*("; diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index 549088ad4a8..18582782888 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -1,9 +1,8 @@ //===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index e102a3ba508..f0b931bdc90 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -101,7 +101,14 @@ using namespace clang; enum FloatingRank { - BFloat16Rank, Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank + BFloat16Rank, + Float16Rank, + HalfRank, + FloatRank, + DoubleRank, + LongDoubleRank, + Float128Rank, + Ibm128Rank }; /// \returns location that is relevant when searching for Doc comments related @@ -172,29 +179,28 @@ static SourceLocation getDeclLocForCommentSearch(const Decl *D, // Allow association with Y across {} in `typedef struct X {} Y`. isa(D)) return D->getBeginLoc(); - else { - const SourceLocation DeclLoc = D->getLocation(); - if (DeclLoc.isMacroID()) { - if (isa(D)) { - // If location of the typedef name is in a macro, it is because being - // declared via a macro. Try using declaration's starting location as - // the "declaration location". - return D->getBeginLoc(); - } else if (const auto *TD = dyn_cast(D)) { - // If location of the tag decl is inside a macro, but the spelling of - // the tag name comes from a macro argument, it looks like a special - // macro like NS_ENUM is being used to define the tag decl. In that - // case, adjust the source location to the expansion loc so that we can - // attach the comment to the tag decl. - if (SourceMgr.isMacroArgExpansion(DeclLoc) && - TD->isCompleteDefinition()) - return SourceMgr.getExpansionLoc(DeclLoc); - } + + const SourceLocation DeclLoc = D->getLocation(); + if (DeclLoc.isMacroID()) { + if (isa(D)) { + // If location of the typedef name is in a macro, it is because being + // declared via a macro. Try using declaration's starting location as + // the "declaration location". + return D->getBeginLoc(); + } + + if (const auto *TD = dyn_cast(D)) { + // If location of the tag decl is inside a macro, but the spelling of + // the tag name comes from a macro argument, it looks like a special + // macro like NS_ENUM is being used to define the tag decl. In that + // case, adjust the source location to the expansion loc so that we can + // attach the comment to the tag decl. + if (SourceMgr.isMacroArgExpansion(DeclLoc) && TD->isCompleteDefinition()) + return SourceMgr.getExpansionLoc(DeclLoc); } - return DeclLoc; } - return {}; + return DeclLoc; } RawComment *ASTContext::getRawCommentForDeclNoCacheImpl( @@ -984,7 +990,7 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, addTranslationUnitDecl(); } -ASTContext::~ASTContext() { +void ASTContext::cleanup() { // Release the DenseMaps associated with DeclContext objects. // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); @@ -992,6 +998,7 @@ ASTContext::~ASTContext() { // Call all of the deallocation functions on all of their targets. for (auto &Pair : Deallocations) (Pair.first)(Pair.second); + Deallocations.clear(); // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed // because they can contain DenseMaps. @@ -1001,6 +1008,7 @@ ASTContext::~ASTContext() { // Increment in loop to prevent using deallocated memory. if (auto *R = const_cast((I++)->second)) R->Destroy(*this); + ObjCLayouts.clear(); for (llvm::DenseMap::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { @@ -1008,16 +1016,21 @@ ASTContext::~ASTContext() { if (auto *R = const_cast((I++)->second)) R->Destroy(*this); } + ASTRecordLayouts.clear(); for (llvm::DenseMap::iterator A = DeclAttrs.begin(), AEnd = DeclAttrs.end(); A != AEnd; ++A) A->second->~AttrVec(); + DeclAttrs.clear(); for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); + ModuleInitializers.clear(); } +ASTContext::~ASTContext() { cleanup(); } + void ASTContext::setTraversalScope(const std::vector &TopLevelDecls) { TraversalScope = TopLevelDecls; getParentMapContext().clear(); @@ -1112,7 +1125,7 @@ void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) { for (Module *&M : Merged) if (!Found.insert(M).second) M = nullptr; - Merged.erase(std::remove(Merged.begin(), Merged.end(), nullptr), Merged.end()); + llvm::erase_value(Merged, nullptr); } ArrayRef @@ -1308,6 +1321,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, // GNU extension, __float128 for IEEE quadruple precision InitBuiltinType(Float128Ty, BuiltinType::Float128); + // __ibm128 for IBM extended precision + InitBuiltinType(Ibm128Ty, BuiltinType::Ibm128); + // C11 extension ISO/IEC TS 18661-3 InitBuiltinType(Float16Ty, BuiltinType::Float16); @@ -1402,12 +1418,6 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, if (LangOpts.MatrixTypes) InitBuiltinType(IncompleteMatrixIdxTy, BuiltinType::IncompleteMatrixIdx); - // C99 6.2.5p11. - FloatComplexTy = getComplexType(FloatTy); - DoubleComplexTy = getComplexType(DoubleTy); - LongDoubleComplexTy = getComplexType(LongDoubleTy); - Float128ComplexTy = getComplexType(Float128Ty); - // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); @@ -1435,13 +1445,10 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, #include "clang/Basic/AArch64SVEACLETypes.def" } - if (Target.getTriple().isPPC64() && - Target.hasFeature("paired-vector-memops")) { - if (Target.hasFeature("mma")) { + if (Target.getTriple().isPPC64()) { #define PPC_VECTOR_MMA_TYPE(Name, Id, Size) \ InitBuiltinType(Id##Ty, BuiltinType::Id); #include "clang/Basic/PPCTypes.def" - } #define PPC_VECTOR_VSX_TYPE(Name, Id, Size) \ InitBuiltinType(Id##Ty, BuiltinType::Id); #include "clang/Basic/PPCTypes.def" @@ -1704,6 +1711,8 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { return Target->getHalfFormat(); case BuiltinType::Float: return Target->getFloatFormat(); case BuiltinType::Double: return Target->getDoubleFormat(); + case BuiltinType::Ibm128: + return Target->getIbm128Format(); case BuiltinType::LongDouble: if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) return AuxTarget->getLongDoubleFormat(); @@ -1859,7 +1868,7 @@ static getConstantArrayInfoInChars(const ASTContext &Context, Width = llvm::alignTo(Width, Align); return TypeInfoChars(CharUnits::fromQuantity(Width), CharUnits::fromQuantity(Align), - EltInfo.AlignIsRequired); + EltInfo.AlignRequirement); } TypeInfoChars ASTContext::getTypeInfoInChars(const Type *T) const { @@ -1867,8 +1876,7 @@ TypeInfoChars ASTContext::getTypeInfoInChars(const Type *T) const { return getConstantArrayInfoInChars(*this, CAT); TypeInfo Info = getTypeInfo(T); return TypeInfoChars(toCharUnitsFromBits(Info.Width), - toCharUnitsFromBits(Info.Align), - Info.AlignIsRequired); + toCharUnitsFromBits(Info.Align), Info.AlignRequirement); } TypeInfoChars ASTContext::getTypeInfoInChars(QualType T) const { @@ -1876,7 +1884,7 @@ TypeInfoChars ASTContext::getTypeInfoInChars(QualType T) const { } bool ASTContext::isAlignmentRequired(const Type *T) const { - return getTypeInfo(T).AlignIsRequired; + return getTypeInfo(T).AlignRequirement != AlignRequirementKind::None; } bool ASTContext::isAlignmentRequired(QualType T) const { @@ -1928,7 +1936,7 @@ TypeInfo ASTContext::getTypeInfo(const Type *T) const { TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { uint64_t Width = 0; unsigned Align = 8; - bool AlignIsRequired = false; + AlignRequirementKind AlignRequirement = AlignRequirementKind::None; unsigned AS = 0; switch (T->getTypeClass()) { #define TYPE(Class, Base) @@ -1962,7 +1970,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { "Overflow in array type bit size evaluation"); Width = EltInfo.Width * Size; Align = EltInfo.Align; - AlignIsRequired = EltInfo.AlignIsRequired; + AlignRequirement = EltInfo.AlignRequirement; if (!getTargetInfo().getCXXABI().isMicrosoft() || getTargetInfo().getPointerWidth(0) == 64) Width = llvm::alignTo(Width, Align); @@ -2131,6 +2139,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Width = Target->getDoubleWidth(); Align = Target->getDoubleAlign(); break; + case BuiltinType::Ibm128: + Width = Target->getIbm128Width(); + Align = Target->getIbm128Align(); + break; case BuiltinType::LongDouble: if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() || @@ -2299,7 +2311,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); if (unsigned AttrAlign = ED->getMaxAlignment()) { Info.Align = AttrAlign; - Info.AlignIsRequired = true; + Info.AlignRequirement = AlignRequirementKind::RequiredByEnum; } return Info; } @@ -2309,7 +2321,9 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); - AlignIsRequired = RD->hasAttr(); + AlignRequirement = RD->hasAttr() + ? AlignRequirementKind::RequiredByRecord + : AlignRequirementKind::None; break; } @@ -2343,10 +2357,10 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { // attribute(aligned) can only round up) but matches its implementation. if (unsigned AttrAlign = Typedef->getMaxAlignment()) { Align = AttrAlign; - AlignIsRequired = true; + AlignRequirement = AlignRequirementKind::RequiredByTypedef; } else { Align = Info.Align; - AlignIsRequired = Info.AlignIsRequired; + AlignRequirement = Info.AlignRequirement; } Width = Info.Width; break; @@ -2392,7 +2406,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); - return TypeInfo(Width, Align, AlignIsRequired); + return TypeInfo(Width, Align, AlignRequirement); } unsigned ASTContext::getTypeUnadjustedAlign(const Type *T) const { @@ -2478,11 +2492,18 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; if (const auto *RT = T->getAs()) { - if (TI.AlignIsRequired || RT->getDecl()->isInvalidDecl()) + const RecordDecl *RD = RT->getDecl(); + + // When used as part of a typedef, or together with a 'packed' attribute, + // the 'aligned' attribute can be used to decrease alignment. Note that the + // 'packed' case is already taken into consideration when computing the + // alignment, we only need to handle the typedef case here. + if (TI.AlignRequirement == AlignRequirementKind::RequiredByTypedef || + RD->isInvalidDecl()) return ABIAlign; unsigned PreferredAlign = static_cast( - toBits(getASTRecordLayout(RT->getDecl()).PreferredAlignment)); + toBits(getASTRecordLayout(RD).PreferredAlignment)); assert(PreferredAlign >= ABIAlign && "PreferredAlign should be at least as large as ABIAlign."); return PreferredAlign; @@ -2502,7 +2523,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { Target->defaultsToAIXPowerAlignment())) // Don't increase the alignment if an alignment attribute was specified on a // typedef declaration. - if (!TI.AlignIsRequired) + if (!TI.isAlignRequired()) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; @@ -2629,16 +2650,66 @@ static bool unionHasUniqueObjectRepresentations(const ASTContext &Context, return !RD->field_empty(); } -static bool isStructEmpty(QualType Ty) { - const RecordDecl *RD = Ty->castAs()->getDecl(); +static int64_t getSubobjectOffset(const FieldDecl *Field, + const ASTContext &Context, + const clang::ASTRecordLayout & /*Layout*/) { + return Context.getFieldOffset(Field); +} - if (!RD->field_empty()) - return false; +static int64_t getSubobjectOffset(const CXXRecordDecl *RD, + const ASTContext &Context, + const clang::ASTRecordLayout &Layout) { + return Context.toBits(Layout.getBaseClassOffset(RD)); +} - if (const auto *ClassDecl = dyn_cast(RD)) - return ClassDecl->isEmpty(); +static llvm::Optional +structHasUniqueObjectRepresentations(const ASTContext &Context, + const RecordDecl *RD); - return true; +static llvm::Optional +getSubobjectSizeInBits(const FieldDecl *Field, const ASTContext &Context) { + if (Field->getType()->isRecordType()) { + const RecordDecl *RD = Field->getType()->getAsRecordDecl(); + if (!RD->isUnion()) + return structHasUniqueObjectRepresentations(Context, RD); + } + if (!Field->getType()->isReferenceType() && + !Context.hasUniqueObjectRepresentations(Field->getType())) + return llvm::None; + + int64_t FieldSizeInBits = + Context.toBits(Context.getTypeSizeInChars(Field->getType())); + if (Field->isBitField()) { + int64_t BitfieldSize = Field->getBitWidthValue(Context); + if (BitfieldSize > FieldSizeInBits) + return llvm::None; + FieldSizeInBits = BitfieldSize; + } + return FieldSizeInBits; +} + +static llvm::Optional +getSubobjectSizeInBits(const CXXRecordDecl *RD, const ASTContext &Context) { + return structHasUniqueObjectRepresentations(Context, RD); +} + +template +static llvm::Optional structSubobjectsHaveUniqueObjectRepresentations( + const RangeT &Subobjects, int64_t CurOffsetInBits, + const ASTContext &Context, const clang::ASTRecordLayout &Layout) { + for (const auto *Subobject : Subobjects) { + llvm::Optional SizeInBits = + getSubobjectSizeInBits(Subobject, Context); + if (!SizeInBits) + return llvm::None; + if (*SizeInBits != 0) { + int64_t Offset = getSubobjectOffset(Subobject, Context, Layout); + if (Offset != CurOffsetInBits) + return llvm::None; + CurOffsetInBits += *SizeInBits; + } + } + return CurOffsetInBits; } static llvm::Optional @@ -2652,57 +2723,31 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, if (ClassDecl->isDynamicClass()) return llvm::None; - SmallVector, 4> Bases; + SmallVector Bases; for (const auto &Base : ClassDecl->bases()) { // Empty types can be inherited from, and non-empty types can potentially // have tail padding, so just make sure there isn't an error. - if (!isStructEmpty(Base.getType())) { - llvm::Optional Size = structHasUniqueObjectRepresentations( - Context, Base.getType()->castAs()->getDecl()); - if (!Size) - return llvm::None; - Bases.emplace_back(Base.getType(), Size.getValue()); - } + Bases.emplace_back(Base.getType()->getAsCXXRecordDecl()); } - llvm::sort(Bases, [&](const std::pair &L, - const std::pair &R) { - return Layout.getBaseClassOffset(L.first->getAsCXXRecordDecl()) < - Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl()); + llvm::sort(Bases, [&](const CXXRecordDecl *L, const CXXRecordDecl *R) { + return Layout.getBaseClassOffset(L) < Layout.getBaseClassOffset(R); }); - for (const auto &Base : Bases) { - int64_t BaseOffset = Context.toBits( - Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl())); - int64_t BaseSize = Base.second; - if (BaseOffset != CurOffsetInBits) - return llvm::None; - CurOffsetInBits = BaseOffset + BaseSize; - } + llvm::Optional OffsetAfterBases = + structSubobjectsHaveUniqueObjectRepresentations(Bases, CurOffsetInBits, + Context, Layout); + if (!OffsetAfterBases) + return llvm::None; + CurOffsetInBits = *OffsetAfterBases; } - for (const auto *Field : RD->fields()) { - if (!Field->getType()->isReferenceType() && - !Context.hasUniqueObjectRepresentations(Field->getType())) - return llvm::None; - - int64_t FieldSizeInBits = - Context.toBits(Context.getTypeSizeInChars(Field->getType())); - if (Field->isBitField()) { - int64_t BitfieldSize = Field->getBitWidthValue(Context); - - if (BitfieldSize > FieldSizeInBits) - return llvm::None; - FieldSizeInBits = BitfieldSize; - } - - int64_t FieldOffsetInBits = Context.getFieldOffset(Field); - - if (FieldOffsetInBits != CurOffsetInBits) - return llvm::None; - - CurOffsetInBits = FieldSizeInBits + FieldOffsetInBits; - } + llvm::Optional OffsetAfterFields = + structSubobjectsHaveUniqueObjectRepresentations( + RD->fields(), CurOffsetInBits, Context, Layout); + if (!OffsetAfterFields) + return llvm::None; + CurOffsetInBits = *OffsetAfterFields; return CurOffsetInBits; } @@ -4770,6 +4815,23 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, return QualType(Spec, 0); } +static bool +getCanonicalTemplateArguments(const ASTContext &C, + ArrayRef OrigArgs, + SmallVectorImpl &CanonArgs) { + bool AnyNonCanonArgs = false; + unsigned NumArgs = OrigArgs.size(); + CanonArgs.resize(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + const TemplateArgument &OrigArg = OrigArgs[I]; + TemplateArgument &CanonArg = CanonArgs[I]; + CanonArg = C.getCanonicalTemplateArgument(OrigArg); + if (!CanonArg.structurallyEquals(OrigArg)) + AnyNonCanonArgs = true; + } + return AnyNonCanonArgs; +} + QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef Args) const { assert(!Template.getAsDependentTemplateName() && @@ -4782,10 +4844,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector CanonArgs; - unsigned NumArgs = Args.size(); - CanonArgs.reserve(NumArgs); - for (const TemplateArgument &Arg : Args) - CanonArgs.push_back(getCanonicalTemplateArgument(Arg)); + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); // Determine whether this canonical template specialization type already // exists. @@ -4800,7 +4859,7 @@ QualType ASTContext::getCanonicalTemplateSpecializationType( if (!Spec) { // Allocate a new canonical template specialization type. void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * CanonArgs.size()), TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs, @@ -4942,14 +5001,9 @@ ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword CanonKeyword = Keyword; if (Keyword == ETK_None) CanonKeyword = ETK_Typename; - bool AnyNonCanonArgs = false; - unsigned NumArgs = Args.size(); - SmallVector CanonArgs(NumArgs); - for (unsigned I = 0; I != NumArgs; ++I) { - CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); - if (!CanonArgs[I].structurallyEquals(Args[I])) - AnyNonCanonArgs = true; - } + SmallVector CanonArgs; + bool AnyNonCanonArgs = + ::getCanonicalTemplateArguments(*this, Args, CanonArgs); QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { @@ -4962,7 +5016,7 @@ ASTContext::getDependentTemplateSpecializationType( } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + sizeof(TemplateArgument) * Args.size()), TypeAlignment); T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, Name, Args, Canon); @@ -5123,11 +5177,8 @@ QualType ASTContext::getObjCObjectType( // sorted-and-uniqued list of protocols and the type arguments // canonicalized. QualType canonical; - bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), - effectiveTypeArgs.end(), - [&](QualType type) { - return type.isCanonical(); - }); + bool typeArgsAreCanonical = llvm::all_of( + effectiveTypeArgs, [&](QualType type) { return type.isCanonical(); }); bool protocolsSorted = areSortedAndUniqued(protocols); if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { // Determine the canonical type arguments. @@ -5454,6 +5505,29 @@ QualType ASTContext::getTypeOfType(QualType tofType) const { return QualType(tot, 0); } +/// getReferenceQualifiedType - Given an expr, will return the type for +/// that expression, as in [dcl.type.simple]p4 but without taking id-expressions +/// and class member access into account. +QualType ASTContext::getReferenceQualifiedType(const Expr *E) const { + // C++11 [dcl.type.simple]p4: + // [...] + QualType T = E->getType(); + switch (E->getValueKind()) { + // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the + // type of e; + case VK_XValue: + return getRValueReferenceType(T); + // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the + // type of e; + case VK_LValue: + return getLValueReferenceType(T); + // - otherwise, decltype(e) is the type of e. + case VK_PRValue: + return T; + } + llvm_unreachable("Unknown value kind"); +} + /// Unlike many "get" functions, we don't unique DecltypeType /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there @@ -5524,15 +5598,10 @@ QualType ASTContext::getUnaryTransformType(QualType BaseType, return QualType(ut, 0); } -/// getAutoType - Return the uniqued reference to the 'auto' type which has been -/// deduced to the given type, or to the canonical undeduced 'auto' type, or the -/// canonical deduced-but-dependent 'auto' type. -QualType -ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack, - ConceptDecl *TypeConstraintConcept, - ArrayRef TypeConstraintArgs) const { - assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); +QualType ASTContext::getAutoTypeInternal( + QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, + bool IsPack, ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs, bool IsCanon) const { if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !TypeConstraintConcept && !IsDependent) return getAutoDeductType(); @@ -5545,21 +5614,52 @@ ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); + QualType Canon; + if (!IsCanon) { + if (DeducedType.isNull()) { + SmallVector CanonArgs; + bool AnyNonCanonArgs = + ::getCanonicalTemplateArguments(*this, TypeConstraintArgs, CanonArgs); + if (AnyNonCanonArgs) { + Canon = getAutoTypeInternal(QualType(), Keyword, IsDependent, IsPack, + TypeConstraintConcept, CanonArgs, true); + // Find the insert position again. + AutoTypes.FindNodeOrInsertPos(ID, InsertPos); + } + } else { + Canon = DeducedType.getCanonicalType(); + } + } + void *Mem = Allocate(sizeof(AutoType) + - sizeof(TemplateArgument) * TypeConstraintArgs.size(), + sizeof(TemplateArgument) * TypeConstraintArgs.size(), TypeAlignment); auto *AT = new (Mem) AutoType( DeducedType, Keyword, (IsDependent ? TypeDependence::DependentInstantiation : TypeDependence::None) | (IsPack ? TypeDependence::UnexpandedPack : TypeDependence::None), - TypeConstraintConcept, TypeConstraintArgs); + Canon, TypeConstraintConcept, TypeConstraintArgs); Types.push_back(AT); - if (InsertPos) - AutoTypes.InsertNode(AT, InsertPos); + AutoTypes.InsertNode(AT, InsertPos); return QualType(AT, 0); } +/// getAutoType - Return the uniqued reference to the 'auto' type which has been +/// deduced to the given type, or to the canonical undeduced 'auto' type, or the +/// canonical deduced-but-dependent 'auto' type. +QualType +ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, + bool IsDependent, bool IsPack, + ConceptDecl *TypeConstraintConcept, + ArrayRef TypeConstraintArgs) const { + assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); + assert((!IsDependent || DeducedType.isNull()) && + "A dependent auto should be undeduced"); + return getAutoTypeInternal(DeducedType, Keyword, IsDependent, IsPack, + TypeConstraintConcept, TypeConstraintArgs); +} + /// Return the uniqued reference to the deduced template specialization type /// which has been deduced to the given type, or to the canonical undeduced /// such type, or the canonical deduced-but-dependent such type. @@ -5577,8 +5677,7 @@ QualType ASTContext::getDeducedTemplateSpecializationType( auto *DTST = new (*this, TypeAlignment) DeducedTemplateSpecializationType(Template, DeducedType, IsDependent); Types.push_back(DTST); - if (InsertPos) - DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); + DeducedTemplateSpecializationTypes.InsertNode(DTST, InsertPos); return QualType(DTST, 0); } @@ -5615,7 +5714,7 @@ QualType ASTContext::getAutoDeductType() const { if (AutoDeductTy.isNull()) AutoDeductTy = QualType(new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, - TypeDependence::None, + TypeDependence::None, QualType(), /*concept*/ nullptr, /*args*/ {}), 0); return AutoDeductTy; @@ -5783,7 +5882,11 @@ QualType ASTContext::getUnqualifiedArrayType(QualType type, /// Attempt to unwrap two types that may both be array types with the same bound /// (or both be array types of unknown bound) for the purpose of comparing the /// cv-decomposition of two types per C++ [conv.qual]. -void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2) { +/// +/// \param AllowPiMismatch Allow the Pi1 and Pi2 to differ as described in +/// C++20 [conv.qual], if permitted by the current language mode. +void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2, + bool AllowPiMismatch) { while (true) { auto *AT1 = getAsArrayType(T1); if (!AT1) @@ -5795,12 +5898,21 @@ void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2) { // If we don't have two array types with the same constant bound nor two // incomplete array types, we've unwrapped everything we can. + // C++20 also permits one type to be a constant array type and the other + // to be an incomplete array type. + // FIXME: Consider also unwrapping array of unknown bound and VLA. if (auto *CAT1 = dyn_cast(AT1)) { auto *CAT2 = dyn_cast(AT2); - if (!CAT2 || CAT1->getSize() != CAT2->getSize()) + if (!((CAT2 && CAT1->getSize() == CAT2->getSize()) || + (AllowPiMismatch && getLangOpts().CPlusPlus20 && + isa(AT2)))) return; - } else if (!isa(AT1) || - !isa(AT2)) { + } else if (isa(AT1)) { + if (!(isa(AT2) || + (AllowPiMismatch && getLangOpts().CPlusPlus20 && + isa(AT2)))) + return; + } else { return; } @@ -5819,10 +5931,14 @@ void ASTContext::UnwrapSimilarArrayTypes(QualType &T1, QualType &T2) { /// "unwraps" pointer and pointer-to-member types to compare them at each /// level. /// +/// \param AllowPiMismatch Allow the Pi1 and Pi2 to differ as described in +/// C++20 [conv.qual], if permitted by the current language mode. +/// /// \return \c true if a pointer type was unwrapped, \c false if we reached a /// pair of types that can't be unwrapped further. -bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2) { - UnwrapSimilarArrayTypes(T1, T2); +bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2, + bool AllowPiMismatch) { + UnwrapSimilarArrayTypes(T1, T2, AllowPiMismatch); const auto *T1PtrType = T1->getAs(); const auto *T2PtrType = T2->getAs(); @@ -5883,7 +5999,7 @@ bool ASTContext::hasCvrSimilarType(QualType T1, QualType T2) { if (hasSameType(T1, T2)) return true; - if (!UnwrapSimilarTypes(T1, T2)) + if (!UnwrapSimilarTypes(T1, T2, /*AllowPiMismatch*/ false)) return false; } } @@ -6066,9 +6182,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { NNS->getAsNamespaceAlias()->getNamespace() ->getOriginalNamespace()); + // The difference between TypeSpec and TypeSpecWithTemplate is that the + // latter will have the 'template' keyword when printed. case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); + const Type *T = getCanonicalType(NNS->getAsType()); // If we have some kind of dependent-named type (e.g., "typename T::type"), // break it apart into its prefix and identifier, then reconsititute those @@ -6078,14 +6196,16 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { // typedef typename T::type T1; // typedef typename T1::type T2; if (const auto *DNT = T->getAs()) - return NestedNameSpecifier::Create(*this, DNT->getQualifier(), - const_cast(DNT->getIdentifier())); + return NestedNameSpecifier::Create( + *this, DNT->getQualifier(), + const_cast(DNT->getIdentifier())); + if (const auto *DTST = T->getAs()) + return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, + const_cast(T)); - // Otherwise, just canonicalize the type, and force it to be a TypeSpec. - // FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the - // first place? + // TODO: Set 'Template' parameter to true for other template types. return NestedNameSpecifier::Create(*this, nullptr, false, - const_cast(T.getTypePtr())); + const_cast(T)); } case NestedNameSpecifier::Global: @@ -6253,6 +6373,7 @@ static FloatingRank getFloatingRank(QualType T) { case BuiltinType::LongDouble: return LongDoubleRank; case BuiltinType::Float128: return Float128Rank; case BuiltinType::BFloat16: return BFloat16Rank; + case BuiltinType::Ibm128: return Ibm128Rank; } } @@ -6268,10 +6389,11 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, case BFloat16Rank: llvm_unreachable("Complex bfloat16 is not supported"); case Float16Rank: case HalfRank: llvm_unreachable("Complex half is not supported"); - case FloatRank: return FloatComplexTy; - case DoubleRank: return DoubleComplexTy; - case LongDoubleRank: return LongDoubleComplexTy; - case Float128Rank: return Float128ComplexTy; + case Ibm128Rank: return getComplexType(Ibm128Ty); + case FloatRank: return getComplexType(FloatTy); + case DoubleRank: return getComplexType(DoubleTy); + case LongDoubleRank: return getComplexType(LongDoubleTy); + case Float128Rank: return getComplexType(Float128Ty); } } @@ -6284,6 +6406,8 @@ QualType ASTContext::getFloatingTypeOfSizeWithinDomain(QualType Size, case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; case Float128Rank: return Float128Ty; + case Ibm128Rank: + return Ibm128Ty; } llvm_unreachable("getFloatingRank(): illegal value for rank"); } @@ -7001,7 +7125,7 @@ ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl) const { void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, QualType T, std::string& S, bool Extended) const { - // Encode type qualifer, 'in', 'inout', etc. for the parameter. + // Encode type qualifier, 'in', 'inout', etc. for the parameter. getObjCEncodingForTypeQualifier(QT, S); // Encode parameter type. ObjCEncOptions Options = ObjCEncOptions() @@ -7259,6 +7383,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, case BuiltinType::BFloat16: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::Ibm128: case BuiltinType::Half: case BuiltinType::ShortAccum: case BuiltinType::Accum: @@ -7705,7 +7830,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, .setExpandStructures()), FD); if (FD || Options.EncodingProperty() || Options.EncodeClassNames()) { - // Note that we do extended encoding of protocol qualifer list + // Note that we do extended encoding of protocol qualifier list // Only when doing ivar or property encoding. S += '"'; for (const auto *I : OPT->quals()) { @@ -8674,8 +8799,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, static uint64_t getSVETypeSize(ASTContext &Context, const BuiltinType *Ty) { assert(Ty->isVLSTBuiltinType() && "Invalid SVE Type"); return Ty->getKind() == BuiltinType::SveBool - ? Context.getLangOpts().ArmSveVectorBits / Context.getCharWidth() - : Context.getLangOpts().ArmSveVectorBits; + ? (Context.getLangOpts().VScaleMin * 128) / Context.getCharWidth() + : Context.getLangOpts().VScaleMin * 128; } bool ASTContext::areCompatibleSveTypes(QualType FirstType, @@ -9105,13 +9230,9 @@ void getIntersectionOfProtocols(ASTContext &Context, // Remove any implied protocols from the list of inherited protocols. if (!ImpliedProtocols.empty()) { - IntersectionSet.erase( - std::remove_if(IntersectionSet.begin(), - IntersectionSet.end(), - [&](ObjCProtocolDecl *proto) -> bool { - return ImpliedProtocols.count(proto) > 0; - }), - IntersectionSet.end()); + llvm::erase_if(IntersectionSet, [&](ObjCProtocolDecl *proto) -> bool { + return ImpliedProtocols.count(proto) > 0; + }); } // Sort the remaining protocols by name. @@ -9649,11 +9770,19 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, bool Unqualified, bool BlockReturnType) { + // For C++ we will not reach this code with reference types (see below), + // for OpenMP variant call overloading we might. + // // C++ [expr]: If an expression initially has the type "reference to T", the // type is adjusted to "T" prior to any further analysis, the expression // designates the object or function denoted by the reference, and the // expression is an lvalue unless the reference is an rvalue reference and // the expression is a function call (possibly inside parentheses). + if (LangOpts.OpenMP && LHS->getAs() && + RHS->getAs() && LHS->getTypeClass() == RHS->getTypeClass()) + return mergeTypes(LHS->getAs()->getPointeeType(), + RHS->getAs()->getPointeeType(), + OfBlockPointer, Unqualified, BlockReturnType); if (LHS->getAs() || RHS->getAs()) return {}; @@ -9976,7 +10105,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, unsigned LHSBits = LHS->castAs()->getNumBits(); unsigned RHSBits = RHS->castAs()->getNumBits(); - // Like unsigned/int, shouldn't have a type if they dont match. + // Like unsigned/int, shouldn't have a type if they don't match. if (LHSUnsigned != RHSUnsigned) return {}; @@ -10617,7 +10746,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, } // On some targets such as PowerPC, some of the builtins are defined with custom -// type decriptors for target-dependent types. These descriptors are decoded in +// type descriptors for target-dependent types. These descriptors are decoded in // other functions, but it may be useful to be able to fall back to default // descriptor decoding to define builtins mixing target-dependent and target- // independent types. This function allows decoding one type descriptor with @@ -11174,19 +11303,21 @@ QualType ASTContext::getIntTypeForBitwidth(unsigned DestWidth, /// sets floating point QualTy according to specified bitwidth. /// Returns empty type if there is no appropriate target types. QualType ASTContext::getRealTypeForBitwidth(unsigned DestWidth, - bool ExplicitIEEE) const { - TargetInfo::RealType Ty = - getTargetInfo().getRealTypeByWidth(DestWidth, ExplicitIEEE); + FloatModeKind ExplicitType) const { + FloatModeKind Ty = + getTargetInfo().getRealTypeByWidth(DestWidth, ExplicitType); switch (Ty) { - case TargetInfo::Float: + case FloatModeKind::Float: return FloatTy; - case TargetInfo::Double: + case FloatModeKind::Double: return DoubleTy; - case TargetInfo::LongDouble: + case FloatModeKind::LongDouble: return LongDoubleTy; - case TargetInfo::Float128: + case FloatModeKind::Float128: return Float128Ty; - case TargetInfo::NoFloat: + case FloatModeKind::Ibm128: + return Ibm128Ty; + case FloatModeKind::NoFloat: return {}; } @@ -11615,13 +11746,9 @@ ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const { assert(TD != nullptr); ParsedTargetAttr ParsedAttr = TD->parse(); - ParsedAttr.Features.erase( - llvm::remove_if(ParsedAttr.Features, - [&](const std::string &Feat) { - return !Target->isValidFeatureName( - StringRef{Feat}.substr(1)); - }), - ParsedAttr.Features.end()); + llvm::erase_if(ParsedAttr.Features, [&](const std::string &Feat) { + return !Target->isValidFeatureName(StringRef{Feat}.substr(1)); + }); return ParsedAttr; } @@ -11666,6 +11793,9 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->getCPUSpecificCPUDispatchFeatures( SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); std::vector Features(FeaturesTmp.begin(), FeaturesTmp.end()); + Features.insert(Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else { FeatureMap = Target->getTargetOpts().FeatureMap; @@ -11712,86 +11842,3 @@ StringRef ASTContext::getCUIDHash() const { CUIDHash = llvm::utohexstr(llvm::MD5Hash(LangOpts.CUID), /*LowerCase=*/true); return CUIDHash; } - -// Get the closest named parent, so we can order the sycl naming decls somewhere -// that mangling is meaningful. -static const DeclContext *GetNamedParent(const CXXRecordDecl *RD) { - const DeclContext *DC = RD->getDeclContext(); - - while (!isa(DC)) - DC = DC->getParent(); - return DC; -} - -void ASTContext::AddSYCLKernelNamingDecl(const CXXRecordDecl *RD) { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - RD = RD->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - assert(RD->getLocation().isValid() && - "Invalid location on kernel naming decl"); - - (void)SYCLKernelNamingTypes[DC].insert(RD); -} - -bool ASTContext::IsSYCLKernelNamingDecl(const NamedDecl *ND) const { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - const auto *RD = dyn_cast(ND); - if (!RD) - return false; - RD = RD->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - auto Itr = SYCLKernelNamingTypes.find(DC); - - if (Itr == SYCLKernelNamingTypes.end()) - return false; - - return Itr->getSecond().count(RD); -} - -// Filters the Decls list to those that share the lambda mangling with the -// passed RD. -void ASTContext::FilterSYCLKernelNamingDecls( - const CXXRecordDecl *RD, - llvm::SmallVectorImpl &Decls) { - - if (!SYCLKernelFilterContext) - SYCLKernelFilterContext.reset( - ItaniumMangleContext::create(*this, getDiagnostics())); - - llvm::SmallString<128> LambdaSig; - llvm::raw_svector_ostream Out(LambdaSig); - SYCLKernelFilterContext->mangleLambdaSig(RD, Out); - - llvm::erase_if(Decls, [this, &LambdaSig](const CXXRecordDecl *LocalRD) { - llvm::SmallString<128> LocalLambdaSig; - llvm::raw_svector_ostream LocalOut(LocalLambdaSig); - SYCLKernelFilterContext->mangleLambdaSig(LocalRD, LocalOut); - return LambdaSig != LocalLambdaSig; - }); -} - -unsigned ASTContext::GetSYCLKernelNamingIndex(const NamedDecl *ND) { - assert(getLangOpts().isSYCL() && "Only valid for SYCL programs"); - assert(IsSYCLKernelNamingDecl(ND) && - "Lambda not involved in mangling asked for a naming index?"); - - const CXXRecordDecl *RD = cast(ND)->getCanonicalDecl(); - const DeclContext *DC = GetNamedParent(RD); - - auto Itr = SYCLKernelNamingTypes.find(DC); - assert(Itr != SYCLKernelNamingTypes.end() && "Not a valid DeclContext?"); - - const llvm::SmallPtrSet &Set = Itr->getSecond(); - - llvm::SmallVector Decls{Set.begin(), Set.end()}; - - FilterSYCLKernelNamingDecls(RD, Decls); - - llvm::sort(Decls, [](const CXXRecordDecl *LHS, const CXXRecordDecl *RHS) { - return LHS->getLambdaManglingNumber() < RHS->getLambdaManglingNumber(); - }); - - return llvm::find(Decls, RD) - Decls.begin(); -} diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index dc22481d0a8..7e435e8b35b 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -1088,6 +1088,9 @@ class TemplateDiff { Ty->getAs()) return TST; + if (const auto* SubstType = Ty->getAs()) + Ty = SubstType->getReplacementType(); + const RecordType *RT = Ty->getAs(); if (!RT) diff --git a/clang/lib/AST/ASTDumper.cpp b/clang/lib/AST/ASTDumper.cpp index 3d368a0a7b6..c6df61f79e2 100644 --- a/clang/lib/AST/ASTDumper.cpp +++ b/clang/lib/AST/ASTDumper.cpp @@ -90,15 +90,7 @@ void ASTDumper::dumpTemplateDeclSpecialization(const SpecializationDecl *D, // FIXME: The redecls() range sometimes has elements of a less-specific // type. (In particular, ClassTemplateSpecializationDecl::redecls() gives // us TagDecls, and should give CXXRecordDecls). - auto *Redecl = dyn_cast(RedeclWithBadType); - if (!Redecl) { - // Found the injected-class-name for a class template. This will be dumped - // as part of its surrounding class so we don't need to dump it here. - assert(isa(RedeclWithBadType) && - "expected an injected-class-name"); - continue; - } - + auto *Redecl = cast(RedeclWithBadType); switch (Redecl->getTemplateSpecializationKind()) { case TSK_ExplicitInstantiationDeclaration: case TSK_ExplicitInstantiationDefinition: diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 787e02029da..710e40bbb4b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -76,6 +76,7 @@ namespace clang { using llvm::make_error; using llvm::Error; using llvm::Expected; + using ExpectedTypePtr = llvm::Expected; using ExpectedType = llvm::Expected; using ExpectedStmt = llvm::Expected; using ExpectedExpr = llvm::Expected; @@ -160,7 +161,9 @@ namespace clang { // Call the import function of ASTImporter for a baseclass of type `T` and // cast the return value to `T`. template - Expected import(T *From) { + auto import(T *From) + -> std::conditional_t::value, + Expected, Expected> { auto ToOrErr = Importer.Import(From); if (!ToOrErr) return ToOrErr.takeError(); @@ -168,7 +171,7 @@ namespace clang { } template - Expected import(const T *From) { + auto import(const T *From) { return import(const_cast(From)); } @@ -186,22 +189,6 @@ namespace clang { return import(*From); } - // Helper for chaining together multiple imports. If an error is detected, - // subsequent imports will return default constructed nodes, so that failure - // can be detected with a single conditional branch after a sequence of - // imports. - template T importChecked(Error &Err, const T &From) { - // Don't attempt to import nodes if we hit an error earlier. - if (Err) - return T{}; - Expected MaybeVal = import(From); - if (!MaybeVal) { - Err = MaybeVal.takeError(); - return T{}; - } - return *MaybeVal; - } - ExplicitSpecifier importExplicitSpecifier(Error &Err, ExplicitSpecifier ESpec); @@ -313,11 +300,8 @@ namespace clang { auto *ToNamed = cast(ToD); DeclContextLookupResult FromLookup = FromDC->lookup(FromNamed->getDeclName()); - for (NamedDecl *ND : FromLookup) - if (ND == FromNamed) { - ToDC->makeDeclVisibleInContext(ToNamed); - break; - } + if (llvm::is_contained(FromLookup, FromNamed)) + ToDC->makeDeclVisibleInContext(ToNamed); } } } @@ -383,6 +367,8 @@ namespace clang { ExpectedType VisitTemplateTypeParmType(const TemplateTypeParmType *T); ExpectedType VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T); + ExpectedType + VisitSubstTemplateTypeParmPackType(const SubstTemplateTypeParmPackType *T); ExpectedType VisitTemplateSpecializationType( const TemplateSpecializationType *T); ExpectedType VisitElaboratedType(const ElaboratedType *T); @@ -475,21 +461,13 @@ namespace clang { Error ImportDefaultArgOfParmVarDecl(const ParmVarDecl *FromParam, ParmVarDecl *ToParam); + Expected + ImportInheritedConstructor(const InheritedConstructor &From); + template bool hasSameVisibilityContextAndLinkage(T *Found, T *From); - bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); - bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, - bool Complain = true); - bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, - bool Complain = true); - bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); - bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); - bool IsStructuralMatch(FunctionTemplateDecl *From, - FunctionTemplateDecl *To); - bool IsStructuralMatch(FunctionDecl *From, FunctionDecl *To); - bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); - bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); + bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true); ExpectedDecl VisitDecl(Decl *D); ExpectedDecl VisitImportDecl(ImportDecl *D); ExpectedDecl VisitEmptyDecl(EmptyDecl *D); @@ -597,6 +575,7 @@ namespace clang { ExpectedStmt VisitSourceLocExpr(SourceLocExpr *E); ExpectedStmt VisitVAArgExpr(VAArgExpr *E); ExpectedStmt VisitChooseExpr(ChooseExpr *E); + ExpectedStmt VisitShuffleVectorExpr(ShuffleVectorExpr *E); ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E); ExpectedStmt VisitGenericSelectionExpr(GenericSelectionExpr *E); ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E); @@ -667,6 +646,22 @@ namespace clang { ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E); ExpectedStmt VisitCXXFoldExpr(CXXFoldExpr *E); + // Helper for chaining together multiple imports. If an error is detected, + // subsequent imports will return default constructed nodes, so that failure + // can be detected with a single conditional branch after a sequence of + // imports. + template T importChecked(Error &Err, const T &From) { + // Don't attempt to import nodes if we hit an error earlier. + if (Err) + return T{}; + Expected MaybeVal = import(From); + if (!MaybeVal) { + Err = MaybeVal.takeError(); + return T{}; + } + return *MaybeVal; + } + template Error ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) { using ItemT = std::remove_reference_t; @@ -1161,12 +1156,12 @@ ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { if (!ToPointeeTypeOrErr) return ToPointeeTypeOrErr.takeError(); - ExpectedType ClassTypeOrErr = import(QualType(T->getClass(), 0)); + ExpectedTypePtr ClassTypeOrErr = import(T->getClass()); if (!ClassTypeOrErr) return ClassTypeOrErr.takeError(); - return Importer.getToContext().getMemberPointerType( - *ToPointeeTypeOrErr, (*ClassTypeOrErr).getTypePtr()); + return Importer.getToContext().getMemberPointerType(*ToPointeeTypeOrErr, + *ClassTypeOrErr); } ExpectedType @@ -1472,18 +1467,32 @@ ExpectedType ASTNodeImporter::VisitTemplateTypeParmType( ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( const SubstTemplateTypeParmType *T) { - ExpectedType ReplacedOrErr = import(QualType(T->getReplacedParameter(), 0)); + Expected ReplacedOrErr = + import(T->getReplacedParameter()); if (!ReplacedOrErr) return ReplacedOrErr.takeError(); - const TemplateTypeParmType *Replaced = - cast((*ReplacedOrErr).getTypePtr()); ExpectedType ToReplacementTypeOrErr = import(T->getReplacementType()); if (!ToReplacementTypeOrErr) return ToReplacementTypeOrErr.takeError(); return Importer.getToContext().getSubstTemplateTypeParmType( - Replaced, (*ToReplacementTypeOrErr).getCanonicalType()); + *ReplacedOrErr, ToReplacementTypeOrErr->getCanonicalType()); +} + +ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + Expected ReplacedOrErr = + import(T->getReplacedParameter()); + if (!ReplacedOrErr) + return ReplacedOrErr.takeError(); + + Expected ToArgumentPack = import(T->getArgumentPack()); + if (!ToArgumentPack) + return ToArgumentPack.takeError(); + + return Importer.getToContext().getSubstTemplateTypeParmPackType( + *ReplacedOrErr, *ToArgumentPack); } ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( @@ -1498,7 +1507,7 @@ ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( return std::move(Err); QualType ToCanonType; - if (!QualType(T, 0).isCanonical()) { + if (!T->isCanonicalUnqualified()) { QualType FromCanonType = Importer.getFromContext().getCanonicalType(QualType(T, 0)); if (ExpectedType TyOrErr = import(FromCanonType)) @@ -1806,7 +1815,7 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { RecordDecl *FromRecordDecl = nullptr; RecordDecl *ToRecordDecl = nullptr; // If we have a field that is an ArrayType we need to check if the array - // element is a RecordDecl and if so we need to import the defintion. + // element is a RecordDecl and if so we need to import the definition. if (FieldFrom->getType()->isArrayType()) { // getBaseElementTypeUnsafe(...) handles multi-dimensonal arrays for us. FromRecordDecl = FieldFrom->getType()->getBaseElementTypeUnsafe()->getAsRecordDecl(); @@ -2158,96 +2167,17 @@ getStructuralEquivalenceKind(const ASTImporter &Importer) { } bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { - StructuralEquivalenceContext Ctx( - Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), - false, Complain); - return Ctx.IsEquivalent(From, To); -} - -bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, - RecordDecl *ToRecord, bool Complain) { // Eliminate a potential failure point where we attempt to re-import // something we're trying to import while completing ToRecord. - Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord); + Decl *ToOrigin = Importer.GetOriginalDecl(To); if (ToOrigin) { - auto *ToOriginRecord = dyn_cast(ToOrigin); - if (ToOriginRecord) - ToRecord = ToOriginRecord; + To = ToOrigin; } - StructuralEquivalenceContext Ctx(Importer.getFromContext(), - ToRecord->getASTContext(), - Importer.getNonEquivalentDecls(), - getStructuralEquivalenceKind(Importer), - false, Complain); - return Ctx.IsEquivalent(FromRecord, ToRecord); -} - -bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, - bool Complain) { StructuralEquivalenceContext Ctx( Importer.getFromContext(), Importer.getToContext(), Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), false, Complain); - return Ctx.IsEquivalent(FromVar, ToVar); -} - -bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { - // Eliminate a potential failure point where we attempt to re-import - // something we're trying to import while completing ToEnum. - if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum)) - if (auto *ToOriginEnum = dyn_cast(ToOrigin)) - ToEnum = ToOriginEnum; - - StructuralEquivalenceContext Ctx( - Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); - return Ctx.IsEquivalent(FromEnum, ToEnum); -} - -bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, - FunctionTemplateDecl *To) { - StructuralEquivalenceContext Ctx( - Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), - false, false); - return Ctx.IsEquivalent(From, To); -} - -bool ASTNodeImporter::IsStructuralMatch(FunctionDecl *From, FunctionDecl *To) { - StructuralEquivalenceContext Ctx( - Importer.getFromContext(), Importer.getToContext(), - Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), - false, false); - return Ctx.IsEquivalent(From, To); -} - -bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, - EnumConstantDecl *ToEC) { - const llvm::APSInt &FromVal = FromEC->getInitVal(); - const llvm::APSInt &ToVal = ToEC->getInitVal(); - - return FromVal.isSigned() == ToVal.isSigned() && - FromVal.getBitWidth() == ToVal.getBitWidth() && - FromVal == ToVal; -} - -bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, - ClassTemplateDecl *To) { - StructuralEquivalenceContext Ctx(Importer.getFromContext(), - Importer.getToContext(), - Importer.getNonEquivalentDecls(), - getStructuralEquivalenceKind(Importer)); - return Ctx.IsEquivalent(From, To); -} - -bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, - VarTemplateDecl *To) { - StructuralEquivalenceContext Ctx(Importer.getFromContext(), - Importer.getToContext(), - Importer.getNonEquivalentDecls(), - getStructuralEquivalenceKind(Importer)); return Ctx.IsEquivalent(From, To); } @@ -3242,13 +3172,14 @@ static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { QualType FromTy = D->getType(); - const FunctionProtoType *FromFPT = FromTy->getAs(); + const auto *FromFPT = FromTy->getAs(); assert(FromFPT && "Must be called on FunctionProtoType"); - if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) { + if (const AutoType *AutoT = + FromFPT->getReturnType()->getContainedAutoType()) { QualType DeducedT = AutoT->getDeducedType(); - if (const RecordType *RecordT = - DeducedT.isNull() ? nullptr : dyn_cast(DeducedT)) { - RecordDecl *RD = RecordT->getDecl(); + if (const auto *RecordT = + !DeducedT.isNull() ? DeducedT->getAs() : nullptr) { + const RecordDecl *RD = RecordT->getDecl(); assert(RD); if (isAncestorDeclContextOf(D, RD)) { assert(RD->getLexicalDeclContext() == RD->getDeclContext()); @@ -3256,9 +3187,8 @@ bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { } } } - if (const TypedefType *TypedefT = - dyn_cast(FromFPT->getReturnType())) { - TypedefNameDecl *TD = TypedefT->getDecl(); + if (const auto *TypedefT = FromFPT->getReturnType()->getAs()) { + const TypedefNameDecl *TD = TypedefT->getDecl(); assert(TD); if (isAncestorDeclContextOf(D, TD)) { assert(TD->getLexicalDeclContext() == TD->getDeclContext()); @@ -3399,11 +3329,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); QualType FromTy = D->getType(); + TypeSourceInfo *FromTSI = D->getTypeSourceInfo(); // Set to true if we do not import the type of the function as is. There are // cases when the original type would result in an infinite recursion during // the import. To avoid an infinite recursion when importing, we create the // FunctionDecl with a simplified function type and update it only after the // relevant AST nodes are already imported. + // The type is related to TypeSourceInfo (it references the type), so we must + // do the same with TypeSourceInfo. bool UsedDifferentProtoType = false; if (const auto *FromFPT = FromTy->getAs()) { QualType FromReturnTy = FromFPT->getReturnType(); @@ -3430,11 +3363,13 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } FromTy = Importer.getFromContext().getFunctionType( FromReturnTy, FromFPT->getParamTypes(), FromEPI); + FromTSI = Importer.getFromContext().getTrivialTypeSourceInfo( + FromTy, D->getBeginLoc()); } Error Err = Error::success(); auto T = importChecked(Err, FromTy); - auto TInfo = importChecked(Err, D->getTypeSourceInfo()); + auto TInfo = importChecked(Err, FromTSI); auto ToInnerLocStart = importChecked(Err, D->getInnerLocStart()); auto ToEndLoc = importChecked(Err, D->getEndLoc()); auto ToQualifierLoc = importChecked(Err, D->getQualifierLoc()); @@ -3459,13 +3394,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { importExplicitSpecifier(Err, FromConstructor->getExplicitSpecifier()); if (Err) return std::move(Err); + auto ToInheritedConstructor = InheritedConstructor(); + if (FromConstructor->isInheritingConstructor()) { + Expected ImportedInheritedCtor = + import(FromConstructor->getInheritedConstructor()); + if (!ImportedInheritedCtor) + return ImportedInheritedCtor.takeError(); + ToInheritedConstructor = *ImportedInheritedCtor; + } if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), - ToInnerLocStart, NameInfo, T, TInfo, ESpec, D->isInlineSpecified(), - D->isImplicit(), D->getConstexprKind(), - InheritedConstructor(), // FIXME: Properly import inherited - // constructor info - TrailingRequiresClause)) + ToInnerLocStart, NameInfo, T, TInfo, ESpec, D->UsesFPIntrin(), + D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(), + ToInheritedConstructor, TrailingRequiresClause)) return ToFunction; } else if (CXXDestructorDecl *FromDtor = dyn_cast(D)) { @@ -3477,9 +3418,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); if (GetImportedOrCreateDecl( - ToFunction, D, Importer.getToContext(), cast(DC), - ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), - D->isImplicit(), D->getConstexprKind(), TrailingRequiresClause)) + ToFunction, D, Importer.getToContext(), cast(DC), + ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(), + D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(), + TrailingRequiresClause)) return ToFunction; CXXDestructorDecl *ToDtor = cast(ToFunction); @@ -3493,15 +3435,16 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), - ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), ESpec, - D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) + ToInnerLocStart, NameInfo, T, TInfo, D->UsesFPIntrin(), + D->isInlineSpecified(), ESpec, D->getConstexprKind(), + SourceLocation(), TrailingRequiresClause)) return ToFunction; } else if (auto *Method = dyn_cast(D)) { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), cast(DC), ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), - Method->isInlineSpecified(), D->getConstexprKind(), - SourceLocation(), TrailingRequiresClause)) + Method->UsesFPIntrin(), Method->isInlineSpecified(), + D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; } else if (auto *Guide = dyn_cast(D)) { ExplicitSpecifier ESpec = @@ -3519,9 +3462,9 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, - NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->getConstexprKind(), - TrailingRequiresClause)) + NameInfo, T, TInfo, D->getStorageClass(), D->UsesFPIntrin(), + D->isInlineSpecified(), D->hasWrittenPrototype(), + D->getConstexprKind(), TrailingRequiresClause)) return ToFunction; } @@ -3604,6 +3547,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setType(*TyOrErr); else return TyOrErr.takeError(); + if (Expected TSIOrErr = import(D->getTypeSourceInfo())) + ToFunction->setTypeSourceInfo(*TSIOrErr); + else + return TSIOrErr.takeError(); } // FIXME: Other bits to merge? @@ -4197,6 +4144,17 @@ Error ASTNodeImporter::ImportDefaultArgOfParmVarDecl( return Error::success(); } +Expected +ASTNodeImporter::ImportInheritedConstructor(const InheritedConstructor &From) { + Error Err = Error::success(); + CXXConstructorDecl *ToBaseCtor = importChecked(Err, From.getConstructor()); + ConstructorUsingShadowDecl *ToShadow = + importChecked(Err, From.getShadowDecl()); + if (Err) + return std::move(Err); + return InheritedConstructor(ToShadow, ToBaseCtor); +} + ExpectedDecl ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { // Parameters are created in the translation unit's context, then moved // into the function declaration's context afterward. @@ -4736,9 +4694,29 @@ ExpectedDecl ASTNodeImporter::VisitUsingShadowDecl(UsingShadowDecl *D) { return ToTargetOrErr.takeError(); UsingShadowDecl *ToShadow; - if (GetImportedOrCreateDecl(ToShadow, D, Importer.getToContext(), DC, Loc, - Name, *ToIntroducerOrErr, *ToTargetOrErr)) - return ToShadow; + if (auto *FromConstructorUsingShadow = + dyn_cast(D)) { + Error Err = Error::success(); + ConstructorUsingShadowDecl *Nominated = importChecked( + Err, FromConstructorUsingShadow->getNominatedBaseClassShadowDecl()); + if (Err) + return std::move(Err); + // The 'Target' parameter of ConstructorUsingShadowDecl constructor + // is really the "NominatedBaseClassShadowDecl" value if it exists + // (see code of ConstructorUsingShadowDecl::ConstructorUsingShadowDecl). + // We should pass the NominatedBaseClassShadowDecl to it (if non-null) to + // get the correct values. + if (GetImportedOrCreateDecl( + ToShadow, D, Importer.getToContext(), DC, Loc, + cast(*ToIntroducerOrErr), + Nominated ? Nominated : *ToTargetOrErr, + FromConstructorUsingShadow->constructsVirtualBase())) + return ToShadow; + } else { + if (GetImportedOrCreateDecl(ToShadow, D, Importer.getToContext(), DC, Loc, + Name, *ToIntroducerOrErr, *ToTargetOrErr)) + return ToShadow; + } ToShadow->setLexicalDeclContext(LexicalDC); ToShadow->setAccess(D->getAccess()); @@ -6339,7 +6317,7 @@ ExpectedStmt ASTNodeImporter::VisitIfStmt(IfStmt *S) { if (Err) return std::move(Err); - return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->isConstexpr(), + return IfStmt::Create(Importer.getToContext(), ToIfLoc, S->getStatementKind(), ToInit, ToConditionVariable, ToCond, ToLParenLoc, ToRParenLoc, ToThen, ToElseLoc, ToElse); } @@ -6710,6 +6688,24 @@ ExpectedStmt ASTNodeImporter::VisitChooseExpr(ChooseExpr *E) { ToRParenLoc, CondIsTrue); } +ExpectedStmt ASTNodeImporter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + Error Err = Error::success(); + auto ToRParenLoc = importChecked(Err, E->getRParenLoc()); + auto ToBeginLoc = importChecked(Err, E->getBeginLoc()); + auto ToType = importChecked(Err, E->getType()); + const unsigned NumSubExprs = E->getNumSubExprs(); + + llvm::SmallVector ToSubExprs; + llvm::ArrayRef FromSubExprs(E->getSubExprs(), NumSubExprs); + ToSubExprs.resize(NumSubExprs); + + if ((Err = ImportContainerChecked(FromSubExprs, ToSubExprs))) + return std::move(Err); + + return new (Importer.getToContext()) ShuffleVectorExpr( + Importer.getToContext(), ToSubExprs, ToType, ToBeginLoc, ToRParenLoc); +} + ExpectedStmt ASTNodeImporter::VisitGNUNullExpr(GNUNullExpr *E) { ExpectedType TypeOrErr = import(E->getType()); if (!TypeOrErr) @@ -8339,7 +8335,7 @@ ASTImporter::Import(ExprWithCleanups::CleanupObject From) { return make_error(ImportError::UnsupportedConstruct); } -Expected ASTImporter::Import(const Type *FromT) { +ExpectedTypePtr ASTImporter::Import(const Type *FromT) { if (!FromT) return FromT; @@ -8349,7 +8345,7 @@ Expected ASTImporter::Import(const Type *FromT) { if (Pos != ImportedTypes.end()) return Pos->second; - // Import the type + // Import the type. ASTNodeImporter Importer(*this); ExpectedType ToTOrErr = Importer.Visit(FromT); if (!ToTOrErr) @@ -8365,7 +8361,7 @@ Expected ASTImporter::Import(QualType FromT) { if (FromT.isNull()) return QualType{}; - Expected ToTyOrErr = Import(FromT.getTypePtr()); + ExpectedTypePtr ToTyOrErr = Import(FromT.getTypePtr()); if (!ToTyOrErr) return ToTyOrErr.takeError(); @@ -8388,59 +8384,269 @@ Expected ASTImporter::Import(TypeSourceInfo *FromTSI) { return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr); } -Expected ASTImporter::Import(const Attr *FromAttr) { +// To use this object, it should be created before the new attribute is created, +// and destructed after it is created. The construction already performs the +// import of the data. +template struct AttrArgImporter { + AttrArgImporter(const AttrArgImporter &) = delete; + AttrArgImporter(AttrArgImporter &&) = default; + AttrArgImporter &operator=(const AttrArgImporter &) = delete; + AttrArgImporter &operator=(AttrArgImporter &&) = default; + + AttrArgImporter(ASTNodeImporter &I, Error &Err, const T &From) + : To(I.importChecked(Err, From)) {} + + const T &value() { return To; } + +private: + T To; +}; + +// To use this object, it should be created before the new attribute is created, +// and destructed after it is created. The construction already performs the +// import of the data. The array data is accessible in a pointer form, this form +// is used by the attribute classes. This object should be created once for the +// array data to be imported (the array size is not imported, just copied). +template struct AttrArgArrayImporter { + AttrArgArrayImporter(const AttrArgArrayImporter &) = delete; + AttrArgArrayImporter(AttrArgArrayImporter &&) = default; + AttrArgArrayImporter &operator=(const AttrArgArrayImporter &) = delete; + AttrArgArrayImporter &operator=(AttrArgArrayImporter &&) = default; + + AttrArgArrayImporter(ASTNodeImporter &I, Error &Err, + const llvm::iterator_range &From, + unsigned ArraySize) { + if (Err) + return; + To.reserve(ArraySize); + Err = I.ImportContainerChecked(From, To); + } + + T *value() { return To.data(); } + +private: + llvm::SmallVector To; +}; + +class AttrImporter { + Error Err{Error::success()}; Attr *ToAttr = nullptr; - SourceRange ToRange; - if (Error Err = importInto(ToRange, FromAttr->getRange())) - return std::move(Err); + ASTImporter &Importer; + ASTNodeImporter NImporter; + +public: + AttrImporter(ASTImporter &I) : Importer(I), NImporter(I) {} + + // 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. + template AttrArgImporter importArg(const T &From) { + return AttrArgImporter(NImporter, Err, From); + } + + // Create an "importer" for an attribute parameter that has array type. + // Result of the 'value()' of that object is to be passed to the function + // 'importAttr', then the size of the array as next argument. + template + AttrArgArrayImporter importArrayArg(const llvm::iterator_range &From, + unsigned ArraySize) { + return AttrArgArrayImporter(NImporter, Err, From, ArraySize); + } + + // Create an attribute object with the specified arguments. + // The 'FromAttr' is the original (not imported) attribute, the 'ImportedArg' + // should be values that are passed to the 'Create' function of the attribute. + // (The 'Create' with 'ASTContext' first and 'AttributeCommonInfo' last is + // used here.) As much data is copied or imported from the old attribute + // as possible. The passed arguments should be already imported. + // If an import error happens, the internal error is set to it, and any + // further import attempt is ignored. + template + void importAttr(const T *FromAttr, Arg &&...ImportedArg) { + static_assert(std::is_base_of::value, + "T should be subclass of Attr."); + assert(!ToAttr && "Use one AttrImporter to import one Attribute object."); + + const IdentifierInfo *ToAttrName = Importer.Import(FromAttr->getAttrName()); + const IdentifierInfo *ToScopeName = + Importer.Import(FromAttr->getScopeName()); + SourceRange ToAttrRange = + NImporter.importChecked(Err, FromAttr->getRange()); + SourceLocation ToScopeLoc = + NImporter.importChecked(Err, FromAttr->getScopeLoc()); + + if (Err) + return; + + AttributeCommonInfo ToI(ToAttrName, ToScopeName, ToAttrRange, ToScopeLoc, + FromAttr->getParsedKind(), FromAttr->getSyntax(), + FromAttr->getAttributeSpellingListIndex()); + // The "SemanticSpelling" is not needed to be passed to the constructor. + // That value is recalculated from the SpellingListIndex if needed. + ToAttr = T::Create(Importer.getToContext(), + std::forward(ImportedArg)..., ToI); + + ToAttr->setImplicit(FromAttr->isImplicit()); + ToAttr->setPackExpansion(FromAttr->isPackExpansion()); + if (auto *ToInheritableAttr = dyn_cast(ToAttr)) + ToInheritableAttr->setInherited(FromAttr->isInherited()); + } + + // Create a clone of the 'FromAttr' and import its source range only. + // This causes objects with invalid references to be created if the 'FromAttr' + // contains other data that should be imported. + void cloneAttr(const Attr *FromAttr) { + assert(!ToAttr && "Use one AttrImporter to import one Attribute object."); + + SourceRange ToRange = NImporter.importChecked(Err, FromAttr->getRange()); + if (Err) + return; + + ToAttr = FromAttr->clone(Importer.getToContext()); + ToAttr->setRange(ToRange); + } + + // Get the result of the previous import attempt (can be used only once). + llvm::Expected getResult() && { + if (Err) + return std::move(Err); + assert(ToAttr && "Attribute should be created."); + return ToAttr; + } +}; + +Expected ASTImporter::Import(const Attr *FromAttr) { + AttrImporter AI(*this); // FIXME: Is there some kind of AttrVisitor to use here? switch (FromAttr->getKind()) { case attr::Aligned: { auto *From = cast(FromAttr); - AlignedAttr *To; - auto CreateAlign = [&](bool IsAlignmentExpr, void *Alignment) { - return AlignedAttr::Create(ToContext, IsAlignmentExpr, Alignment, ToRange, - From->getSyntax(), - From->getSemanticSpelling()); - }; - if (From->isAlignmentExpr()) { - if (auto ToEOrErr = Import(From->getAlignmentExpr())) - To = CreateAlign(true, *ToEOrErr); - else - return ToEOrErr.takeError(); - } else { - if (auto ToTOrErr = Import(From->getAlignmentType())) - To = CreateAlign(false, *ToTOrErr); - else - return ToTOrErr.takeError(); - } - To->setInherited(From->isInherited()); - To->setPackExpansion(From->isPackExpansion()); - To->setImplicit(From->isImplicit()); - ToAttr = To; + if (From->isAlignmentExpr()) + AI.importAttr(From, true, AI.importArg(From->getAlignmentExpr()).value()); + else + AI.importAttr(From, false, + AI.importArg(From->getAlignmentType()).value()); break; } + case attr::Format: { const auto *From = cast(FromAttr); - FormatAttr *To; - IdentifierInfo *ToAttrType = Import(From->getType()); - To = FormatAttr::Create(ToContext, ToAttrType, From->getFormatIdx(), - From->getFirstArg(), ToRange, From->getSyntax()); - To->setInherited(From->isInherited()); - ToAttr = To; + AI.importAttr(From, Import(From->getType()), From->getFormatIdx(), + From->getFirstArg()); break; } - default: - // FIXME: 'clone' copies every member but some of them should be imported. - // Handle other Attrs that have parameters that should be imported. - ToAttr = FromAttr->clone(ToContext); - ToAttr->setRange(ToRange); + + case attr::AssertCapability: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); break; } - assert(ToAttr && "Attribute should be created."); - - return ToAttr; + case attr::AcquireCapability: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::TryAcquireCapability: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(), + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::ReleaseCapability: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::RequiresCapability: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::GuardedBy: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getArg()).value()); + break; + } + case attr::PtGuardedBy: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getArg()).value()); + break; + } + case attr::AcquiredAfter: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::AcquiredBefore: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::AssertExclusiveLock: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::AssertSharedLock: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::ExclusiveTrylockFunction: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(), + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::SharedTrylockFunction: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getSuccessValue()).value(), + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + case attr::LockReturned: { + const auto *From = cast(FromAttr); + AI.importAttr(From, AI.importArg(From->getArg()).value()); + break; + } + case attr::LocksExcluded: { + const auto *From = cast(FromAttr); + AI.importAttr(From, + AI.importArrayArg(From->args(), From->args_size()).value(), + From->args_size()); + break; + } + + default: { + // The default branch works for attributes that have no arguments to import. + // FIXME: Handle every attribute type that has arguments of type to import + // (most often Expr* or Decl* or type) in the switch above. + AI.cloneAttr(FromAttr); + break; + } + } + + return std::move(AI).getResult(); } Decl *ASTImporter::GetAlreadyImportedOrNull(const Decl *FromD) const { @@ -8597,6 +8803,11 @@ Expected ASTImporter::Import(Decl *FromD) { return ToDOrErr; } +llvm::Expected +ASTImporter::Import(const InheritedConstructor &From) { + return ASTNodeImporter(*this).ImportInheritedConstructor(From); +} + Expected ASTImporter::ImportContext(DeclContext *FromDC) { if (!FromDC) return FromDC; @@ -8741,12 +8952,11 @@ ASTImporter::Import(NestedNameSpecifier *FromNNS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: - if (Expected TyOrErr = - Import(QualType(FromNNS->getAsType(), 0u))) { + if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) { bool TSTemplate = FromNNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate; return NestedNameSpecifier::Create(ToContext, Prefix, TSTemplate, - TyOrErr->getTypePtr()); + *TyOrErr); } else { return TyOrErr.takeError(); } @@ -9381,16 +9591,14 @@ ASTNodeImporter::ImportAPValue(const APValue &FromValue) { } } else { FromElemTy = FromValue.getLValueBase().getTypeInfoType(); - QualType ImpTypeInfo = importChecked( - Err, - QualType(FromValue.getLValueBase().get().getType(), - 0)); + const Type *ImpTypeInfo = importChecked( + Err, FromValue.getLValueBase().get().getType()); QualType ImpType = importChecked(Err, FromValue.getLValueBase().getTypeInfoType()); if (Err) return std::move(Err); - Base = APValue::LValueBase::getTypeInfo( - TypeInfoLValue(ImpTypeInfo.getTypePtr()), ImpType); + Base = APValue::LValueBase::getTypeInfo(TypeInfoLValue(ImpTypeInfo), + ImpType); } } CharUnits Offset = FromValue.getLValueOffset(); diff --git a/clang/lib/AST/ASTImporterLookupTable.cpp b/clang/lib/AST/ASTImporterLookupTable.cpp index b78cc0c053f..ef42561c6f9 100644 --- a/clang/lib/AST/ASTImporterLookupTable.cpp +++ b/clang/lib/AST/ASTImporterLookupTable.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTImporterLookupTable.h" #include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/Support/FormatVariadic.h" namespace clang { @@ -93,10 +94,19 @@ void ASTImporterLookupTable::add(DeclContext *DC, NamedDecl *ND) { } void ASTImporterLookupTable::remove(DeclContext *DC, NamedDecl *ND) { - DeclList &Decls = LookupTable[DC][ND->getDeclName()]; + const DeclarationName Name = ND->getDeclName(); + DeclList &Decls = LookupTable[DC][Name]; bool EraseResult = Decls.remove(ND); (void)EraseResult; - assert(EraseResult == true && "Trying to remove not contained Decl"); +#ifndef NDEBUG + if (!EraseResult) { + std::string Message = + llvm::formatv("Trying to remove not contained Decl '{0}' of type {1}", + Name.getAsString(), DC->getDeclKindName()) + .str(); + llvm_unreachable(Message.c_str()); + } +#endif } void ASTImporterLookupTable::add(NamedDecl *ND) { @@ -145,7 +155,7 @@ ASTImporterLookupTable::lookup(DeclContext *DC, DeclarationName Name) const { } bool ASTImporterLookupTable::contains(DeclContext *DC, NamedDecl *ND) const { - return 0 < lookup(DC, ND->getDeclName()).count(ND); + return lookup(DC, ND->getDeclName()).contains(ND); } void ASTImporterLookupTable::dump(DeclContext *DC) const { diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index c4ff05ba932..e85feb77919 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1591,6 +1591,26 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumConstantDecl *D1, + EnumConstantDecl *D2) { + const llvm::APSInt &FromVal = D1->getInitVal(); + const llvm::APSInt &ToVal = D2->getInitVal(); + if (FromVal.isSigned() != ToVal.isSigned()) + return false; + if (FromVal.getBitWidth() != ToVal.getBitWidth()) + return false; + if (FromVal != ToVal) + return false; + + if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier())) + return false; + + // Init expressions are the most expensive check, so do them last. + return IsStructurallyEquivalent(Context, D1->getInitExpr(), + D2->getInitExpr()); +} + /// Determine structural equivalence of two enums. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, EnumDecl *D1, EnumDecl *D2) { diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 4a033bf50bd..b333f4618ef 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -14,9 +14,11 @@ #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" +#include "clang/AST/TypeLoc.h" using namespace clang; @@ -24,9 +26,12 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { {NKI_None, ""}, {NKI_None, "TemplateArgument"}, {NKI_None, "TemplateArgumentLoc"}, + {NKI_None, "LambdaCapture"}, {NKI_None, "TemplateName"}, {NKI_None, "NestedNameSpecifierLoc"}, {NKI_None, "QualType"}, +#define TYPELOC(CLASS, PARENT) {NKI_##PARENT, #CLASS "TypeLoc"}, +#include "clang/AST/TypeLocNodes.def" {NKI_None, "TypeLoc"}, {NKI_None, "CXXBaseSpecifier"}, {NKI_None, "CXXCtorInitializer"}, @@ -44,6 +49,9 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = { #define GEN_CLANG_CLAUSE_CLASS #define CLAUSE_CLASS(Enum, Str, Class) {NKI_OMPClause, #Class}, #include "llvm/Frontend/OpenMP/OMP.inc" + {NKI_None, "Attr"}, +#define ATTR(A) {NKI_Attr, #A "Attr"}, +#include "clang/Basic/AttrList.inc" }; bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const { @@ -123,6 +131,17 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) { llvm_unreachable("invalid type kind"); } + ASTNodeKind ASTNodeKind::getFromNode(const TypeLoc &T) { + switch (T.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: \ + return ASTNodeKind(NKI_##CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("invalid typeloc kind"); + } + ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { switch (C.getClauseKind()) { #define GEN_CLANG_CLAUSE_CLASS @@ -134,7 +153,17 @@ ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { llvm_unreachable("unexpected OpenMP clause kind"); #include "llvm/Frontend/OpenMP/OMP.inc" } - llvm_unreachable("invalid stmt kind"); + llvm_unreachable("invalid omp clause kind"); +} + +ASTNodeKind ASTNodeKind::getFromNode(const Attr &A) { + switch (A.getKind()) { +#define ATTR(A) \ + case attr::A: \ + return ASTNodeKind(NKI_##A##Attr); +#include "clang/Basic/AttrList.inc" + } + llvm_unreachable("invalid attr kind"); } void DynTypedNode::print(llvm::raw_ostream &OS, @@ -162,6 +191,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS, S->printPretty(OS, nullptr, PP); else if (const Type *T = get()) QualType(T, 0).print(OS, PP); + else if (const Attr *A = get()) + A->printPretty(OS, PP); else OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n"; } @@ -195,5 +226,7 @@ SourceRange DynTypedNode::getSourceRange() const { return SourceRange(C->getBeginLoc(), C->getEndLoc()); if (const auto *CBS = get()) return CBS->getSourceRange(); + if (const auto *A = get()) + return A->getRange(); return SourceRange(); } diff --git a/clang/lib/AST/AttrDocTable.cpp b/clang/lib/AST/AttrDocTable.cpp new file mode 100644 index 00000000000..3bfedac8b8f --- /dev/null +++ b/clang/lib/AST/AttrDocTable.cpp @@ -0,0 +1,27 @@ +//===--- AttrDocTable.cpp - implements Attr::getDocumentation() -*- 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 contains out-of-line methods for Attr classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "llvm/ADT/StringRef.h" + +#include "AttrDocTable.inc" + +static const llvm::StringRef AttrDoc[] = { +#define ATTR(NAME) AttrDoc_##NAME, +#include "clang/Basic/AttrList.inc" +}; + +llvm::StringRef clang::Attr::getDocumentation(clang::attr::Kind K) { + if(K < llvm::array_lengthof(AttrDoc)) + return AttrDoc[K]; + return ""; +} diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 662f86722fa..a3b46752c51 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -195,6 +195,40 @@ void OMPDeclareVariantAttr::printPrettyPragma( OS << ")"; } OS << " match(" << traitInfos << ")"; + + auto PrintExprs = [&OS, &Policy](Expr **Begin, Expr **End) { + for (Expr **I = Begin; I != End; ++I) { + assert(*I && "Expected non-null Stmt"); + if (I != Begin) + OS << ","; + (*I)->printPretty(OS, nullptr, Policy); + } + }; + if (adjustArgsNothing_size()) { + OS << " adjust_args(nothing:"; + PrintExprs(adjustArgsNothing_begin(), adjustArgsNothing_end()); + OS << ")"; + } + if (adjustArgsNeedDevicePtr_size()) { + OS << " adjust_args(need_device_ptr:"; + PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end()); + OS << ")"; + } + + auto PrintInteropTypes = [&OS](InteropType *Begin, InteropType *End) { + for (InteropType *I = Begin; I != End; ++I) { + if (I != Begin) + OS << ", "; + OS << "interop("; + OS << ConvertInteropTypeToStr(*I); + OS << ")"; + } + }; + if (appendArgs_size()) { + OS << " append_args("; + PrintInteropTypes(appendArgs_begin(), appendArgs_end()); + OS << ")"; + } } #include "clang/AST/AttrImpl.inc" diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index 9027fa7a751..96a6f344be7 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -465,7 +465,7 @@ void OverridingMethods::add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding) { SmallVectorImpl &SubobjectOverrides = Overrides[OverriddenSubobject]; - if (llvm::find(SubobjectOverrides, Overriding) == SubobjectOverrides.end()) + if (!llvm::is_contained(SubobjectOverrides, Overriding)) SubobjectOverrides.push_back(Overriding); } @@ -671,9 +671,7 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { // FIXME: IsHidden reads from Overriding from the middle of a remove_if // over the same sequence! Is this guaranteed to work? - Overriding.erase( - std::remove_if(Overriding.begin(), Overriding.end(), IsHidden), - Overriding.end()); + llvm::erase_if(Overriding, IsHidden); } } } diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index a02cc9d119f..fae3640d5ff 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -210,6 +210,7 @@ void DeclInfo::fill() { IsObjCMethod = false; IsInstanceMethod = false; IsClassMethod = false; + IsVariadic = false; ParamVars = None; TemplateParameters = nullptr; @@ -221,6 +222,7 @@ void DeclInfo::fill() { CurrentDecl = CommentDecl; Decl::Kind K = CommentDecl->getKind(); + const TypeSourceInfo *TSI = nullptr; switch (K) { default: // Defaults are should be good for declarations we don't handle explicitly. @@ -247,6 +249,8 @@ void DeclInfo::fill() { IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } + IsVariadic = FD->isVariadic(); + assert(involvesFunctionType()); break; } case Decl::ObjCMethod: { @@ -257,6 +261,8 @@ void DeclInfo::fill() { IsObjCMethod = true; IsInstanceMethod = MD->isInstanceMethod(); IsClassMethod = !IsInstanceMethod; + IsVariadic = MD->isVariadic(); + assert(involvesFunctionType()); break; } case Decl::FunctionTemplate: { @@ -267,6 +273,8 @@ void DeclInfo::fill() { ParamVars = FD->parameters(); ReturnType = FD->getReturnType(); TemplateParameters = FTD->getTemplateParameters(); + IsVariadic = FD->isVariadic(); + assert(involvesFunctionType()); break; } case Decl::ClassTemplate: { @@ -293,71 +301,47 @@ void DeclInfo::fill() { Kind = ClassKind; break; case Decl::Var: + if (const VarTemplateDecl *VTD = + cast(CommentDecl)->getDescribedVarTemplate()) { + TemplateKind = TemplateSpecialization; + TemplateParameters = VTD->getTemplateParameters(); + } + LLVM_FALLTHROUGH; case Decl::Field: case Decl::EnumConstant: case Decl::ObjCIvar: case Decl::ObjCAtDefsField: - case Decl::ObjCProperty: { - const TypeSourceInfo *TSI; + case Decl::ObjCProperty: if (const auto *VD = dyn_cast(CommentDecl)) TSI = VD->getTypeSourceInfo(); else if (const auto *PD = dyn_cast(CommentDecl)) TSI = PD->getTypeSourceInfo(); - else - TSI = nullptr; - if (TSI) { - TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); - FunctionTypeLoc FTL; - if (getFunctionTypeLoc(TL, FTL)) { - ParamVars = FTL.getParams(); - ReturnType = FTL.getReturnLoc().getType(); - } - } Kind = VariableKind; break; + case Decl::VarTemplate: { + const VarTemplateDecl *VTD = cast(CommentDecl); + Kind = VariableKind; + TemplateKind = Template; + TemplateParameters = VTD->getTemplateParameters(); + if (const VarDecl *VD = VTD->getTemplatedDecl()) + TSI = VD->getTypeSourceInfo(); + break; } case Decl::Namespace: Kind = NamespaceKind; break; case Decl::TypeAlias: - case Decl::Typedef: { + case Decl::Typedef: Kind = TypedefKind; - // If this is a typedef / using to something we consider a function, extract - // arguments and return type. - const TypeSourceInfo *TSI = - K == Decl::Typedef - ? cast(CommentDecl)->getTypeSourceInfo() - : cast(CommentDecl)->getTypeSourceInfo(); - if (!TSI) - break; - TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); - FunctionTypeLoc FTL; - if (getFunctionTypeLoc(TL, FTL)) { - Kind = FunctionKind; - ParamVars = FTL.getParams(); - ReturnType = FTL.getReturnLoc().getType(); - } + TSI = cast(CommentDecl)->getTypeSourceInfo(); break; - } case Decl::TypeAliasTemplate: { const TypeAliasTemplateDecl *TAT = cast(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); - TypeAliasDecl *TAD = TAT->getTemplatedDecl(); - if (!TAD) - break; - - const TypeSourceInfo *TSI = TAD->getTypeSourceInfo(); - if (!TSI) - break; - TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); - FunctionTypeLoc FTL; - if (getFunctionTypeLoc(TL, FTL)) { - Kind = FunctionKind; - ParamVars = FTL.getParams(); - ReturnType = FTL.getReturnLoc().getType(); - } + if (TypeAliasDecl *TAD = TAT->getTemplatedDecl()) + TSI = TAD->getTypeSourceInfo(); break; } case Decl::Enum: @@ -365,6 +349,20 @@ void DeclInfo::fill() { break; } + // If the type is a typedef / using to something we consider a function, + // extract arguments and return type. + if (TSI) { + TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); + FunctionTypeLoc FTL; + if (getFunctionTypeLoc(TL, FTL)) { + ParamVars = FTL.getParams(); + ReturnType = FTL.getReturnLoc().getType(); + if (const auto *FPT = dyn_cast(FTL.getTypePtr())) + IsVariadic = FPT->isVariadic(); + assert(involvesFunctionType()); + } + } + IsFilled = true; } diff --git a/clang/lib/AST/CommentBriefParser.cpp b/clang/lib/AST/CommentBriefParser.cpp index 2b648cbb1d4..2a5f7452b77 100644 --- a/clang/lib/AST/CommentBriefParser.cpp +++ b/clang/lib/AST/CommentBriefParser.cpp @@ -123,7 +123,7 @@ std::string BriefParser::Parse() { // We found a paragraph end. This ends the brief description if // \command or its equivalent was explicitly used. // Stop scanning text because an explicit \paragraph is the - // preffered one. + // preferred one. if (InBrief) break; // End first paragraph if we found some non-whitespace text. diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index 4bebd41e15e..93531c06192 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -392,10 +392,11 @@ void Lexer::lexCommentText(Token &T) { unsigned Length = TokenPtr - (BufferPtr + 1); // Hardcoded support for lexing LaTeX formula commands - // \f$ \f[ \f] \f{ \f} as a single command. + // \f$ \f( \f) \f[ \f] \f{ \f} as a single command. if (Length == 1 && TokenPtr[-1] == 'f' && TokenPtr != CommentEnd) { C = *TokenPtr; - if (C == '$' || C == '[' || C == ']' || C == '{' || C == '}') { + if (C == '$' || C == '(' || C == ')' || C == '[' || C == ']' || + C == '{' || C == '}') { TokenPtr++; Length++; } diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index 7642e73fa17..087f103e493 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -86,7 +86,7 @@ ParamCommandComment *Sema::actOnParamCommandStart( new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, CommandMarker); - if (!isFunctionDecl() && !isFunctionOrBlockPointerVarLikeDecl()) + if (!involvesFunctionType()) Diag(Command->getLocation(), diag::warn_doc_param_not_attached_to_a_function_decl) << CommandMarker @@ -236,9 +236,7 @@ void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, if (Direction == -1) { // Try again with whitespace removed. - ArgLower.erase( - std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), - ArgLower.end()); + llvm::erase_if(ArgLower, clang::isWhitespace); Direction = getParamPassDirection(ArgLower); SourceRange ArgRange(ArgLocBegin, ArgLocEnd); @@ -590,7 +588,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { // to document the value that the property getter returns. if (isObjCPropertyDecl()) return; - if (isFunctionDecl() || isFunctionOrBlockPointerVarLikeDecl()) { + if (involvesFunctionType()) { assert(!ThisDeclInfo->ReturnType.isNull() && "should have a valid return type"); if (ThisDeclInfo->ReturnType->isVoidType()) { @@ -730,7 +728,7 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { } void Sema::resolveParamCommandIndexes(const FullComment *FC) { - if (!isFunctionDecl()) { + if (!involvesFunctionType()) { // We already warned that \\param commands are not attached to a function // decl. return; @@ -818,6 +816,14 @@ void Sema::resolveParamCommandIndexes(const FullComment *FC) { } } +bool Sema::involvesFunctionType() { + if (!ThisDeclInfo) + return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->involvesFunctionType(); +} + bool Sema::isFunctionDecl() { if (!ThisDeclInfo) return false; @@ -832,26 +838,11 @@ bool Sema::isAnyFunctionDecl() { } bool Sema::isFunctionOrMethodVariadic() { - if (!isFunctionDecl() || !ThisDeclInfo->CurrentDecl) + if (!ThisDeclInfo) return false; - if (const FunctionDecl *FD = - dyn_cast(ThisDeclInfo->CurrentDecl)) - return FD->isVariadic(); - if (const FunctionTemplateDecl *FTD = - dyn_cast(ThisDeclInfo->CurrentDecl)) - return FTD->getTemplatedDecl()->isVariadic(); - if (const ObjCMethodDecl *MD = - dyn_cast(ThisDeclInfo->CurrentDecl)) - return MD->isVariadic(); - if (const TypedefNameDecl *TD = - dyn_cast(ThisDeclInfo->CurrentDecl)) { - QualType Type = TD->getUnderlyingType(); - if (Type->isFunctionPointerType() || Type->isBlockPointerType()) - Type = Type->getPointeeType(); - if (const auto *FT = Type->getAs()) - return FT->isVariadic(); - } - return false; + if (!ThisDeclInfo->IsFilled) + inspectThisDecl(); + return ThisDeclInfo->IsVariadic; } bool Sema::isObjCMethodDecl() { @@ -873,36 +864,6 @@ bool Sema::isFunctionPointerVarDecl() { return false; } -bool Sema::isFunctionOrBlockPointerVarLikeDecl() { - if (!ThisDeclInfo) - return false; - if (!ThisDeclInfo->IsFilled) - inspectThisDecl(); - if (ThisDeclInfo->getKind() != DeclInfo::VariableKind || - !ThisDeclInfo->CurrentDecl) - return false; - QualType QT; - if (const auto *VD = dyn_cast(ThisDeclInfo->CurrentDecl)) - QT = VD->getType(); - else if (const auto *PD = - dyn_cast(ThisDeclInfo->CurrentDecl)) - QT = PD->getType(); - else - return false; - // We would like to warn about the 'returns'/'param' commands for - // variables that don't directly specify the function type, so type aliases - // can be ignored. - if (QT->getAs()) - return false; - if (const auto *P = QT->getAs()) - if (P->getPointeeType()->getAs()) - return false; - if (const auto *P = QT->getAs()) - if (P->getPointeeType()->getAs()) - return false; - return QT->isFunctionPointerType() || QT->isBlockPointerType(); -} - bool Sema::isObjCPropertyDecl() { if (!ThisDeclInfo) return false; diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp index 89605048264..a42960ad3c7 100644 --- a/clang/lib/AST/ComparisonCategories.cpp +++ b/clang/lib/AST/ComparisonCategories.cpp @@ -57,7 +57,7 @@ bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const { /// Attempt to determine the integer value used to represent the comparison /// category result by evaluating the initializer for the specified VarDecl as -/// a constant expression and retreiving the value of the class's first +/// a constant expression and retrieving the value of the class's first /// (and only) field. /// /// Note: The STL types are expected to have the form: diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 8f2ecb7bcf2..5ea091edcf4 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1088,13 +1088,29 @@ NamedDecl::isReserved(const LangOptions &LangOpts) const { return ReservedIdentifierStatus::NotReserved; ReservedIdentifierStatus Status = II->isReserved(LangOpts); - if (Status == ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope) { - // Check if we're at TU level or not. + if (isReservedAtGlobalScope(Status) && !isReservedInAllContexts(Status)) { + // This name is only reserved at global scope. Check if this declaration + // conflicts with a global scope declaration. if (isa(this) || isTemplateParameter()) return ReservedIdentifierStatus::NotReserved; + + // C++ [dcl.link]/7: + // Two declarations [conflict] if [...] one declares a function or + // variable with C language linkage, and the other declares [...] a + // variable that belongs to the global scope. + // + // Therefore names that are reserved at global scope are also reserved as + // names of variables and functions with C language linkage. const DeclContext *DC = getDeclContext()->getRedeclContext(); - if (!DC->isTranslationUnit()) - return ReservedIdentifierStatus::NotReserved; + if (DC->isTranslationUnit()) + return Status; + if (auto *VD = dyn_cast(this)) + if (VD->isExternC()) + return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC; + if (auto *FD = dyn_cast(this)) + if (FD->isExternC()) + return ReservedIdentifierStatus::StartsWithUnderscoreAndIsExternC; + return ReservedIdentifierStatus::NotReserved; } return Status; @@ -1647,8 +1663,7 @@ void NamedDecl::printNestedNameSpecifier(raw_ostream &OS, NameInScope = ND->getDeclName(); } - for (unsigned I = Contexts.size(); I != 0; --I) { - const DeclContext *DC = Contexts[I - 1]; + for (const DeclContext *DC : llvm::reverse(Contexts)) { if (const auto *Spec = dyn_cast(DC)) { OS << Spec->getName(); const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); @@ -2216,14 +2231,18 @@ VarDecl *VarDecl::getActingDefinition() { return nullptr; VarDecl *LastTentative = nullptr; - VarDecl *First = getFirstDecl(); - for (auto I : First->redecls()) { - Kind = I->isThisDeclarationADefinition(); + + // Loop through the declaration chain, starting with the most recent. + for (VarDecl *Decl = getMostRecentDecl(); Decl; + Decl = Decl->getPreviousDecl()) { + Kind = Decl->isThisDeclarationADefinition(); if (Kind == Definition) return nullptr; - if (Kind == TentativeDefinition) - LastTentative = I; + // Record the first (most recent) TentativeDefinition that is encountered. + if (Kind == TentativeDefinition && !LastTentative) + LastTentative = Decl; } + return LastTentative; } @@ -2769,11 +2788,15 @@ SourceRange ParmVarDecl::getSourceRange() const { } bool ParmVarDecl::isDestroyedInCallee() const { + // ns_consumed only affects code generation in ARC if (hasAttr()) - return true; + return getASTContext().getLangOpts().ObjCAutoRefCount; + // FIXME: isParamDestroyedInCallee() should probably imply + // isDestructedType() auto *RT = getType()->getAs(); - if (RT && RT->getDecl()->isParamDestroyedInCallee()) + if (RT && RT->getDecl()->isParamDestroyedInCallee() && + getType().isDestructedType()) return true; return false; @@ -2852,7 +2875,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, - bool isInlineSpecified, + bool UsesFPIntrin, bool isInlineSpecified, ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, @@ -2878,7 +2901,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.ConstexprKind = static_cast(ConstexprKind); FunctionDeclBits.InstantiationIsPending = false; FunctionDeclBits.UsesSEHTry = false; - FunctionDeclBits.UsesFPIntrin = false; + FunctionDeclBits.UsesFPIntrin = UsesFPIntrin; FunctionDeclBits.HasSkippedBody = false; FunctionDeclBits.WillHaveBody = false; FunctionDeclBits.IsMultiVersion = false; @@ -3172,7 +3195,9 @@ bool FunctionDecl::isInlineBuiltinDeclaration() const { return false; const FunctionDecl *Definition; - return hasBody(Definition) && Definition->isInlineSpecified(); + return hasBody(Definition) && Definition->isInlineSpecified() && + Definition->hasAttr() && + Definition->hasAttr(); } bool FunctionDecl::isDestroyingOperatorDelete() const { @@ -4498,6 +4523,17 @@ unsigned EnumDecl::getODRHash() { return ODRHash; } +SourceRange EnumDecl::getSourceRange() const { + auto Res = TagDecl::getSourceRange(); + // Set end-point to enum-base, e.g. enum foo : ^bar + if (auto *TSI = getIntegerTypeSourceInfo()) { + // TagDecl doesn't know about the enum base. + if (!getBraceRange().getEnd().isValid()) + Res.setEnd(TSI->getTypeLoc().getEndLoc()); + } + return Res; +} + //===----------------------------------------------------------------------===// // RecordDecl Implementation //===----------------------------------------------------------------------===// @@ -4857,18 +4893,16 @@ ImplicitParamDecl *ImplicitParamDecl::CreateDeserialized(ASTContext &C, return new (C, ID) ImplicitParamDecl(C, QualType(), ImplicitParamKind::Other); } -FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool isInlineSpecified, - bool hasWrittenPrototype, - ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) { - FunctionDecl *New = - new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, - SC, isInlineSpecified, ConstexprKind, - TrailingRequiresClause); +FunctionDecl * +FunctionDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, + bool isInlineSpecified, bool hasWrittenPrototype, + ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause) { + FunctionDecl *New = new (C, DC) FunctionDecl( + Function, C, DC, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, + isInlineSpecified, ConstexprKind, TrailingRequiresClause); New->setHasWrittenPrototype(hasWrittenPrototype); return New; } @@ -4876,7 +4910,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FunctionDecl( Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), - nullptr, SC_None, false, ConstexprSpecKind::Unspecified, nullptr); + nullptr, SC_None, false, false, ConstexprSpecKind::Unspecified, nullptr); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 3467da2b549..4044404f74e 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1217,6 +1217,15 @@ bool DeclContext::Encloses(const DeclContext *DC) const { return false; } +DeclContext *DeclContext::getNonTransparentContext() { + DeclContext *DC = this; + while (DC->isTransparentContext()) { + DC = DC->getParent(); + assert(DC && "All transparent contexts should have a parent!"); + } + return DC; +} + DeclContext *DeclContext::getPrimaryContext() { switch (getDeclKind()) { case Decl::ExternCContext: @@ -1953,6 +1962,7 @@ void ASTContext::ReleaseDeclContextMaps() { // pointer because the subclass doesn't add anything that needs to // be deleted. StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); + LastSDM.setPointer(nullptr); } void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index aeee35d9c74..1780358cc34 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -178,6 +178,8 @@ static bool hasRepeatedBaseClass(const CXXRecordDecl *StartRD) { SmallVector WorkList = {StartRD}; while (!WorkList.empty()) { const CXXRecordDecl *RD = WorkList.pop_back_val(); + if (RD->getTypeForDecl()->isDependentType()) + continue; for (const CXXBaseSpecifier &BaseSpec : RD->bases()) { if (const CXXRecordDecl *B = BaseSpec.getType()->getAsCXXRecordDecl()) { if (!SeenBaseTypes.insert(B).second) @@ -1776,7 +1778,7 @@ void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { for (unsigned I = 0, E = Convs.size(); I != E; ++I) { if (Convs[I].getDecl() == ConvDecl) { Convs.erase(I); - assert(llvm::find(Convs, ConvDecl) == Convs.end() && + assert(!llvm::is_contained(Convs, ConvDecl) && "conversion was found multiple times in unresolved set"); return; } @@ -2156,12 +2158,9 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, } // Other candidate final overriders might be overridden by this function. - FinalOverriders.erase( - std::remove_if(FinalOverriders.begin(), FinalOverriders.end(), - [&](CXXMethodDecl *OtherD) { - return recursivelyOverrides(D, OtherD); - }), - FinalOverriders.end()); + llvm::erase_if(FinalOverriders, [&](CXXMethodDecl *OtherD) { + return recursivelyOverrides(D, OtherD); + }); FinalOverriders.push_back(D); }; @@ -2178,25 +2177,23 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return FinalOverriders.size() == 1 ? FinalOverriders.front() : nullptr; } -CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - StorageClass SC, bool isInline, - ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, - Expr *TrailingRequiresClause) { - return new (C, RD) - CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, - isInline, ConstexprKind, EndLocation, - TrailingRequiresClause); +CXXMethodDecl * +CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, StorageClass SC, bool UsesFPIntrin, + bool isInline, ConstexprSpecKind ConstexprKind, + SourceLocation EndLocation, + Expr *TrailingRequiresClause) { + return new (C, RD) CXXMethodDecl( + CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, UsesFPIntrin, + isInline, ConstexprKind, EndLocation, TrailingRequiresClause); } CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) - CXXMethodDecl(CXXMethod, C, nullptr, SourceLocation(), - DeclarationNameInfo(), QualType(), nullptr, SC_None, false, - ConstexprSpecKind::Unspecified, SourceLocation(), nullptr); + return new (C, ID) CXXMethodDecl( + CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), + QualType(), nullptr, SC_None, false, false, + ConstexprSpecKind::Unspecified, SourceLocation(), nullptr); } CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, @@ -2339,7 +2336,7 @@ bool CXXMethodDecl::isUsualDeallocationFunction( // In C++17 onwards, all potential usual deallocation functions are actual // usual deallocation functions. Honor this behavior when post-C++14 // deallocation functions are offered as extensions too. - // FIXME(EricWF): Destrying Delete should be a language option. How do we + // FIXME(EricWF): Destroying Delete should be a language option. How do we // handle when destroying delete is used prior to C++17? if (Context.getLangOpts().CPlusPlus17 || Context.getLangOpts().AlignedAllocation || @@ -2568,12 +2565,12 @@ SourceRange CXXCtorInitializer::getSourceRange() const { CXXConstructorDecl::CXXConstructorDecl( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited, - Expr *TrailingRequiresClause) + ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, + bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, + InheritedConstructor Inherited, Expr *TrailingRequiresClause) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, ConstexprKind, SourceLocation(), - TrailingRequiresClause) { + SC_None, UsesFPIntrin, isInline, ConstexprKind, + SourceLocation(), TrailingRequiresClause) { setNumCtorInitializers(0); setInheritingConstructor(static_cast(Inherited)); setImplicit(isImplicitlyDeclared); @@ -2596,7 +2593,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, isInheritingConstructor, hasTrailingExplicit); auto *Result = new (C, ID, Extra) CXXConstructorDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - ExplicitSpecifier(), false, false, ConstexprSpecKind::Unspecified, + ExplicitSpecifier(), false, false, false, ConstexprSpecKind::Unspecified, InheritedConstructor(), nullptr); Result->setInheritingConstructor(isInheritingConstructor); Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier = @@ -2608,19 +2605,18 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, CXXConstructorDecl *CXXConstructorDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited, - Expr *TrailingRequiresClause) { + ExplicitSpecifier ES, bool UsesFPIntrin, bool isInline, + bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, + InheritedConstructor Inherited, Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); unsigned Extra = additionalSizeToAlloc( Inherited ? 1 : 0, ES.getExpr() ? 1 : 0); - return new (C, RD, Extra) - CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline, - isImplicitlyDeclared, ConstexprKind, Inherited, - TrailingRequiresClause); + return new (C, RD, Extra) CXXConstructorDecl( + C, RD, StartLoc, NameInfo, T, TInfo, ES, UsesFPIntrin, isInline, + isImplicitlyDeclared, ConstexprKind, Inherited, TrailingRequiresClause); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -2737,21 +2733,20 @@ CXXDestructorDecl * CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXDestructorDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - false, false, ConstexprSpecKind::Unspecified, nullptr); + false, false, false, ConstexprSpecKind::Unspecified, nullptr); } CXXDestructorDecl *CXXDestructorDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, - Expr *TrailingRequiresClause) { + bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared, + ConstexprSpecKind ConstexprKind, Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); - return new (C, RD) - CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, - isImplicitlyDeclared, ConstexprKind, - TrailingRequiresClause); + return new (C, RD) CXXDestructorDecl( + C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline, + isImplicitlyDeclared, ConstexprKind, TrailingRequiresClause); } void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) { @@ -2770,21 +2765,22 @@ CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXConversionDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - false, ExplicitSpecifier(), ConstexprSpecKind::Unspecified, + false, false, ExplicitSpecifier(), ConstexprSpecKind::Unspecified, SourceLocation(), nullptr); } CXXConversionDecl *CXXConversionDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation, Expr *TrailingRequiresClause) { + bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES, + ConstexprSpecKind ConstexprKind, SourceLocation EndLocation, + Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); - return new (C, RD) - CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES, - ConstexprKind, EndLocation, TrailingRequiresClause); + return new (C, RD) CXXConversionDecl( + C, RD, StartLoc, NameInfo, T, TInfo, UsesFPIntrin, isInline, ES, + ConstexprKind, EndLocation, TrailingRequiresClause); } bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { @@ -3017,8 +3013,7 @@ CXXRecordDecl *ConstructorUsingShadowDecl::getNominatedBaseClass() const { void BaseUsingDecl::anchor() {} void BaseUsingDecl::addShadowDecl(UsingShadowDecl *S) { - assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && - "declaration already in set"); + assert(!llvm::is_contained(shadows(), S) && "declaration already in set"); assert(S->getIntroducer() == this); if (FirstUsingShadow.getPointer()) @@ -3027,8 +3022,7 @@ void BaseUsingDecl::addShadowDecl(UsingShadowDecl *S) { } void BaseUsingDecl::removeShadowDecl(UsingShadowDecl *S) { - assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() && - "declaration not in set"); + assert(llvm::is_contained(shadows(), S) && "declaration not in set"); assert(S->getIntroducer() == this); // Remove S from the shadow decl chain. This is O(n) but hopefully rare. diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 6e790f03b02..ba827a79c02 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -603,10 +603,6 @@ void ObjCInterfaceDecl::allocateDefinitionData() { assert(!hasDefinition() && "ObjC class already has a definition"); Data.setPointer(new (getASTContext()) DefinitionData()); Data.getPointer()->Definition = this; - - // Make the type point at the definition, now that we have one. - if (TypeForDecl) - cast(TypeForDecl)->Decl = this; } void ObjCInterfaceDecl::startDefinition() { @@ -855,6 +851,14 @@ bool ObjCMethodDecl::isDesignatedInitializerForTheInterface( return false; } +bool ObjCMethodDecl::hasParamDestroyedInCallee() const { + for (auto param : parameters()) { + if (param->isDestroyedInCallee()) + return true; + } + return false; +} + Stmt *ObjCMethodDecl::getBody() const { return Body.get(getASTContext().getExternalSource()); } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 4dcf3d0e6ab..044eb8f8f8e 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -112,11 +112,9 @@ namespace { void printTemplateParameters(const TemplateParameterList *Params, bool OmitTemplateKW = false); void printTemplateArguments(llvm::ArrayRef Args, - const TemplateParameterList *Params, - bool TemplOverloaded); + const TemplateParameterList *Params); void printTemplateArguments(llvm::ArrayRef Args, - const TemplateParameterList *Params, - bool TemplOverloaded); + const TemplateParameterList *Params); void prettyPrintAttributes(Decl *D); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); @@ -153,11 +151,14 @@ static QualType GetBaseType(QualType T) { while (!BaseType->isSpecifierType()) { if (const PointerType *PTy = BaseType->getAs()) BaseType = PTy->getPointeeType(); + else if (const ObjCObjectPointerType *OPT = + BaseType->getAs()) + BaseType = OPT->getPointeeType(); else if (const BlockPointerType *BPy = BaseType->getAs()) BaseType = BPy->getPointeeType(); - else if (const ArrayType* ATy = dyn_cast(BaseType)) + else if (const ArrayType *ATy = dyn_cast(BaseType)) BaseType = ATy->getElementType(); - else if (const FunctionType* FTy = BaseType->getAs()) + else if (const FunctionType *FTy = BaseType->getAs()) BaseType = FTy->getReturnType(); else if (const VectorType *VTy = BaseType->getAs()) BaseType = VTy->getElementType(); @@ -649,16 +650,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { llvm::raw_string_ostream POut(Proto); DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation); const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten(); - const TemplateParameterList *TPL = D->getTemplateSpecializationInfo() - ->getTemplate() - ->getTemplateParameters(); if (TArgAsWritten && !Policy.PrintCanonicalTypes) - TArgPrinter.printTemplateArguments(TArgAsWritten->arguments(), TPL, - /*TemplOverloaded*/ true); + TArgPrinter.printTemplateArguments(TArgAsWritten->arguments(), nullptr); else if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) - TArgPrinter.printTemplateArguments(TArgs->asArray(), TPL, - /*TemplOverloaded*/ true); + TArgPrinter.printTemplateArguments(TArgs->asArray(), nullptr); } QualType Ty = D->getType(); @@ -786,11 +782,10 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << ";\n"; } Indentation -= Policy.Indentation; - } else - Out << ' '; + } if (D->getBody()) - D->getBody()->printPretty(Out, nullptr, SubPolicy, Indentation, "\n", + D->getBody()->printPrettyControlled(Out, nullptr, SubPolicy, Indentation, "\n", &Context); } else { if (!Policy.TerseOutput && isa(*D)) @@ -999,8 +994,7 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { dyn_cast(TSI->getType())) Args = TST->template_arguments(); printTemplateArguments( - Args, S->getSpecializedTemplate()->getTemplateParameters(), - /*TemplOverloaded*/ false); + Args, S->getSpecializedTemplate()->getTemplateParameters()); } } @@ -1093,35 +1087,34 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, } void DeclPrinter::printTemplateArguments(ArrayRef Args, - const TemplateParameterList *Params, - bool TemplOverloaded) { + const TemplateParameterList *Params) { Out << "<"; for (size_t I = 0, E = Args.size(); I < E; ++I) { if (I) Out << ", "; - if (TemplOverloaded || !Params) + if (!Params) Args[I].print(Policy, Out, /*IncludeType*/ true); else - Args[I].print( - Policy, Out, - TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); + Args[I].print(Policy, Out, + TemplateParameterList::shouldIncludeTypeForArgument( + Policy, Params, I)); } Out << ">"; } void DeclPrinter::printTemplateArguments(ArrayRef Args, - const TemplateParameterList *Params, - bool TemplOverloaded) { + const TemplateParameterList *Params) { Out << "<"; for (size_t I = 0, E = Args.size(); I < E; ++I) { if (I) Out << ", "; - if (TemplOverloaded) + if (!Params) Args[I].getArgument().print(Policy, Out, /*IncludeType*/ true); else Args[I].getArgument().print( Policy, Out, - TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); + TemplateParameterList::shouldIncludeTypeForArgument(Policy, Params, + I)); } Out << ">"; } @@ -1191,6 +1184,7 @@ void DeclPrinter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (D->isThisDeclarationADefinition()) Out << ";"; Out << "\n"; + Indent(); Visit(I); } } @@ -1658,10 +1652,11 @@ void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) { Out << ")"; } if (!D->clauselist_empty()) { - Out << " "; OMPClausePrinter Printer(Out, Policy); - for (OMPClause *C : D->clauselists()) + for (OMPClause *C : D->clauselists()) { + Out << " "; Printer.Visit(C); + } } } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index ec8b00a9eb7..223f06b9db1 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -77,7 +77,7 @@ TemplateParameterList::TemplateParameterList(const ASTContext& C, if (TTP->hasTypeConstraint()) HasConstrainedParameters = true; } else { - llvm_unreachable("unexpcted template parameter type"); + llvm_unreachable("unexpected template parameter type"); } // FIXME: If a default argument contains an unexpanded parameter pack, the // template parameter list does too. @@ -165,14 +165,20 @@ unsigned TemplateParameterList::getDepth() const { return cast(FirstParm)->getDepth(); } -static void AdoptTemplateParameterList(TemplateParameterList *Params, +static bool AdoptTemplateParameterList(TemplateParameterList *Params, DeclContext *Owner) { + bool Invalid = false; for (NamedDecl *P : *Params) { P->setDeclContext(Owner); if (const auto *TTP = dyn_cast(P)) - AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner); + if (AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner)) + Invalid = true; + + if (P->isInvalidDecl()) + Invalid = true; } + return Invalid; } void TemplateParameterList:: @@ -196,8 +202,9 @@ bool TemplateParameterList::hasAssociatedConstraints() const { } bool TemplateParameterList::shouldIncludeTypeForArgument( - const TemplateParameterList *TPL, unsigned Idx) { - if (!TPL || Idx >= TPL->size()) + const PrintingPolicy &Policy, const TemplateParameterList *TPL, + unsigned Idx) { + if (!TPL || Idx >= TPL->size() || Policy.AlwaysIncludeTypeForTemplateArgument) return true; const NamedDecl *TemplParam = TPL->getParam(Idx); if (const auto *ParamValueDecl = @@ -339,14 +346,15 @@ void RedeclarableTemplateDecl::addSpecializationImpl( // FunctionTemplateDecl Implementation //===----------------------------------------------------------------------===// -FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, - DeclContext *DC, - SourceLocation L, - DeclarationName Name, - TemplateParameterList *Params, - NamedDecl *Decl) { - AdoptTemplateParameterList(Params, cast(Decl)); - return new (C, DC) FunctionTemplateDecl(C, DC, L, Name, Params, Decl); +FunctionTemplateDecl * +FunctionTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) { + bool Invalid = AdoptTemplateParameterList(Params, cast(Decl)); + auto *TD = new (C, DC) FunctionTemplateDecl(C, DC, L, Name, Params, Decl); + if (Invalid) + TD->setInvalidDecl(); + return TD; } FunctionTemplateDecl *FunctionTemplateDecl::CreateDeserialized(ASTContext &C, @@ -438,15 +446,16 @@ void FunctionTemplateDecl::mergePrevDecl(FunctionTemplateDecl *Prev) { // ClassTemplateDecl Implementation //===----------------------------------------------------------------------===// -ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, - DeclContext *DC, +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) { - AdoptTemplateParameterList(Params, cast(Decl)); - - return new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); + bool Invalid = AdoptTemplateParameterList(Params, cast(Decl)); + auto *TD = new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); + if (Invalid) + TD->setInvalidDecl(); + return TD; } ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, @@ -1005,8 +1014,11 @@ ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, Expr *ConstraintExpr) { - AdoptTemplateParameterList(Params, DC); - return new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr); + bool Invalid = AdoptTemplateParameterList(Params, DC); + auto *TD = new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr); + if (Invalid) + TD->setInvalidDecl(); + return TD; } ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, @@ -1039,7 +1051,8 @@ ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, SpecializedTemplate, Args, PrevDecl), TemplateParams(Params), ArgsAsWritten(ArgInfos), InstantiatedFromMember(nullptr, false) { - AdoptTemplateParameterList(Params, this); + if (AdoptTemplateParameterList(Params, this)) + setInvalidDecl(); } ClassTemplatePartialSpecializationDecl * @@ -1097,14 +1110,15 @@ FriendTemplateDecl *FriendTemplateDecl::CreateDeserialized(ASTContext &C, // TypeAliasTemplateDecl Implementation //===----------------------------------------------------------------------===// -TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, - DeclContext *DC, - SourceLocation L, - DeclarationName Name, - TemplateParameterList *Params, - NamedDecl *Decl) { - AdoptTemplateParameterList(Params, DC); - return new (C, DC) TypeAliasTemplateDecl(C, DC, L, Name, Params, Decl); +TypeAliasTemplateDecl * +TypeAliasTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) { + bool Invalid = AdoptTemplateParameterList(Params, DC); + auto *TD = new (C, DC) TypeAliasTemplateDecl(C, DC, L, Name, Params, Decl); + if (Invalid) + TD->setInvalidDecl(); + return TD; } TypeAliasTemplateDecl *TypeAliasTemplateDecl::CreateDeserialized(ASTContext &C, @@ -1151,8 +1165,11 @@ VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, VarDecl *Decl) { - AdoptTemplateParameterList(Params, DC); - return new (C, DC) VarTemplateDecl(C, DC, L, Name, Params, Decl); + bool Invalid = AdoptTemplateParameterList(Params, DC); + auto *TD = new (C, DC) VarTemplateDecl(C, DC, L, Name, Params, Decl); + if (Invalid) + TD->setInvalidDecl(); + return TD; } VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, @@ -1334,8 +1351,8 @@ VarTemplatePartialSpecializationDecl::VarTemplatePartialSpecializationDecl( TInfo, S, Args), TemplateParams(Params), ArgsAsWritten(ArgInfos), InstantiatedFromMember(nullptr, false) { - // TODO: The template parameters should be in DC by now. Verify. - // AdoptTemplateParameterList(Params, DC); + if (AdoptTemplateParameterList(Params, DC)) + setInvalidDecl(); } VarTemplatePartialSpecializationDecl * diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index e8b4aaa2b81..7bd3dce43f4 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -545,20 +545,11 @@ std::string SYCLUniqueStableNameExpr::ComputeName(ASTContext &Context, QualType Ty) { auto MangleCallback = [](ASTContext &Ctx, const NamedDecl *ND) -> llvm::Optional { - // This replaces the 'lambda number' in the mangling with a unique number - // based on its order in the declaration. To provide some level of visual - // notability (actual uniqueness from normal lambdas isn't necessary, as - // these are used differently), we add 10,000 to the number. - // For example: - // _ZTSZ3foovEUlvE10005_ - // Demangles to: typeinfo name for foo()::'lambda10005'() - // Note that the mangler subtracts 2, since with normal lambdas the lambda - // mangling number '0' is an anonymous struct mangle, and '1' is omitted. - // So 10,002 results in the first number being 10,000. - if (Ctx.IsSYCLKernelNamingDecl(ND)) - return 10'002 + Ctx.GetSYCLKernelNamingIndex(ND); + if (const auto *RD = dyn_cast(ND)) + return RD->getDeviceLambdaManglingNumber(); return llvm::None; }; + std::unique_ptr Ctx{ItaniumMangleContext::create( Context, Context.getDiagnostics(), MangleCallback)}; @@ -762,19 +753,18 @@ std::string PredefinedExpr::ComputeName(IdentKind IK, const Decl *CurrentDecl) { std::string TemplateParams; llvm::raw_string_ostream TOut(TemplateParams); - for (SpecsTy::reverse_iterator I = Specs.rbegin(), E = Specs.rend(); - I != E; ++I) { - const TemplateParameterList *Params - = (*I)->getSpecializedTemplate()->getTemplateParameters(); - const TemplateArgumentList &Args = (*I)->getTemplateArgs(); + for (const ClassTemplateSpecializationDecl *D : llvm::reverse(Specs)) { + const TemplateParameterList *Params = + D->getSpecializedTemplate()->getTemplateParameters(); + const TemplateArgumentList &Args = D->getTemplateArgs(); assert(Params->size() == Args.size()); for (unsigned i = 0, numParams = Params->size(); i != numParams; ++i) { StringRef Param = Params->getParam(i)->getName(); if (Param.empty()) continue; TOut << Param << " = "; - Args.get(i).print( - Policy, TOut, - TemplateParameterList::shouldIncludeTypeForArgument(Params, i)); + Args.get(i).print(Policy, TOut, + TemplateParameterList::shouldIncludeTypeForArgument( + Policy, Params, i)); TOut << ", "; } } @@ -2233,8 +2223,11 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx, }; switch (getIdentKind()) { - case SourceLocExpr::File: - return MakeStringLiteral(PLoc.getFilename()); + case SourceLocExpr::File: { + SmallString<256> Path(PLoc.getFilename()); + Ctx.getLangOpts().remapPathPrefix(Path); + return MakeStringLiteral(Path); + } case SourceLocExpr::Function: { const Decl *CurDecl = dyn_cast_or_null(Context); return MakeStringLiteral( @@ -2305,7 +2298,7 @@ bool InitListExpr::isStringLiteralInit() const { const Expr *Init = getInit(0); if (!Init) return false; - Init = Init->IgnoreParens(); + Init = Init->IgnoreParenImpCasts(); return isa(Init) || isa(Init); } @@ -2367,10 +2360,8 @@ SourceLocation InitListExpr::getEndLoc() const { SourceLocation End = RBraceLoc; if (End.isInvalid()) { // Find the first non-null initializer from the end. - for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(), - E = InitExprs.rend(); - I != E; ++I) { - if (Stmt *S = *I) { + for (Stmt *S : llvm::reverse(InitExprs)) { + if (S) { End = S->getEndLoc(); break; } @@ -3776,11 +3767,8 @@ Expr::isNullPointerConstant(ASTContext &Ctx, // has non-default address space it is not treated as nullptr. // (__generic void*)0 in OpenCL 2.0 should not be treated as nullptr // since it cannot be assigned to a pointer to constant address space. - if ((Ctx.getLangOpts().OpenCLVersion >= 200 && - Pointee.getAddressSpace() == LangAS::opencl_generic) || - (Ctx.getLangOpts().OpenCL && - Ctx.getLangOpts().OpenCLVersion < 200 && - Pointee.getAddressSpace() == LangAS::opencl_private)) + if (Ctx.getLangOpts().OpenCL && + Pointee.getAddressSpace() == Ctx.getDefaultOpenCLPointeeAddrSpace()) Qs.removeAddressSpace(); if (Pointee->isVoidType() && Qs.empty() && // to void* @@ -4125,7 +4113,7 @@ bool ExtVectorElementExpr::containsDuplicateElements() const { Comp = Comp.substr(1); for (unsigned i = 0, e = Comp.size(); i != e; ++i) - if (Comp.substr(i + 1).find(Comp[i]) != StringRef::npos) + if (Comp.substr(i + 1).contains(Comp[i])) return true; return false; @@ -4704,6 +4692,7 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__c11_atomic_fetch_and: case AO__c11_atomic_fetch_or: case AO__c11_atomic_fetch_xor: + case AO__c11_atomic_fetch_nand: case AO__c11_atomic_fetch_max: case AO__c11_atomic_fetch_min: case AO__atomic_fetch_add: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 01c0168d61a..fe96db9ca91 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -1084,14 +1084,10 @@ namespace { void performLifetimeExtension() { // Disable the cleanups for lifetime-extended temporaries. - CleanupStack.erase(std::remove_if(CleanupStack.begin(), - CleanupStack.end(), - [](Cleanup &C) { - return !C.isDestroyedAtEndOf( - ScopeKind::FullExpression); - }), - CleanupStack.end()); - } + llvm::erase_if(CleanupStack, [](Cleanup &C) { + return !C.isDestroyedAtEndOf(ScopeKind::FullExpression); + }); + } /// Throw away any remaining cleanups at the end of evaluation. If any /// cleanups would have had a side-effect, note that as an unmodeled @@ -1826,6 +1822,8 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info); static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result, EvalInfo &Info); static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result); +static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, + EvalInfo &Info); /// Evaluate an integer or fixed point expression into an APResult. static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result, @@ -2673,7 +2671,7 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E, QualType EltTy = VecTy->castAs()->getElementType(); unsigned EltSize = Info.Ctx.getTypeSize(EltTy); bool BigEndian = Info.Ctx.getTargetInfo().isBigEndian(); - Res = llvm::APInt::getNullValue(VecSize); + Res = llvm::APInt::getZero(VecSize); for (unsigned i = 0; i < SVal.getVectorLength(); i++) { APValue &Elt = SVal.getVectorElt(i); llvm::APInt EltAsInt; @@ -2755,8 +2753,8 @@ static bool handleIntIntBinOp(EvalInfo &Info, const Expr *E, const APSInt &LHS, Result = (Opcode == BO_Rem ? LHS % RHS : LHS / RHS); // Check for overflow case: INT_MIN / -1 or INT_MIN % -1. APSInt supports // this operation and gives the two's complement result. - if (RHS.isNegative() && RHS.isAllOnesValue() && - LHS.isSigned() && LHS.isMinSignedValue()) + if (RHS.isNegative() && RHS.isAllOnes() && LHS.isSigned() && + LHS.isMinSignedValue()) return HandleOverflow(Info, E, -LHS.extend(LHS.getBitWidth() + 1), E->getType()); return true; @@ -5193,7 +5191,10 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, } } bool Cond; - if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), Cond)) + if (IS->isConsteval()) + Cond = IS->isNonNegatedConsteval(); + else if (!EvaluateCond(Info, IS->getConditionVariable(), IS->getCond(), + Cond)) return ESR_Failed; if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) { @@ -5318,6 +5319,11 @@ static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info, return ESR; } + // In error-recovery cases it's possible to get here even if we failed to + // synthesize the __begin and __end variables. + if (!FS->getBeginStmt() || !FS->getEndStmt() || !FS->getCond()) + return ESR_Failed; + // Create the __begin and __end iterators. ESR = EvaluateStmt(Result, Info, FS->getBeginStmt()); if (ESR != ESR_Succeeded) { @@ -6757,7 +6763,7 @@ public: SmallVectorImpl &Output) const { for (CharUnits I = Offset, E = Offset + Width; I != E; ++I) { // If a byte of an integer is uninitialized, then the whole integer is - // uninitalized. + // uninitialized. if (!Bytes[I.getQuantity()]) return false; Output.push_back(*Bytes[I.getQuantity()]); @@ -8672,8 +8678,6 @@ public: bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E) { std::string ResultStr = E->ComputeName(Info.Ctx); - Info.Ctx.SYCLUniqueStableNameEvaluatedValues[E] = ResultStr; - QualType CharTy = Info.Ctx.CharTy.withConst(); APInt Size(Info.Ctx.getTypeSize(Info.Ctx.getSizeType()), ResultStr.size() + 1); @@ -9931,10 +9935,19 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, return false; // Avoid materializing a temporary for an elidable copy/move constructor. - if (E->isElidable() && !ZeroInit) - if (const MaterializeTemporaryExpr *ME - = dyn_cast(E->getArg(0))) + if (E->isElidable() && !ZeroInit) { + // FIXME: This only handles the simplest case, where the source object + // is passed directly as the first argument to the constructor. + // This should also handle stepping though implicit casts and + // and conversion sequences which involve two steps, with a + // conversion operator followed by a converting constructor. + const Expr *SrcObj = E->getArg(0); + assert(SrcObj->isTemporaryObject(Info.Ctx, FD->getParent())); + assert(Info.Ctx.hasSameUnqualifiedType(E->getType(), SrcObj->getType())); + if (const MaterializeTemporaryExpr *ME = + dyn_cast(SrcObj)) return Visit(ME->getSubExpr()); + } if (ZeroInit && !ZeroInitialization(E, T)) return false; @@ -10471,13 +10484,17 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E, // C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...] // an appropriately-typed string literal enclosed in braces. if (E->isStringLiteralInit()) { - auto *SL = dyn_cast(E->getInit(0)->IgnoreParens()); + auto *SL = dyn_cast(E->getInit(0)->IgnoreParenImpCasts()); // FIXME: Support ObjCEncodeExpr here once we support it in // ArrayExprEvaluator generally. if (!SL) return Error(E); return VisitStringLiteral(SL, AllocType); } + // Any other transparent list init will need proper handling of the + // AllocType; we can't just recurse to the inner initializer. + assert(!E->isTransparent() && + "transparent array list initialization is not string literal init?"); bool Success = true; @@ -10598,8 +10615,8 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, for (unsigned I = 0; I != N; ++I) if (!VisitCXXConstructExpr(E, ArrayElt, &Value->getArrayInitializedElt(I), CAT->getElementType()) || - !HandleLValueArrayAdjustment(Info, E, ArrayElt, - CAT->getElementType(), 1)) + !HandleLValueArrayAdjustment(Info, E, ArrayElt, CAT->getElementType(), + 1)) return false; return true; @@ -11836,46 +11853,10 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_wcslen: { // As an extension, we support __builtin_strlen() as a constant expression, // and support folding strlen() to a constant. - LValue String; - if (!EvaluatePointer(E->getArg(0), String, Info)) - return false; - - QualType CharTy = E->getArg(0)->getType()->getPointeeType(); - - // Fast path: if it's a string literal, search the string value. - if (const StringLiteral *S = dyn_cast_or_null( - String.getLValueBase().dyn_cast())) { - // The string literal may have embedded null characters. Find the first - // one and truncate there. - StringRef Str = S->getBytes(); - int64_t Off = String.Offset.getQuantity(); - if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() && - S->getCharByteWidth() == 1 && - // FIXME: Add fast-path for wchar_t too. - Info.Ctx.hasSameUnqualifiedType(CharTy, Info.Ctx.CharTy)) { - Str = Str.substr(Off); - - StringRef::size_type Pos = Str.find(0); - if (Pos != StringRef::npos) - Str = Str.substr(0, Pos); - - return Success(Str.size(), E); - } - - // Fall through to slow path to issue appropriate diagnostic. - } - - // Slow path: scan the bytes of the string looking for the terminating 0. - for (uint64_t Strlen = 0; /**/; ++Strlen) { - APValue Char; - if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) || - !Char.isInt()) - return false; - if (!Char.getInt()) - return Success(Strlen, E); - if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1)) - return false; - } + uint64_t StrLen; + if (EvaluateBuiltinStrLen(E->getArg(0), StrLen, Info)) + return Success(StrLen, E); + return false; } case Builtin::BIstrcmp: @@ -15347,7 +15328,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx); if (REval == 0) return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); - if (REval.isSigned() && REval.isAllOnesValue()) { + if (REval.isSigned() && REval.isAllOnes()) { llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx); if (LEval.isMinSignedValue()) return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); @@ -15525,8 +15506,10 @@ bool Expr::isIntegerConstantExpr(const ASTContext &Ctx, Optional Expr::getIntegerConstantExpr(const ASTContext &Ctx, SourceLocation *Loc, bool isEvaluated) const { - assert(!isValueDependent() && - "Expression evaluator can't be called on a dependent expression."); + if (isValueDependent()) { + // Expression evaluator can't succeed on a dependent expression. + return None; + } APSInt Value; @@ -15736,3 +15719,58 @@ bool Expr::tryEvaluateObjectSize(uint64_t &Result, ASTContext &Ctx, EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); return tryEvaluateBuiltinObjectSize(this, Type, Info, Result); } + +static bool EvaluateBuiltinStrLen(const Expr *E, uint64_t &Result, + EvalInfo &Info) { + if (!E->getType()->hasPointerRepresentation() || !E->isPRValue()) + return false; + + LValue String; + + if (!EvaluatePointer(E, String, Info)) + return false; + + QualType CharTy = E->getType()->getPointeeType(); + + // Fast path: if it's a string literal, search the string value. + if (const StringLiteral *S = dyn_cast_or_null( + String.getLValueBase().dyn_cast())) { + StringRef Str = S->getBytes(); + int64_t Off = String.Offset.getQuantity(); + if (Off >= 0 && (uint64_t)Off <= (uint64_t)Str.size() && + S->getCharByteWidth() == 1 && + // FIXME: Add fast-path for wchar_t too. + Info.Ctx.hasSameUnqualifiedType(CharTy, Info.Ctx.CharTy)) { + Str = Str.substr(Off); + + StringRef::size_type Pos = Str.find(0); + if (Pos != StringRef::npos) + Str = Str.substr(0, Pos); + + Result = Str.size(); + return true; + } + + // Fall through to slow path. + } + + // Slow path: scan the bytes of the string looking for the terminating 0. + for (uint64_t Strlen = 0; /**/; ++Strlen) { + APValue Char; + if (!handleLValueToRValueConversion(Info, E, CharTy, String, Char) || + !Char.isInt()) + return false; + if (!Char.getInt()) { + Result = Strlen; + return true; + } + if (!HandleLValueArrayAdjustment(Info, E, String, CharTy, 1)) + return false; + } +} + +bool Expr::tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const { + Expr::EvalStatus Status; + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold); + return EvaluateBuiltinStrLen(this, Result, Info); +} diff --git a/clang/lib/AST/ExprObjC.cpp b/clang/lib/AST/ExprObjC.cpp index 7d932c8b059..a3222c2da24 100644 --- a/clang/lib/AST/ExprObjC.cpp +++ b/clang/lib/AST/ExprObjC.cpp @@ -271,20 +271,7 @@ QualType ObjCMessageExpr::getCallReturnType(ASTContext &Ctx) const { } return QT; } - - // Expression type might be different from an expected call return type, - // as expression type would never be a reference even if call returns a - // reference. Reconstruct the original expression type. - QualType QT = getType(); - switch (getValueKind()) { - case VK_LValue: - return Ctx.getLValueReferenceType(QT); - case VK_XValue: - return Ctx.getRValueReferenceType(QT); - case VK_PRValue: - return QT; - } - llvm_unreachable("Unsupported ExprValueKind"); + return Ctx.getReferenceQualifiedType(this); } SourceRange ObjCMessageExpr::getReceiverRange() const { diff --git a/clang/lib/AST/ExternalASTMerger.cpp b/clang/lib/AST/ExternalASTMerger.cpp index c7789b707b2..a2ef270d7a9 100644 --- a/clang/lib/AST/ExternalASTMerger.cpp +++ b/clang/lib/AST/ExternalASTMerger.cpp @@ -425,16 +425,14 @@ void ExternalASTMerger::RemoveSources(llvm::ArrayRef Sources) { logs() << "(ExternalASTMerger*)" << (void *)this << " removing source (ASTContext*)" << (void *)&S.getASTContext() << "\n"; - Importers.erase( - std::remove_if(Importers.begin(), Importers.end(), - [&Sources](std::unique_ptr &Importer) -> bool { - for (const ImporterSource &S : Sources) { - if (&Importer->getFromContext() == &S.getASTContext()) - return true; - } - return false; - }), - Importers.end()); + llvm::erase_if(Importers, + [&Sources](std::unique_ptr &Importer) -> bool { + for (const ImporterSource &S : Sources) { + if (&Importer->getFromContext() == &S.getASTContext()) + return true; + } + return false; + }); for (OriginMap::iterator OI = Origins.begin(), OE = Origins.end(); OI != OE; ) { std::pair Origin = *OI; bool Erase = false; diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index 7a4569820a1..a69b23fd613 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -11,6 +11,7 @@ #include "Opcode.h" #include "Program.h" #include "clang/AST/DeclCXX.h" +#include using namespace clang; using namespace clang::interp; @@ -122,29 +123,48 @@ bool ByteCodeEmitter::bail(const SourceLocation &Loc) { return false; } +/// Helper to write bytecode and bail out if 32-bit offsets become invalid. +/// Pointers will be automatically marshalled as 32-bit IDs. +template +static std::enable_if_t::value, void> +emit(Program &P, std::vector &Code, const T &Val, bool &Success) { + size_t Size = sizeof(Val); + if (Code.size() + Size > std::numeric_limits::max()) { + Success = false; + return; + } + + const char *Data = reinterpret_cast(&Val); + Code.insert(Code.end(), Data, Data + Size); +} + +template +static std::enable_if_t::value, void> +emit(Program &P, std::vector &Code, const T &Val, bool &Success) { + size_t Size = sizeof(uint32_t); + if (Code.size() + Size > std::numeric_limits::max()) { + Success = false; + return; + } + + uint32_t ID = P.getOrCreateNativePointer(Val); + const char *Data = reinterpret_cast(&ID); + Code.insert(Code.end(), Data, Data + Size); +} + template bool ByteCodeEmitter::emitOp(Opcode Op, const Tys &... Args, const SourceInfo &SI) { bool Success = true; - /// Helper to write bytecode and bail out if 32-bit offsets become invalid. - auto emit = [this, &Success](const char *Data, size_t Size) { - if (Code.size() + Size > std::numeric_limits::max()) { - Success = false; - return; - } - Code.insert(Code.end(), Data, Data + Size); - }; - /// The opcode is followed by arguments. The source info is /// attached to the address after the opcode. - emit(reinterpret_cast(&Op), sizeof(Opcode)); + emit(P, Code, Op, Success); if (SI) SrcMap.emplace_back(Code.size(), SI); /// The initializer list forces the expression to be evaluated /// for each argument in the variadic template, in order. - (void)std::initializer_list{ - (emit(reinterpret_cast(&Args), sizeof(Args)), 0)...}; + (void)std::initializer_list{(emit(P, Code, Args, Success), 0)...}; return Success; } diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 5b47489e65e..90e84149b05 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -188,6 +188,12 @@ bool ByteCodeStmtGen::visitReturnStmt(const ReturnStmt *RS) { template bool ByteCodeStmtGen::visitIfStmt(const IfStmt *IS) { BlockScope IfScope(this); + + if (IS->isNonNegatedConsteval()) + return visitStmt(IS->getThen()); + if (IS->isNegatedConsteval()) + return IS->getElse() ? visitStmt(IS->getElse()) : true; + if (auto *CondInit = IS->getInit()) if (!visitStmt(IS->getInit())) return false; diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index e8238eea716..4f25ff977b8 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -67,7 +67,7 @@ private: /// Runs a function. bool Run(State &Parent, Function *Func, APValue &Result); - /// Checks a result fromt the interpreter. + /// Checks a result from the interpreter. bool Check(State &Parent, llvm::Expected &&R); private: diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index b260b760097..11072cab3e9 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -184,7 +184,7 @@ struct InlineDescriptor { /// Bitfield tracking the initialisation status of elements of primitive arrays. /// A pointer to this is embedded at the end of all primitive arrays. -/// If the map was not yet created and nothing was initialied, the pointer to +/// If the map was not yet created and nothing was initialized, the pointer to /// this structure is 0. If the object was fully initialized, the pointer is -1. struct InitMap { private: diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index c1c18f832d4..36adbe296b0 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -21,6 +21,19 @@ using namespace clang; using namespace clang::interp; +template +inline std::enable_if_t::value, T> ReadArg(Program &P, + CodePtr OpPC) { + return OpPC.read(); +} + +template +inline std::enable_if_t::value, T> ReadArg(Program &P, + CodePtr OpPC) { + uint32_t ID = OpPC.read(); + return reinterpret_cast(P.getNativePointer(ID)); +} + LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); } LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const { diff --git a/clang/lib/AST/Interp/Function.h b/clang/lib/AST/Interp/Function.h index 28531f04b6e..ac1dffea116 100644 --- a/clang/lib/AST/Interp/Function.h +++ b/clang/lib/AST/Interp/Function.h @@ -73,7 +73,7 @@ public: /// Returns the original FunctionDecl. const FunctionDecl *getDecl() const { return F; } - /// Returns the lcoation. + /// Returns the location. SourceLocation getLoc() const { return Loc; } /// Returns a parameter descriptor. diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index e2f7bf0dc26..a1d90f26ba4 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -13,8 +13,6 @@ #ifndef LLVM_CLANG_AST_INTERP_INTERP_H #define LLVM_CLANG_AST_INTERP_INTERP_H -#include -#include #include "Function.h" #include "InterpFrame.h" #include "InterpStack.h" @@ -30,6 +28,9 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Endian.h" +#include +#include +#include namespace clang { namespace interp { @@ -37,7 +38,7 @@ namespace interp { using APInt = llvm::APInt; using APSInt = llvm::APSInt; -/// Convers a value to an APValue. +/// Convert a value to an APValue. template bool ReturnValue(const T &V, APValue &R) { R = V.toAPValue(); return true; @@ -49,7 +50,7 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if the array is offsetable. bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); -/// Checks if a pointer is live and accesible. +/// Checks if a pointer is live and accessible. bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); /// Checks if a pointer is null. @@ -949,6 +950,23 @@ inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { return true; } +//===----------------------------------------------------------------------===// +// Read opcode arguments +//===----------------------------------------------------------------------===// + +template +inline std::enable_if_t::value, T> ReadArg(InterpState &S, + CodePtr OpPC) { + return OpPC.read(); +} + +template +inline std::enable_if_t::value, T> ReadArg(InterpState &S, + CodePtr OpPC) { + uint32_t ID = OpPC.read(); + return reinterpret_cast(S.P.getNativePointer(ID)); +} + /// Interpreter entry point. bool Interpret(InterpState &S, APValue &Result); diff --git a/clang/lib/AST/Interp/InterpStack.h b/clang/lib/AST/Interp/InterpStack.h index 127adb6b8eb..b02d3c6a34b 100644 --- a/clang/lib/AST/Interp/InterpStack.h +++ b/clang/lib/AST/Interp/InterpStack.h @@ -69,7 +69,7 @@ private: return ((sizeof(T) + PtrAlign - 1) / PtrAlign) * PtrAlign; } - /// Grows the stack to accomodate a value and returns a pointer to it. + /// Grows the stack to accommodate a value and returns a pointer to it. void *grow(size_t Size); /// Returns a pointer from the top of the stack. void *peek(size_t Size); diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index c2209bbcbb9..57e36c4c63e 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -46,7 +46,7 @@ public: return Parent.getBottomFrame(); } - // Acces objects from the walker context. + // Access objects from the walker context. Expr::EvalStatus &getEvalStatus() const override { return Parent.getEvalStatus(); } diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 4aba5f5cd83..638d5b3d235 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -57,7 +57,7 @@ def ArgValueDecl : ArgType { let Name = "const ValueDecl *"; } def ArgRecordField : ArgType { let Name = "const Record::Field *"; } //===----------------------------------------------------------------------===// -// Classes of types intructions operate on. +// Classes of types instructions operate on. //===----------------------------------------------------------------------===// class TypeClass { diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index fcbab0ea817..e310c967814 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -18,6 +18,21 @@ using namespace clang; using namespace clang::interp; +unsigned Program::getOrCreateNativePointer(const void *Ptr) { + auto It = NativePointerIndices.find(Ptr); + if (It != NativePointerIndices.end()) + return It->second; + + unsigned Idx = NativePointers.size(); + NativePointers.push_back(Ptr); + NativePointerIndices[Ptr] = Idx; + return Idx; +} + +const void *Program::getNativePointer(unsigned Idx) { + return NativePointers[Idx]; +} + unsigned Program::createGlobalString(const StringLiteral *S) { const size_t CharWidth = S->getCharByteWidth(); const size_t BitWidth = CharWidth * Ctx.getCharBit(); @@ -89,7 +104,7 @@ llvm::Optional Program::getGlobal(const ValueDecl *VD) { if (It != GlobalIndices.end()) return It->second; - // Find any previous declarations which were aleady evaluated. + // Find any previous declarations which were already evaluated. llvm::Optional Index; for (const Decl *P = VD; P; P = P->getPreviousDecl()) { auto It = GlobalIndices.find(P); diff --git a/clang/lib/AST/Interp/Program.h b/clang/lib/AST/Interp/Program.h index 5f0012db9b3..c81ec777a5f 100644 --- a/clang/lib/AST/Interp/Program.h +++ b/clang/lib/AST/Interp/Program.h @@ -44,6 +44,12 @@ class Program { public: Program(Context &Ctx) : Ctx(Ctx) {} + /// Marshals a native pointer to an ID for embedding in bytecode. + unsigned getOrCreateNativePointer(const void *Ptr); + + /// Returns the value of a marshalled native pointer. + const void *getNativePointer(unsigned Idx); + /// Emits a string literal among global data. unsigned createGlobalString(const StringLiteral *S); @@ -143,6 +149,11 @@ private: /// Function relocation locations. llvm::DenseMap> Relocs; + /// Native pointers referenced by bytecode. + std::vector NativePointers; + /// Cached native pointer indices. + llvm::DenseMap NativePointerIndices; + /// Custom allocator for global storage. using PoolAllocTy = llvm::BumpPtrAllocatorImpl; diff --git a/clang/lib/AST/Interp/Source.h b/clang/lib/AST/Interp/Source.h index 19c652b7331..6acaf406b47 100644 --- a/clang/lib/AST/Interp/Source.h +++ b/clang/lib/AST/Interp/Source.h @@ -44,8 +44,9 @@ public: bool operator!=(const CodePtr &RHS) const { return Ptr != RHS.Ptr; } /// Reads data and advances the pointer. - template T read() { - T Value = ReadHelper(Ptr); + template std::enable_if_t::value, T> read() { + using namespace llvm::support; + T Value = endian::read(Ptr); Ptr += sizeof(T); return Value; } @@ -54,22 +55,6 @@ private: /// Constructor used by Function to generate pointers. CodePtr(const char *Ptr) : Ptr(Ptr) {} - /// Helper to decode a value or a pointer. - template - static std::enable_if_t::value, T> - ReadHelper(const char *Ptr) { - using namespace llvm::support; - return endian::read(Ptr); - } - - template - static std::enable_if_t::value, T> - ReadHelper(const char *Ptr) { - using namespace llvm::support; - auto Punned = endian::read(Ptr); - return reinterpret_cast(Punned); - } - private: friend class Function; diff --git a/clang/lib/AST/ItaniumCXXABI.cpp b/clang/lib/AST/ItaniumCXXABI.cpp index be10258a2d7..e99c21dcff7 100644 --- a/clang/lib/AST/ItaniumCXXABI.cpp +++ b/clang/lib/AST/ItaniumCXXABI.cpp @@ -181,6 +181,37 @@ public: } }; +// A version of this for SYCL that makes sure that 'device' mangling context +// matches the lambda mangling number, so that __builtin_sycl_unique_stable_name +// can be consistently generated between a MS and Itanium host by just referring +// to the device mangling number. +class ItaniumSYCLNumberingContext : public ItaniumNumberingContext { + llvm::DenseMap ManglingNumbers; + using ManglingItr = decltype(ManglingNumbers)::iterator; + +public: + ItaniumSYCLNumberingContext(ItaniumMangleContext *Mangler) + : ItaniumNumberingContext(Mangler) {} + + unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { + unsigned Number = ItaniumNumberingContext::getManglingNumber(CallOperator); + std::pair emplace_result = + ManglingNumbers.try_emplace(CallOperator, Number); + (void)emplace_result; + assert(emplace_result.second && "Lambda number set multiple times?"); + return Number; + } + + using ItaniumNumberingContext::getManglingNumber; + + unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override { + ManglingItr Itr = ManglingNumbers.find(CallOperator); + assert(Itr != ManglingNumbers.end() && "Lambda not yet mangled?"); + + return Itr->second; + } +}; + class ItaniumCXXABI : public CXXABI { private: std::unique_ptr Mangler; @@ -249,6 +280,9 @@ public: std::unique_ptr createMangleNumberingContext() const override { + if (Context.getLangOpts().isSYCL()) + return std::make_unique( + cast(Mangler.get())); return std::make_unique( cast(Mangler.get())); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 8cbac66fcf0..07579d04e27 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -1518,9 +1518,16 @@ void CXXNameMangler::mangleUnqualifiedName(GlobalDecl GD, // ::= * + // # Parameter types or 'v' for 'void'. if (const CXXRecordDecl *Record = dyn_cast(TD)) { - if (Record->isLambda() && (Record->getLambdaManglingNumber() || - Context.getDiscriminatorOverride()( - Context.getASTContext(), Record))) { + llvm::Optional DeviceNumber = + Context.getDiscriminatorOverride()(Context.getASTContext(), Record); + + // If we have a device-number via the discriminator, use that to mangle + // the lambda, otherwise use the typical lambda-mangling-number. In either + // case, a '0' should be mangled as a normal unnamed class instead of as a + // lambda. + if (Record->isLambda() && + ((DeviceNumber && *DeviceNumber > 0) || + (!DeviceNumber && Record->getLambdaManglingNumber() > 0))) { assert(!AdditionalAbiTags && "Lambda type cannot have additional abi tags"); mangleLambda(Record); @@ -1960,8 +1967,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { // mangling number for this lambda. llvm::Optional DeviceNumber = Context.getDiscriminatorOverride()(Context.getASTContext(), Lambda); - unsigned Number = DeviceNumber.hasValue() ? *DeviceNumber - : Lambda->getLambdaManglingNumber(); + unsigned Number = + DeviceNumber ? *DeviceNumber : Lambda->getLambdaManglingNumber(); assert(Number > 0 && "Lambda should be mangled as an unnamed class"); if (Number > 1) @@ -2860,6 +2867,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { // ::= d # double // ::= e # long double, __float80 // ::= g # __float128 + // ::= g # __ibm128 // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) @@ -2988,6 +2996,11 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { Out << TI->getBFloat16Mangling(); break; } + case BuiltinType::Ibm128: { + const TargetInfo *TI = &getASTContext().getTargetInfo(); + Out << TI->getIbm128Mangling(); + break; + } case BuiltinType::NullPtr: Out << "Dn"; break; @@ -3559,7 +3572,7 @@ void CXXNameMangler::mangleAArch64NeonVectorType(const DependentVectorType *T) { // mangling scheme, it will be specified in the next revision. The mangling // scheme is otherwise defined in the appendices to the Procedure Call Standard // for the Arm Architecture, see -// https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst#appendix-c-mangling +// https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#appendix-c-mangling void CXXNameMangler::mangleAArch64FixedSveVectorType(const VectorType *T) { assert((T->getVectorKind() == VectorType::SveFixedLengthDataVector || T->getVectorKind() == VectorType::SveFixedLengthPredicateVector) && @@ -4168,7 +4181,6 @@ recurse: case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::ParenListExprClass: - case Expr::LambdaExprClass: case Expr::MSPropertyRefExprClass: case Expr::MSPropertySubscriptExprClass: case Expr::TypoExprClass: // This should no longer exist in the AST by now. @@ -4953,6 +4965,16 @@ recurse: break; } + case Expr::LambdaExprClass: { + // A lambda-expression can't appear in the signature of an + // externally-visible declaration, so there's no standard mangling for + // this, but mangling as a literal of the closure type seems reasonable. + Out << "L"; + mangleType(Context.getASTContext().getRecordType(cast(E)->getLambdaClass())); + Out << "E"; + break; + } + case Expr::PackExpansionExprClass: NotPrimaryExpr(); Out << "sp"; diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index f09f9d38759..86879b8c353 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1489,6 +1489,8 @@ void JSONNodeDumper::VisitIfStmt(const IfStmt *IS) { attributeOnlyIfTrue("hasVar", IS->hasVarStorage()); attributeOnlyIfTrue("hasElse", IS->hasElseStorage()); attributeOnlyIfTrue("isConstexpr", IS->isConstexpr()); + attributeOnlyIfTrue("isConsteval", IS->isConsteval()); + attributeOnlyIfTrue("constevalIsNegated", IS->isNegatedConsteval()); } void JSONNodeDumper::VisitSwitchStmt(const SwitchStmt *SS) { diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 166aa3b3bd6..53d7e0b042f 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -78,6 +78,19 @@ public: } }; +class MSSYCLNumberingContext : public MicrosoftNumberingContext { + std::unique_ptr DeviceCtx; + +public: + MSSYCLNumberingContext(MangleContext *DeviceMangler) { + DeviceCtx = createItaniumNumberingContext(DeviceMangler); + } + + unsigned getDeviceManglingNumber(const CXXMethodDecl *CallOperator) override { + return DeviceCtx->getManglingNumber(CallOperator); + } +}; + class MicrosoftCXXABI : public CXXABI { ASTContext &Context; llvm::SmallDenseMap RecordToCopyCtor; @@ -100,6 +113,10 @@ public: DeviceMangler.reset( Context.createMangleContext(Context.getAuxTargetInfo())); } + else if (Context.getLangOpts().isSYCL()) { + DeviceMangler.reset( + ItaniumMangleContext::create(Context, Context.getDiagnostics())); + } } MemberPointerInfo @@ -162,7 +179,11 @@ public: if (Context.getLangOpts().CUDA && Context.getAuxTargetInfo()) { assert(DeviceMangler && "Missing device mangler"); return std::make_unique(DeviceMangler.get()); + } else if (Context.getLangOpts().isSYCL()) { + assert(DeviceMangler && "Missing device mangler"); + return std::make_unique(DeviceMangler.get()); } + return std::make_unique(); } }; diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index d89cddd2add..163d4e95386 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2466,6 +2466,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, case BuiltinType::SatUFract: case BuiltinType::SatULongFract: case BuiltinType::BFloat16: + case BuiltinType::Ibm128: case BuiltinType::Float128: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID( @@ -2824,8 +2825,8 @@ void MicrosoftCXXNameMangler::mangleArtificialTagType( // Always start with the unqualified name. mangleSourceName(UnqualifiedName); - for (auto I = NestedNames.rbegin(), E = NestedNames.rend(); I != E; ++I) - mangleSourceName(*I); + for (StringRef N : llvm::reverse(NestedNames)) + mangleSourceName(N); // Terminate the whole name with an '@'. Out << '@'; @@ -3602,7 +3603,7 @@ void MicrosoftMangleContextImpl::mangleCXXCatchableType( // FIXME: It is known that the Ctor is present in 2013, and in 2017.7 // (_MSC_VER 1914) and newer, and that it's omitted in 2015 and 2017.4 // (_MSC_VER 1911), but it's unknown when exactly it reappeared (1914? - // Or 1912, 1913 aleady?). + // Or 1912, 1913 already?). bool OmitCopyCtor = getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2015) && !getASTContext().getLangOpts().isCompatibleWithMSVC( @@ -3883,7 +3884,7 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, // - ?[A-Z]: The range from \xc1 to \xda. // - ?[0-9]: The set of [,/\:. \n\t'-]. // - ?$XX: A fallback which maps nibbles. - if (isIdentifierBody(Byte, /*AllowDollar=*/true)) { + if (isAsciiIdentifierContinue(Byte, /*AllowDollar=*/true)) { Mangler.getStream() << Byte; } else if (isLetter(Byte & 0x7f)) { Mangler.getStream() << '?' << static_cast(Byte & 0x7f); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 861060d7c87..db7878e18c4 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -456,6 +456,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::UInt128: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::Ibm128: case BuiltinType::NullPtr: case BuiltinType::ObjCClass: case BuiltinType::ObjCId: diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 21afdd1570f..8f19d80cbdc 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -311,7 +311,8 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, = dyn_cast(T)) { // Print the template name without its corresponding // nested-name-specifier. - SpecType->getTemplateName().print(OS, InnerPolicy, true); + SpecType->getTemplateName().print(OS, InnerPolicy, + TemplateName::Qualified::None); // Print the template argument list. printTemplateArgumentList(OS, SpecType->template_arguments(), diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 50f40395a19..f721e56f7fd 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -160,6 +160,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_bind: break; default: break; @@ -257,6 +259,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_bind: break; default: break; @@ -625,6 +629,13 @@ OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPAlignedClause(NumVars); } +OMPAlignClause *OMPAlignClause::Create(const ASTContext &C, Expr *A, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return new (C) OMPAlignClause(A, StartLoc, LParenLoc, EndLoc); +} + void OMPCopyinClause::setSourceExprs(ArrayRef SrcExprs) { assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " "not the same as the " @@ -1584,6 +1595,16 @@ OMPInitClause *OMPInitClause::CreateEmpty(const ASTContext &C, unsigned N) { return new (Mem) OMPInitClause(N); } +OMPBindClause * +OMPBindClause::Create(const ASTContext &C, OpenMPBindClauseKind K, + SourceLocation KLoc, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return new (C) OMPBindClause(K, KLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPBindClause *OMPBindClause::CreateEmpty(const ASTContext &C) { + return new (C) OMPBindClause(); +} //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -1608,6 +1629,12 @@ void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPAlignClause(OMPAlignClause *Node) { + OS << "align("; + Node->getAlignment()->printPretty(OS, nullptr, Policy, 0); + OS << ")"; +} + void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) { OS << "safelen("; Node->getSafelen()->printPretty(OS, nullptr, Policy, 0); @@ -2295,6 +2322,12 @@ void OMPClausePrinter::VisitOMPFilterClause(OMPFilterClause *Node) { OS << ")"; } +void OMPClausePrinter::VisitOMPBindClause(OMPBindClause *Node) { + OS << "bind(" + << getOpenMPSimpleClauseTypeName(OMPC_bind, unsigned(Node->getBindKind())) + << ")"; +} + void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { @@ -2311,9 +2344,8 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, if (Optional CondVal = Selector.ScoreOrCondition->getIntegerConstantExpr(ASTCtx)) - VMI.addTrait(CondVal->isNullValue() - ? TraitProperty::user_condition_false - : TraitProperty::user_condition_true, + VMI.addTrait(CondVal->isZero() ? TraitProperty::user_condition_false + : TraitProperty::user_condition_true, ""); else VMI.addTrait(TraitProperty::user_condition_false, ""); @@ -2342,8 +2374,6 @@ void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx, getOpenMPContextTraitPropertyForSelector( Selector.Kind) && "Ill-formed construct selector!"); - - VMI.ConstructTraits.push_back(Selector.Properties.front().Kind); } } } @@ -2474,7 +2504,8 @@ llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, TargetOMPContext::TargetOMPContext( ASTContext &ASTCtx, std::function &&DiagUnknownTrait, - const FunctionDecl *CurrentFunctionDecl) + const FunctionDecl *CurrentFunctionDecl, + ArrayRef ConstructTraits) : OMPContext(ASTCtx.getLangOpts().OpenMPIsDevice, ASTCtx.getTargetInfo().getTriple()), FeatureValidityCheck([&](StringRef FeatureName) { @@ -2482,6 +2513,9 @@ TargetOMPContext::TargetOMPContext( }), DiagUnknownTrait(std::move(DiagUnknownTrait)) { ASTCtx.getFunctionFeatureMap(FeatureMap, CurrentFunctionDecl); + + for (llvm::omp::TraitProperty Property : ConstructTraits) + addTrait(Property); } bool TargetOMPContext::matchesISATrait(StringRef RawString) const { diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 4a3e0a99c8a..d216be5b59e 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -389,11 +389,10 @@ private: auto *Vector = NodeOrVector.template get(); // Skip duplicates for types that have memoization data. // We must check that the type has memoization data before calling - // std::find() because DynTypedNode::operator== can't compare all + // llvm::is_contained() because DynTypedNode::operator== can't compare all // types. bool Found = ParentStack.back().getMemoizationData() && - std::find(Vector->begin(), Vector->end(), - ParentStack.back()) != Vector->end(); + llvm::is_contained(*Vector, ParentStack.back()); if (!Found) Vector->push_back(ParentStack.back()); } @@ -429,6 +428,11 @@ private: [&] { return VisitorBase::TraverseNestedNameSpecifierLoc(NNSLocNode); }, &Map.OtherParents); } + bool TraverseAttr(Attr *AttrNode) { + return TraverseNode( + AttrNode, AttrNode, [&] { return VisitorBase::TraverseAttr(AttrNode); }, + &Map.PointerParents); + } // Using generic TraverseNode for Stmt would prevent data-recursion. bool dataTraverseStmtPre(Stmt *StmtNode) { diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 4806c554a2a..e2569c9e20d 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -755,6 +755,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, case BuiltinType::BFloat16: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::Ibm128: case BuiltinType::ShortAccum: case BuiltinType::Accum: case BuiltinType::LongAccum: diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index 9a1b418f5ac..67382107834 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -296,7 +296,7 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( } else if (const auto *TD = dyn_cast(Outer)) { return createNestedNameSpecifier( Ctx, TD, FullyQualified, WithGlobalNsPrefix); - } else if (dyn_cast(Outer)) { + } else if (isa(Outer)) { // Context is the TU. Nothing needs to be done. return nullptr; } else { diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 972690becf9..3e39ec1c718 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -240,7 +240,7 @@ EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, return true; const ClassVectorTy &Classes = I->second; - if (llvm::find(Classes, RD) == Classes.end()) + if (!llvm::is_contained(Classes, RD)) return true; // There is already an empty class of the same type at this offset. @@ -1538,7 +1538,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { TypeInfo FieldInfo = Context.getTypeInfo(D->getType()); uint64_t StorageUnitSize = FieldInfo.Width; unsigned FieldAlign = FieldInfo.Align; - bool AlignIsRequired = FieldInfo.AlignIsRequired; + bool AlignIsRequired = FieldInfo.isAlignRequired(); // UnfilledBitsInLastUnit is the difference between the end of the // last allocated bitfield (i.e. the first bit offset available for @@ -1775,11 +1775,18 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { !D->getIdentifier()) FieldAlign = UnpackedFieldAlign = 1; - // On AIX, zero-width bitfields pad out to the alignment boundary, but then - // do not affect overall record alignment if there is a pragma pack or - // pragma align(packed). - if (isAIXLayout(Context) && !MaxFieldAlignment.isZero() && !FieldSize) - FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + // On AIX, zero-width bitfields pad out to the natural alignment boundary, + // but do not increase the alignment greater than the MaxFieldAlignment, or 1 + // if packed. + if (isAIXLayout(Context) && !FieldSize) { + if (FieldPacked) + FieldAlign = 1; + if (!MaxFieldAlignment.isZero()) { + UnpackedFieldAlign = + std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + } + } // Diagnose differences in layout due to padding or packing. if (!UseExternalLayout) @@ -1882,7 +1889,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, bool FieldPacked = Packed || D->hasAttr(); - bool AlignIsRequired = false; + AlignRequirementKind AlignRequirement = AlignRequirementKind::None; CharUnits FieldSize; CharUnits FieldAlign; // The amount of this class's dsize occupied by the field. @@ -1897,7 +1904,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // aligned appropriately for their element type. EffectiveFieldSize = FieldSize = IsIncompleteArrayType ? CharUnits::Zero() : TI.Width; - AlignIsRequired = TI.AlignIsRequired; + AlignRequirement = TI.AlignRequirement; }; if (D->getType()->isIncompleteArrayType()) { @@ -1947,7 +1954,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // Since the combination of -mms-bitfields together with structs // like max_align_t (which contains a long double) for mingw is - // quite comon (and GCC handles it silently), just handle it + // quite common (and GCC handles it silently), just handle it // silently there. For other targets that have ms_struct enabled // (most probably via a pragma or attribute), trigger a diagnostic // that defaults to an error. @@ -1961,6 +1968,19 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } } + // When used as part of a typedef, or together with a 'packed' attribute, the + // 'aligned' attribute can be used to decrease alignment. In that case, it + // overrides any computed alignment we have, and there is no need to upgrade + // the alignment. + auto alignedAttrCanDecreaseAIXAlignment = [AlignRequirement, FieldPacked] { + // Enum alignment sources can be safely ignored here, because this only + // helps decide whether we need the AIX alignment upgrade, which only + // applies to floating-point types. + return AlignRequirement == AlignRequirementKind::RequiredByTypedef || + (AlignRequirement == AlignRequirementKind::RequiredByRecord && + FieldPacked); + }; + // The AIX `power` alignment rules apply the natural alignment of the // "first member" if it is of a floating-point data type (or is an aggregate // whose recursively "first" member or element is such a type). The alignment @@ -1971,7 +1991,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, // and zero-width bit-fields count as prior members; members of empty class // types marked `no_unique_address` are not considered to be prior members. CharUnits PreferredAlign = FieldAlign; - if (DefaultsToAIXPowerAlignment && !AlignIsRequired && + if (DefaultsToAIXPowerAlignment && !alignedAttrCanDecreaseAIXAlignment() && (FoundFirstNonOverlappingEmptyFieldForAIX || IsNaturalAlign)) { auto performBuiltinTypeAlignmentUpgrade = [&](const BuiltinType *BTy) { if (BTy->getKind() == BuiltinType::Double || @@ -1982,12 +2002,13 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } }; - const Type *Ty = D->getType()->getBaseElementTypeUnsafe(); - if (const ComplexType *CTy = Ty->getAs()) { - performBuiltinTypeAlignmentUpgrade(CTy->getElementType()->castAs()); - } else if (const BuiltinType *BTy = Ty->getAs()) { + const Type *BaseTy = D->getType()->getBaseElementTypeUnsafe(); + if (const ComplexType *CTy = BaseTy->getAs()) { + performBuiltinTypeAlignmentUpgrade( + CTy->getElementType()->castAs()); + } else if (const BuiltinType *BTy = BaseTy->getAs()) { performBuiltinTypeAlignmentUpgrade(BTy); - } else if (const RecordType *RT = Ty->getAs()) { + } else if (const RecordType *RT = BaseTy->getAs()) { const RecordDecl *RD = RT->getDecl(); assert(RD && "Expected non-null RecordDecl."); const ASTRecordLayout &FieldRecord = Context.getASTRecordLayout(RD); @@ -2610,7 +2631,7 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // Track zero-sized subobjects here where it's already available. EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); // Respect required alignment, this is necessary because we may have adjusted - // the alignment in the case of pragam pack. Note that the required alignment + // the alignment in the case of pragma pack. Note that the required alignment // doesn't actually apply to the struct alignment at this point. Alignment = std::max(Alignment, Info.Alignment); RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment()); @@ -3070,7 +3091,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { for (const CXXBaseSpecifier &VBase : RD->vbases()) { const CXXRecordDecl *BaseDecl = VBase.getType()->getAsCXXRecordDecl(); const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl); - bool HasVtordisp = HasVtorDispSet.count(BaseDecl) > 0; + bool HasVtordisp = HasVtorDispSet.contains(BaseDecl); // Insert padding between two bases if the left first one is zero sized or // contains a zero sized subobject and the right is zero sized or one leads // with a zero sized base. The padding between virtual bases is 4 @@ -3383,6 +3404,7 @@ uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const { uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID, const ObjCImplementationDecl *ID, const ObjCIvarDecl *Ivar) const { + Ivar = Ivar->getCanonicalDecl(); const ObjCInterfaceDecl *Container = Ivar->getContainingInterface(); // FIXME: We should eliminate the need to have ObjCImplementationDecl passed diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 47693ef9fee..4f76f6ec12e 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -912,7 +912,7 @@ void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr, }); } -IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, +IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, IfStatementKind Kind, Stmt *Init, VarDecl *Var, Expr *Cond, SourceLocation LPL, SourceLocation RPL, Stmt *Then, SourceLocation EL, Stmt *Else) : Stmt(IfStmtClass), LParenLoc(LPL), RParenLoc(RPL) { @@ -923,7 +923,7 @@ IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, IfStmtBits.HasVar = HasVar; IfStmtBits.HasInit = HasInit; - setConstexpr(IsConstexpr); + setStatementKind(Kind); setCond(Cond); setThen(Then); @@ -947,9 +947,9 @@ IfStmt::IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit) } IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL, - bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, - SourceLocation LPL, SourceLocation RPL, Stmt *Then, - SourceLocation EL, Stmt *Else) { + IfStatementKind Kind, Stmt *Init, VarDecl *Var, + Expr *Cond, SourceLocation LPL, SourceLocation RPL, + Stmt *Then, SourceLocation EL, Stmt *Else) { bool HasElse = Else != nullptr; bool HasVar = Var != nullptr; bool HasInit = Init != nullptr; @@ -958,7 +958,7 @@ IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL, NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse), alignof(IfStmt)); return new (Mem) - IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, LPL, RPL, Then, EL, Else); + IfStmt(Ctx, IL, Kind, Init, Var, Cond, LPL, RPL, Then, EL, Else); } IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar, diff --git a/clang/lib/AST/StmtObjC.cpp b/clang/lib/AST/StmtObjC.cpp index 3d586795517..12d8a9e7dac 100644 --- a/clang/lib/AST/StmtObjC.cpp +++ b/clang/lib/AST/StmtObjC.cpp @@ -46,9 +46,8 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context, SourceLocation atTryLoc, Stmt *atTryStmt, Stmt **CatchStmts, unsigned NumCatchStmts, Stmt *atFinallyStmt) { - unsigned Size = - sizeof(ObjCAtTryStmt) + - (1 + NumCatchStmts + (atFinallyStmt != nullptr)) * sizeof(Stmt *); + size_t Size = + totalSizeToAlloc(1 + NumCatchStmts + (atFinallyStmt != nullptr)); void *Mem = Context.Allocate(Size, alignof(ObjCAtTryStmt)); return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, atFinallyStmt); @@ -57,8 +56,7 @@ ObjCAtTryStmt *ObjCAtTryStmt::Create(const ASTContext &Context, ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(const ASTContext &Context, unsigned NumCatchStmts, bool HasFinally) { - unsigned Size = - sizeof(ObjCAtTryStmt) + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + size_t Size = totalSizeToAlloc(1 + NumCatchStmts + HasFinally); void *Mem = Context.Allocate(Size, alignof(ObjCAtTryStmt)); return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); } diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index b0ef2f49ba0..b336a0637d5 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -125,28 +125,34 @@ OMPLoopBasedDirective::tryToFindNextInnerLoop(Stmt *CurStmt, bool OMPLoopBasedDirective::doForAllLoops( Stmt *CurStmt, bool TryImperfectlyNestedLoops, unsigned NumLoops, llvm::function_ref Callback, - llvm::function_ref + llvm::function_ref OnTransformationCallback) { CurStmt = CurStmt->IgnoreContainers(); for (unsigned Cnt = 0; Cnt < NumLoops; ++Cnt) { while (true) { - auto *OrigStmt = CurStmt; - if (auto *Dir = dyn_cast(OrigStmt)) { - OnTransformationCallback(Dir); - CurStmt = Dir->getTransformedStmt(); - } else if (auto *Dir = dyn_cast(OrigStmt)) { - OnTransformationCallback(Dir); - CurStmt = Dir->getTransformedStmt(); - } else { + auto *Dir = dyn_cast(CurStmt); + if (!Dir) break; + + OnTransformationCallback(Dir); + + Stmt *TransformedStmt = Dir->getTransformedStmt(); + if (!TransformedStmt) { + unsigned NumGeneratedLoops = Dir->getNumGeneratedLoops(); + if (NumGeneratedLoops == 0) { + // May happen if the loop transformation does not result in a + // generated loop (such as full unrolling). + break; + } + if (NumGeneratedLoops > 0) { + // The loop transformation construct has generated loops, but these + // may not have been generated yet due to being in a dependent + // context. + return true; + } } - if (!CurStmt) { - // May happen if the loop transformation does not result in a generated - // loop (such as full unrolling). - CurStmt = OrigStmt; - break; - } + CurStmt = TransformedStmt; } if (auto *CanonLoop = dyn_cast(CurStmt)) CurStmt = CanonLoop->getLoopStmt(); @@ -253,6 +259,25 @@ void OMPLoopDirective::setFinalsConditions(ArrayRef A) { llvm::copy(A, getFinalsConditions().begin()); } +OMPMetaDirective *OMPMetaDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt, Stmt *IfStmt) { + auto *Dir = createDirective( + C, Clauses, AssociatedStmt, /*NumChildren=*/1, StartLoc, EndLoc); + Dir->setIfStmt(IfStmt); + return Dir; +} + +OMPMetaDirective *OMPMetaDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + return createEmptyDirective(C, NumClauses, + /*HasAssociatedStmt=*/true, + /*NumChildren=*/1); +} + OMPParallelDirective *OMPParallelDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef Clauses, Stmt *AssociatedStmt, Expr *TaskRedRef, @@ -344,6 +369,32 @@ OMPForDirective *OMPForDirective::Create( return Dir; } +Stmt *OMPLoopTransformationDirective::getTransformedStmt() const { + switch (getStmtClass()) { +#define STMT(CLASS, PARENT) +#define ABSTRACT_STMT(CLASS) +#define OMPLOOPTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + return static_cast(this)->getTransformedStmt(); +#include "clang/AST/StmtNodes.inc" + default: + llvm_unreachable("Not a loop transformation"); + } +} + +Stmt *OMPLoopTransformationDirective::getPreInits() const { + switch (getStmtClass()) { +#define STMT(CLASS, PARENT) +#define ABSTRACT_STMT(CLASS) +#define OMPLOOPTRANSFORMATIONDIRECTIVE(CLASS, PARENT) \ + case Stmt::CLASS##Class: \ + return static_cast(this)->getPreInits(); +#include "clang/AST/StmtNodes.inc" + default: + llvm_unreachable("Not a loop transformation"); + } +} + OMPForDirective *OMPForDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, @@ -377,10 +428,13 @@ OMPTileDirective *OMPTileDirective::CreateEmpty(const ASTContext &C, OMPUnrollDirective * OMPUnrollDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef Clauses, - Stmt *AssociatedStmt, Stmt *TransformedStmt, - Stmt *PreInits) { + Stmt *AssociatedStmt, unsigned NumGeneratedLoops, + Stmt *TransformedStmt, Stmt *PreInits) { + assert(NumGeneratedLoops <= 1 && "Unrolling generates at most one loop"); + auto *Dir = createDirective( C, Clauses, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc); + Dir->setNumGeneratedLoops(NumGeneratedLoops); Dir->setTransformedStmt(TransformedStmt); Dir->setPreInits(PreInits); return Dir; @@ -685,15 +739,19 @@ OMPBarrierDirective *OMPBarrierDirective::CreateEmpty(const ASTContext &C, return new (C) OMPBarrierDirective(); } -OMPTaskwaitDirective *OMPTaskwaitDirective::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation EndLoc) { - return new (C) OMPTaskwaitDirective(StartLoc, EndLoc); +OMPTaskwaitDirective * +OMPTaskwaitDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses) { + return createDirective( + C, Clauses, /*AssociatedStmt=*/nullptr, /*NumChildren=*/0, StartLoc, + EndLoc); } OMPTaskwaitDirective *OMPTaskwaitDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, EmptyShell) { - return new (C) OMPTaskwaitDirective(); + return createEmptyDirective(C, NumClauses); } OMPTaskgroupDirective *OMPTaskgroupDirective::Create( @@ -2032,3 +2090,45 @@ OMPMaskedDirective *OMPMaskedDirective::CreateEmpty(const ASTContext &C, return createEmptyDirective(C, NumClauses, /*HasAssociatedStmt=*/true); } + +OMPGenericLoopDirective *OMPGenericLoopDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { + auto *Dir = createDirective( + C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_loop), + StartLoc, EndLoc, CollapsedNum); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setNumIterations(Exprs.NumIterations); + Dir->setCounters(Exprs.Counters); + Dir->setPrivateCounters(Exprs.PrivateCounters); + Dir->setInits(Exprs.Inits); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); + Dir->setPreInits(Exprs.PreInits); + return Dir; +} + +OMPGenericLoopDirective * +OMPGenericLoopDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses, + unsigned CollapsedNum, EmptyShell) { + return createEmptyDirective( + C, NumClauses, /*HasAssociatedStmt=*/true, + numLoopChildren(CollapsedNum, OMPD_loop), CollapsedNum); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 45b15171aa9..fc267d7006a 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -236,6 +236,22 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { } void StmtPrinter::PrintRawIfStmt(IfStmt *If) { + if (If->isConsteval()) { + OS << "if "; + if (If->isNegatedConsteval()) + OS << "!"; + OS << "consteval"; + OS << NL; + PrintStmt(If->getThen()); + if (Stmt *Else = If->getElse()) { + Indent(); + OS << "else"; + PrintStmt(Else); + OS << NL; + } + return; + } + OS << "if ("; if (If->getInit()) PrintInitStmt(If->getInit(), 4); @@ -505,13 +521,10 @@ void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { OS << NL; } - for (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I); + for (ObjCAtCatchStmt *catchStmt : Node->catch_stmts()) { Indent() << "@catch("; - if (catchStmt->getCatchParamDecl()) { - if (Decl *DS = catchStmt->getCatchParamDecl()) - PrintRawDecl(DS); - } + if (Decl *DS = catchStmt->getCatchParamDecl()) + PrintRawDecl(DS); OS << ")"; if (auto *CS = dyn_cast(catchStmt->getCatchBody())) { PrintRawCompoundStmt(CS); @@ -654,6 +667,11 @@ void StmtPrinter::PrintOMPExecutableDirective(OMPExecutableDirective *S, PrintStmt(S->getRawStmt()); } +void StmtPrinter::VisitOMPMetaDirective(OMPMetaDirective *Node) { + Indent() << "#pragma omp metadirective"; + PrintOMPExecutableDirective(Node); +} + void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { Indent() << "#pragma omp parallel"; PrintOMPExecutableDirective(Node); @@ -982,6 +1000,11 @@ void StmtPrinter::VisitOMPMaskedDirective(OMPMaskedDirective *Node) { PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPGenericLoopDirective(OMPGenericLoopDirective *Node) { + Indent() << "#pragma omp loop"; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// @@ -1183,6 +1206,7 @@ static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, switch (Node->getType()->castAs()->getKind()) { default: llvm_unreachable("Unexpected type for float literal!"); case BuiltinType::Half: break; // FIXME: suffix? + case BuiltinType::Ibm128: break; // FIXME: No suffix for ibm128 literal case BuiltinType::Double: break; // no suffix. case BuiltinType::Float16: OS << "F16"; break; case BuiltinType::Float: OS << 'F'; break; @@ -2571,6 +2595,14 @@ void Stmt::printPretty(raw_ostream &Out, PrinterHelper *Helper, P.Visit(const_cast(this)); } +void Stmt::printPrettyControlled(raw_ostream &Out, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation, StringRef NL, + const ASTContext *Context) const { + StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context); + P.PrintControlledStmt(const_cast(this)); +} + void Stmt::printJson(raw_ostream &Out, PrinterHelper *Helper, const PrintingPolicy &Policy, bool AddQuotes) const { std::string Buf; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index ed000c2467f..4339c249e02 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -452,6 +452,11 @@ void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) { Profiler->VisitStmt(C->getNumThreads()); } +void OMPClauseProfiler::VisitOMPAlignClause(const OMPAlignClause *C) { + if (C->getAlignment()) + Profiler->VisitStmt(C->getAlignment()); +} + void OMPClauseProfiler::VisitOMPSafelenClause(const OMPSafelenClause *C) { if (C->getSafelen()) Profiler->VisitStmt(C->getSafelen()); @@ -878,6 +883,7 @@ void OMPClauseProfiler::VisitOMPAffinityClause(const OMPAffinityClause *C) { Profiler->VisitStmt(E); } void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} +void OMPClauseProfiler::VisitOMPBindClause(const OMPBindClause *C) {} } // namespace void @@ -903,6 +909,10 @@ void StmtProfiler::VisitOMPLoopDirective(const OMPLoopDirective *S) { VisitOMPLoopBasedDirective(S); } +void StmtProfiler::VisitOMPMetaDirective(const OMPMetaDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { VisitOMPExecutableDirective(S); } @@ -911,12 +921,17 @@ void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) { VisitOMPLoopDirective(S); } -void StmtProfiler::VisitOMPTileDirective(const OMPTileDirective *S) { +void StmtProfiler::VisitOMPLoopTransformationDirective( + const OMPLoopTransformationDirective *S) { VisitOMPLoopBasedDirective(S); } +void StmtProfiler::VisitOMPTileDirective(const OMPTileDirective *S) { + VisitOMPLoopTransformationDirective(S); +} + void StmtProfiler::VisitOMPUnrollDirective(const OMPUnrollDirective *S) { - VisitOMPLoopBasedDirective(S); + VisitOMPLoopTransformationDirective(S); } void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { @@ -1181,6 +1196,11 @@ void StmtProfiler::VisitOMPMaskedDirective(const OMPMaskedDirective *S) { VisitOMPExecutableDirective(S); } +void StmtProfiler::VisitOMPGenericLoopDirective( + const OMPGenericLoopDirective *S) { + VisitOMPLoopDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } @@ -1924,30 +1944,9 @@ StmtProfiler::VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { void StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { VisitExpr(S); - for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), - CEnd = S->explicit_capture_end(); - C != CEnd; ++C) { - if (C->capturesVLAType()) - continue; - - ID.AddInteger(C->getCaptureKind()); - switch (C->getCaptureKind()) { - case LCK_StarThis: - case LCK_This: - break; - case LCK_ByRef: - case LCK_ByCopy: - VisitDecl(C->getCapturedVar()); - ID.AddBoolean(C->isPackExpansion()); - break; - case LCK_VLAType: - llvm_unreachable("VLA type in explicit captures."); - } - } - // Note: If we actually needed to be able to match lambda - // expressions, we would have to consider parameters and return type - // here, among other things. - VisitStmt(S->getBody()); + // C++20 [temp.over.link]p5: + // Two lambda-expressions are never considered equivalent. + VisitDecl(S->getLambdaClass()); } void diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index f44230d1bd0..619ce42f9dd 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -452,7 +452,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, break; case Template: - getAsTemplate().print(Out, Policy); + getAsTemplate().print(Out, Policy, TemplateName::Qualified::Fully); break; case TemplateExpansion: diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 22cfa9acbe1..c8bd74f0b5b 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -220,19 +220,28 @@ bool TemplateName::containsUnexpandedParameterPack() const { return getDependence() & TemplateNameDependence::UnexpandedPack; } -void -TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, - bool SuppressNNS) const { +void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, + Qualified Qual) const { if (TemplateDecl *Template = Storage.dyn_cast()) - OS << *Template; + if (Qual == Qualified::Fully && + getDependence() != TemplateNameDependenceScope::DependentInstantiation) + Template->printQualifiedName(OS, Policy); + else + OS << *Template; else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { - if (!SuppressNNS) + if (Qual == Qualified::Fully && + getDependence() != + TemplateNameDependenceScope::DependentInstantiation) { + QTN->getTemplateDecl()->printQualifiedName(OS, Policy); + return; + } + if (Qual == Qualified::AsWritten) QTN->getQualifier()->print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; OS << *QTN->getDecl(); } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { - if (!SuppressNNS && DTN->getQualifier()) + if (Qual == Qualified::AsWritten && DTN->getQualifier()) DTN->getQualifier()->print(OS, Policy); OS << "template "; @@ -242,7 +251,7 @@ TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, OS << "operator " << getOperatorSpelling(DTN->getOperator()); } else if (SubstTemplateTemplateParmStorage *subst = getAsSubstTemplateTemplateParm()) { - subst->getReplacement().print(OS, Policy, SuppressNNS); + subst->getReplacement().print(OS, Policy, Qual); } else if (SubstTemplateTemplateParmPackStorage *SubstPack = getAsSubstTemplateTemplateParmPack()) OS << *SubstPack->getParameterPack(); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 33f914f9f88..b21e806e307 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -948,6 +948,14 @@ void TextNodeDumper::VisitIfStmt(const IfStmt *Node) { OS << " has_var"; if (Node->hasElseStorage()) OS << " has_else"; + if (Node->isConstexpr()) + OS << " constexpr"; + if (Node->isConsteval()) { + OS << " "; + if (Node->isNegatedConsteval()) + OS << "!"; + OS << "consteval"; + } } void TextNodeDumper::VisitSwitchStmt(const SwitchStmt *Node) { diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4a2fc5219ef..e0ac3f5b135 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -821,6 +821,13 @@ QualType ObjCObjectType::stripObjCKindOfTypeAndQuals( /*isKindOf=*/false); } +ObjCInterfaceDecl *ObjCInterfaceType::getDecl() const { + ObjCInterfaceDecl *Canon = Decl->getCanonicalDecl(); + if (ObjCInterfaceDecl *Def = Canon->getDefinition()) + return Def; + return Canon; +} + const ObjCObjectPointerType *ObjCObjectPointerType::stripObjCKindOfTypeAndQuals( const ASTContext &ctx) const { if (!isKindOfType() && qual_empty()) @@ -1885,7 +1892,7 @@ DeducedType *Type::getContainedDeducedType() const { } bool Type::hasAutoForTrailingReturnType() const { - return dyn_cast_or_null( + return isa_and_nonnull( GetContainedDeducedTypeVisitor(true).Visit(this)); } @@ -2097,7 +2104,7 @@ bool Type::hasUnsignedIntegerRepresentation() const { bool Type::isFloatingType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Half && - BT->getKind() <= BuiltinType::Float128; + BT->getKind() <= BuiltinType::Ibm128; if (const auto *CT = dyn_cast(CanonicalType)) return CT->getElementType()->isFloatingType(); return false; @@ -2119,7 +2126,7 @@ bool Type::isRealFloatingType() const { bool Type::isRealType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Float128; + BT->getKind() <= BuiltinType::Ibm128; if (const auto *ET = dyn_cast(CanonicalType)) return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); return isExtIntType(); @@ -2128,7 +2135,7 @@ bool Type::isRealType() const { bool Type::isArithmeticType() const { if (const auto *BT = dyn_cast(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Float128 && + BT->getKind() <= BuiltinType::Ibm128 && BT->getKind() != BuiltinType::BFloat16; if (const auto *ET = dyn_cast(CanonicalType)) // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). @@ -2785,7 +2792,6 @@ bool Type::isSpecifierType() const { case DependentTemplateSpecialization: case ObjCInterface: case ObjCObject: - case ObjCObjectPointer: // FIXME: object pointers aren't really specifiers return true; default: return false; @@ -3030,6 +3036,8 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { return "_Float16"; case Float128: return "__float128"; + case Ibm128: + return "__ibm128"; case WChar_S: case WChar_U: return Policy.MSWChar ? "__wchar_t" : "wchar_t"; @@ -3040,7 +3048,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case Char32: return "char32_t"; case NullPtr: - return "nullptr_t"; + return "std::nullptr_t"; case Overload: return ""; case BoundMember: @@ -3505,7 +3513,7 @@ bool RecordType::hasConstFields() const { return true; FieldTy = FieldTy.getCanonicalType(); if (const auto *FieldRecTy = FieldTy->getAs()) { - if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } } @@ -3757,8 +3765,8 @@ public: friend CachedProperties merge(CachedProperties L, CachedProperties R) { Linkage MergedLinkage = minLinkage(L.L, R.L); - return CachedProperties(MergedLinkage, - L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType()); + return CachedProperties(MergedLinkage, L.hasLocalOrUnnamedType() || + R.hasLocalOrUnnamedType()); } }; @@ -4392,10 +4400,10 @@ void clang::FixedPointValueToString(SmallVectorImpl &Str, } AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, + TypeDependence ExtraDependence, QualType Canon, ConceptDecl *TypeConstraintConcept, ArrayRef TypeConstraintArgs) - : DeducedType(Auto, DeducedAsType, ExtraDependence) { + : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { AutoTypeBits.Keyword = (unsigned)Keyword; AutoTypeBits.NumArgs = TypeConstraintArgs.size(); this->TypeConstraintConcept = TypeConstraintConcept; diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 16d953b4bec..c3ed08d5a8b 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -240,6 +240,8 @@ SourceLocation TypeLoc::getEndLoc() const { case IncompleteArray: case VariableArray: case FunctionNoProto: + // The innermost type with suffix syntax always determines the end of the + // type. Last = Cur; break; case FunctionProto: @@ -248,12 +250,19 @@ SourceLocation TypeLoc::getEndLoc() const { else Last = Cur; break; + case ObjCObjectPointer: + // `id` and `id<...>` have no star location. + if (Cur.castAs().getStarLoc().isInvalid()) + break; + LLVM_FALLTHROUGH; case Pointer: case BlockPointer: case MemberPointer: case LValueReference: case RValueReference: case PackExpansion: + // Types with prefix syntax only determine the end of the type if there + // is no suffix type. if (!Last) Last = Cur; break; @@ -351,6 +360,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::LongDouble: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::Ibm128: case BuiltinType::ShortAccum: case BuiltinType::Accum: case BuiltinType::LongAccum: diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 5de22f76f45..eca9af3e5f3 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -200,11 +200,12 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, // type expands to a simple string. bool CanPrefixQualifiers = false; NeedARCStrongQualifier = false; - Type::TypeClass TC = T->getTypeClass(); + const Type *UnderlyingType = T; if (const auto *AT = dyn_cast(T)) - TC = AT->desugar()->getTypeClass(); + UnderlyingType = AT->desugar().getTypePtr(); if (const auto *Subst = dyn_cast(T)) - TC = Subst->getReplacementType()->getTypeClass(); + UnderlyingType = Subst->getReplacementType().getTypePtr(); + Type::TypeClass TC = UnderlyingType->getTypeClass(); switch (TC) { case Type::Auto: @@ -241,13 +242,17 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType(); break; - case Type::ConstantArray: - case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: NeedARCStrongQualifier = true; LLVM_FALLTHROUGH; + case Type::ConstantArray: + case Type::IncompleteArray: + return canPrefixQualifiers( + cast(UnderlyingType)->getElementType().getTypePtr(), + NeedARCStrongQualifier); + case Type::Adjusted: case Type::Decayed: case Type::Pointer: @@ -498,7 +503,6 @@ void TypePrinter::printMemberPointerAfter(const MemberPointerType *T, void TypePrinter::printConstantArrayBefore(const ConstantArrayType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } @@ -521,7 +525,6 @@ void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } @@ -534,7 +537,6 @@ void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T, void TypePrinter::printVariableArrayBefore(const VariableArrayType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } @@ -581,7 +583,6 @@ void TypePrinter::printDependentSizedArrayBefore( const DependentSizedArrayType *T, raw_ostream &OS) { IncludeStrongLifetimeRAII Strong(Policy); - SaveAndRestore NonEmptyPH(HasEmptyPlaceHolder, false); printBefore(T->getElementType(), OS); } @@ -1363,9 +1364,11 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { void TypePrinter::printRecordBefore(const RecordType *T, raw_ostream &OS) { // Print the preferred name if we have one for this type. - for (const auto *PNA : T->getDecl()->specific_attrs()) { - if (declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), - T->getDecl())) { + if (Policy.UsePreferredNames) { + for (const auto *PNA : T->getDecl()->specific_attrs()) { + if (!declaresSameEntity(PNA->getTypedefType()->getAsCXXRecordDecl(), + T->getDecl())) + continue; // Find the outermost typedef or alias template. QualType T = PNA->getTypedefType(); while (true) { @@ -1743,6 +1746,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::ArmMveStrictPolymorphism: OS << "__clang_arm_mve_strict_polymorphism"; break; + case attr::BTFTypeTag: + OS << "btf_type_tag"; + break; } OS << "))"; } @@ -1998,10 +2004,9 @@ static bool isSubstitutedDefaultArgument(ASTContext &Ctx, TemplateArgument Arg, } template -static void printTo(raw_ostream &OS, ArrayRef Args, - const PrintingPolicy &Policy, bool SkipBrackets, - const TemplateParameterList *TPL, bool IsPack, - unsigned ParmIndex) { +static void +printTo(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, + const TemplateParameterList *TPL, bool IsPack, unsigned ParmIndex) { // Drop trailing template arguments that match default arguments. if (TPL && Policy.SuppressDefaultTemplateArgs && !Policy.PrintCanonicalTypes && !Args.empty() && !IsPack && @@ -2018,7 +2023,7 @@ static void printTo(raw_ostream &OS, ArrayRef Args, } const char *Comma = Policy.MSVCFormatting ? "," : ", "; - if (!SkipBrackets) + if (!IsPack) OS << '<'; bool NeedSpace = false; @@ -2031,15 +2036,15 @@ static void printTo(raw_ostream &OS, ArrayRef Args, if (Argument.getKind() == TemplateArgument::Pack) { if (Argument.pack_size() && !FirstArg) OS << Comma; - printTo(ArgOS, Argument.getPackAsArray(), Policy, true, TPL, + printTo(ArgOS, Argument.getPackAsArray(), Policy, TPL, /*IsPack*/ true, ParmIndex); } else { if (!FirstArg) OS << Comma; // Tries to print the argument with location info if exists. - printArgument( - Arg, Policy, ArgOS, - TemplateParameterList::shouldIncludeTypeForArgument(TPL, ParmIndex)); + printArgument(Arg, Policy, ArgOS, + TemplateParameterList::shouldIncludeTypeForArgument( + Policy, TPL, ParmIndex)); } StringRef ArgString = ArgOS.str(); @@ -2053,20 +2058,21 @@ static void printTo(raw_ostream &OS, ArrayRef Args, // If the last character of our string is '>', add another space to // keep the two '>''s separate tokens. - NeedSpace = Policy.SplitTemplateClosers && !ArgString.empty() && - ArgString.back() == '>'; - FirstArg = false; + if (!ArgString.empty()) { + NeedSpace = Policy.SplitTemplateClosers && ArgString.back() == '>'; + FirstArg = false; + } // Use same template parameter for all elements of Pack if (!IsPack) ParmIndex++; } - if (NeedSpace) - OS << ' '; - - if (!SkipBrackets) + if (!IsPack) { + if (NeedSpace) + OS << ' '; OS << '>'; + } } void clang::printTemplateArgumentList(raw_ostream &OS, @@ -2080,14 +2086,14 @@ void clang::printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, const TemplateParameterList *TPL) { - printTo(OS, Args, Policy, false, TPL, /*isPack*/ false, /*parmIndex*/ 0); + printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0); } void clang::printTemplateArgumentList(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, const TemplateParameterList *TPL) { - printTo(OS, Args, Policy, false, TPL, /*isPack*/ false, /*parmIndex*/ 0); + printTo(OS, Args, Policy, TPL, /*isPack*/ false, /*parmIndex*/ 0); } std::string Qualifiers::getAsString() const { diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 38d6fc28e09..f938565c3cb 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -1070,7 +1070,7 @@ void ItaniumVTableBuilder::AddThunk(const CXXMethodDecl *MD, SmallVectorImpl &ThunksVector = Thunks[MD]; // Check if we have this thunk already. - if (llvm::find(ThunksVector, Thunk) != ThunksVector.end()) + if (llvm::is_contained(ThunksVector, Thunk)) return; ThunksVector.push_back(Thunk); @@ -1418,8 +1418,7 @@ FindNearestOverriddenMethod(const CXXMethodDecl *MD, OverriddenMethodsSetTy OverriddenMethods; ComputeAllOverriddenMethods(MD, OverriddenMethods); - for (const CXXRecordDecl *PrimaryBase : - llvm::make_range(Bases.rbegin(), Bases.rend())) { + for (const CXXRecordDecl *PrimaryBase : llvm::reverse(Bases)) { // Now check the overridden methods. for (const CXXMethodDecl *OverriddenMD : OverriddenMethods) { // We found our overridden method. @@ -2498,7 +2497,7 @@ private: SmallVector &ThunksVector = Thunks[MD]; // Check if we have this thunk already. - if (llvm::find(ThunksVector, Thunk) != ThunksVector.end()) + if (llvm::is_contained(ThunksVector, Thunk)) return; ThunksVector.push_back(Thunk); @@ -3098,8 +3097,7 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, } static void PrintBasePath(const VPtrInfo::BasePath &Path, raw_ostream &Out) { - for (const CXXRecordDecl *Elem : - llvm::make_range(Path.rbegin(), Path.rend())) { + for (const CXXRecordDecl *Elem : llvm::reverse(Path)) { Out << "'"; Elem->printQualifiedName(Out); Out << "' in "; @@ -3454,7 +3452,7 @@ static void removeRedundantPaths(std::list &FullPaths) { if (&SpecificPath == &OtherPath) continue; if (llvm::all_of(SpecificPath, [&](const BaseSubobject &BSO) { - return OtherPath.count(BSO) != 0; + return OtherPath.contains(BSO); })) { return true; } diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 5d6cea54b8e..b19a7fe3be0 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -133,6 +133,8 @@ public: else if (const TemplateArgumentLoc *TALoc = DynNode.get()) traverse(*TALoc); + else if (const Attr *A = DynNode.get()) + traverse(*A); // FIXME: Add other base types after adding tests. // It's OK to always overwrite the bound nodes, as if there was @@ -263,6 +265,15 @@ public: return match(*Node->getLHS()) && match(*Node->getRHS()); } + bool TraverseAttr(Attr *A) { + if (A == nullptr || + (A->isImplicit() && + Finder->getASTContext().getParentMapContext().getTraversalKind() == + TK_IgnoreUnlessSpelledInSource)) + return true; + ScopedIncrement ScopedDepth(&CurrentDepth); + return traverse(*A); + } bool TraverseLambdaExpr(LambdaExpr *Node) { if (!Finder->isTraversalIgnoringImplicitNodes()) return VisitorBase::TraverseLambdaExpr(Node); @@ -345,6 +356,9 @@ private: bool baseTraverse(TemplateArgumentLoc TAL) { return VisitorBase::TraverseTemplateArgumentLoc(TAL); } + bool baseTraverse(const Attr &AttrNode) { + return VisitorBase::TraverseAttr(const_cast(&AttrNode)); + } // Sets 'Matched' to true if 'Matcher' matches 'Node' and: // 0 < CurrentDepth <= MaxDepth. @@ -489,6 +503,7 @@ public: bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit); bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL); + bool TraverseAttr(Attr *AttrNode); bool dataTraverseNode(Stmt *S, DataRecursionQueue *Queue) { if (auto *RF = dyn_cast(S)) { @@ -694,6 +709,8 @@ public: match(*N); } else if (auto *N = Node.get()) { match(*N); + } else if (auto *N = Node.get()) { + match(*N); } } @@ -894,6 +911,9 @@ private: void matchDispatch(const TemplateArgumentLoc *Node) { matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc); } + void matchDispatch(const Attr *Node) { + matchWithoutFilter(*Node, Matchers->Attr); + } void matchDispatch(const void *) { /* Do nothing. */ } /// @} @@ -1300,6 +1320,11 @@ bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) { return RecursiveASTVisitor::TraverseTemplateArgumentLoc(Loc); } +bool MatchASTVisitor::TraverseAttr(Attr *AttrNode) { + match(*AttrNode); + return RecursiveASTVisitor::TraverseAttr(AttrNode); +} + class MatchASTConsumer : public ASTConsumer { public: MatchASTConsumer(MatchFinder *Finder, @@ -1394,6 +1419,12 @@ void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch, Matchers.AllCallbacks.insert(Action); } +void MatchFinder::addMatcher(const AttrMatcher &AttrMatch, + MatchCallback *Action) { + Matchers.Attr.emplace_back(AttrMatch, Action); + Matchers.AllCallbacks.insert(Action); +} + bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, MatchCallback *Action) { if (NodeMatch.canConvertTo()) { @@ -1420,6 +1451,9 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, } else if (NodeMatch.canConvertTo()) { addMatcher(NodeMatch.convertTo(), Action); return true; + } else if (NodeMatch.canConvertTo()) { + addMatcher(NodeMatch.convertTo(), Action); + return true; } return false; } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 169ce3b8398..7680eb38283 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -468,8 +468,8 @@ hasAnyOverloadedOperatorNameFunc(ArrayRef NameRefs) { } HasNameMatcher::HasNameMatcher(std::vector N) - : UseUnqualifiedMatch(llvm::all_of( - N, [](StringRef Name) { return Name.find("::") == Name.npos; })), + : UseUnqualifiedMatch( + llvm::all_of(N, [](StringRef Name) { return !Name.contains("::"); })), Names(std::move(N)) { #ifndef NDEBUG for (StringRef Name : Names) @@ -768,9 +768,23 @@ const internal::VariadicDynCastAllOfMatcher const internal::VariadicDynCastAllOfMatcher templateTemplateParmDecl; +const internal::VariadicAllOfMatcher lambdaCapture; const internal::VariadicAllOfMatcher qualType; const internal::VariadicAllOfMatcher type; const internal::VariadicAllOfMatcher typeLoc; + +const internal::VariadicDynCastAllOfMatcher + qualifiedTypeLoc; +const internal::VariadicDynCastAllOfMatcher + pointerTypeLoc; +const internal::VariadicDynCastAllOfMatcher + referenceTypeLoc; +const internal::VariadicDynCastAllOfMatcher + templateSpecializationTypeLoc; +const internal::VariadicDynCastAllOfMatcher + elaboratedTypeLoc; + const internal::VariadicDynCastAllOfMatcher unaryExprOrTypeTraitExpr; const internal::VariadicDynCastAllOfMatcher valueDecl; @@ -1000,19 +1014,20 @@ const internal::ArgumentAdaptingMatcherFunc forEachDescendant = {}; const internal::ArgumentAdaptingMatcherFunc< internal::HasParentMatcher, - internal::TypeList, - internal::TypeList> + internal::TypeList, + internal::TypeList> hasParent = {}; const internal::ArgumentAdaptingMatcherFunc< internal::HasAncestorMatcher, - internal::TypeList, - internal::TypeList> + internal::TypeList, + internal::TypeList> hasAncestor = {}; const internal::VariadicOperatorMatcherFunc<1, 1> unless = { internal::DynTypedMatcher::VO_UnaryNot}; const internal::VariadicAllOfMatcher nestedNameSpecifier; const internal::VariadicAllOfMatcher nestedNameSpecifierLoc; +const internal::VariadicAllOfMatcher attr; const internal::VariadicDynCastAllOfMatcher cudaKernelCallExpr; const AstTypeMatcher builtinType; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 0048f1133ca..878547923d2 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -106,7 +106,6 @@ RegistryMaps::RegistryMaps() { std::make_unique()); REGISTER_OVERLOADED_2(callee); - REGISTER_OVERLOADED_2(hasAnyCapture); REGISTER_OVERLOADED_2(hasPrefix); REGISTER_OVERLOADED_2(hasType); REGISTER_OVERLOADED_2(ignoringParens); @@ -142,6 +141,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(asmStmt); REGISTER_MATCHER(atomicExpr); REGISTER_MATCHER(atomicType); + REGISTER_MATCHER(attr); REGISTER_MATCHER(autoType); REGISTER_MATCHER(autoreleasePoolStmt) REGISTER_MATCHER(binaryConditionalOperator); @@ -156,6 +156,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(builtinType); REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(capturesThis); + REGISTER_MATCHER(capturesVar); REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); REGISTER_MATCHER(characterLiteral); @@ -225,6 +227,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(doStmt); REGISTER_MATCHER(eachOf); REGISTER_MATCHER(elaboratedType); + REGISTER_MATCHER(elaboratedTypeLoc); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(enumType); @@ -243,6 +246,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forEachArgumentWithParamType); REGISTER_MATCHER(forEachConstructorInitializer); REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachLambdaCapture); REGISTER_MATCHER(forEachOverridden); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); @@ -262,6 +266,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnyBase); REGISTER_MATCHER(hasAnyBinding); REGISTER_MATCHER(hasAnyBody); + REGISTER_MATCHER(hasAnyCapture); REGISTER_MATCHER(hasAnyClause); REGISTER_MATCHER(hasAnyConstructorInitializer); REGISTER_MATCHER(hasAnyDeclaration); @@ -273,6 +278,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnySelector); REGISTER_MATCHER(hasAnySubstatement); REGISTER_MATCHER(hasAnyTemplateArgument); + REGISTER_MATCHER(hasAnyTemplateArgumentLoc); REGISTER_MATCHER(hasAnyUsingShadowDecl); REGISTER_MATCHER(hasArgument); REGISTER_MATCHER(hasArgumentOfType); @@ -321,6 +327,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasMemberName); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasNamedTypeLoc); REGISTER_MATCHER(hasNullSelector); REGISTER_MATCHER(hasObjectExpression); REGISTER_MATCHER(hasOperands); @@ -328,12 +335,15 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasPointeeLoc); REGISTER_MATCHER(hasQualifier); REGISTER_MATCHER(hasRHS); REGISTER_MATCHER(hasRangeInit); REGISTER_MATCHER(hasReceiver); REGISTER_MATCHER(hasReceiverType); + REGISTER_MATCHER(hasReferentLoc); REGISTER_MATCHER(hasReplacementType); + REGISTER_MATCHER(hasReturnTypeLoc); REGISTER_MATCHER(hasReturnValue); REGISTER_MATCHER(hasPlacementArg); REGISTER_MATCHER(hasSelector); @@ -347,6 +357,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasSyntacticForm); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasTemplateArgumentLoc); REGISTER_MATCHER(hasThen); REGISTER_MATCHER(hasThreadStorageDuration); REGISTER_MATCHER(hasTrailingReturn); @@ -357,6 +368,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasUnderlyingDecl); REGISTER_MATCHER(hasUnderlyingType); REGISTER_MATCHER(hasUnqualifiedDesugaredType); + REGISTER_MATCHER(hasUnqualifiedLoc); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); REGISTER_MATCHER(ignoringElidableConstructorCall); @@ -413,6 +425,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isInStdNamespace); REGISTER_MATCHER(isInTemplateInstantiation); + REGISTER_MATCHER(isInitCapture); REGISTER_MATCHER(isInline); REGISTER_MATCHER(isInstanceMessage); REGISTER_MATCHER(isInstanceMethod); @@ -456,6 +469,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(labelDecl); REGISTER_MATCHER(labelStmt); + REGISTER_MATCHER(lambdaCapture); REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(linkageSpecDecl); REGISTER_MATCHER(materializeTemporaryExpr); @@ -503,13 +517,16 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(parmVarDecl); REGISTER_MATCHER(pointee); REGISTER_MATCHER(pointerType); + REGISTER_MATCHER(pointerTypeLoc); REGISTER_MATCHER(predefinedExpr); REGISTER_MATCHER(qualType); + REGISTER_MATCHER(qualifiedTypeLoc); REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(realFloatingPointType); REGISTER_MATCHER(recordDecl); REGISTER_MATCHER(recordType); REGISTER_MATCHER(referenceType); + REGISTER_MATCHER(referenceTypeLoc); REGISTER_MATCHER(refersToDeclaration); REGISTER_MATCHER(refersToIntegralType); REGISTER_MATCHER(refersToTemplate); @@ -537,6 +554,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(templateArgumentLoc); REGISTER_MATCHER(templateName); REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(templateSpecializationTypeLoc); REGISTER_MATCHER(templateTemplateParmDecl); REGISTER_MATCHER(templateTypeParmDecl); REGISTER_MATCHER(templateTypeParmType); diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index e357bfb29b8..49ac74c233b 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -461,8 +461,7 @@ static Stmt *create_call_once(ASTContext &C, const FunctionDecl *D) { DerefType); auto *Out = - IfStmt::Create(C, SourceLocation(), - /* IsConstexpr=*/false, + IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, /* Init=*/nullptr, /* Var=*/nullptr, /* Cond=*/FlagCheck, @@ -547,8 +546,7 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { Expr *GuardCondition = M.makeComparison(LValToRval, DoneValue, BO_NE); // (5) Create the 'if' statement. - auto *If = IfStmt::Create(C, SourceLocation(), - /* IsConstexpr=*/false, + auto *If = IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, /* Init=*/nullptr, /* Var=*/nullptr, /* Cond=*/GuardCondition, @@ -658,8 +656,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) /// Construct the If. auto *If = - IfStmt::Create(C, SourceLocation(), - /* IsConstexpr=*/false, + IfStmt::Create(C, SourceLocation(), IfStatementKind::Ordinary, /* Init=*/nullptr, /* Var=*/nullptr, Comparison, /* LPL=*/SourceLocation(), diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index ba5eceda24b..abf65e3efce 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -482,8 +482,10 @@ class CFGBuilder { CFGBlock *SwitchTerminatedBlock = nullptr; CFGBlock *DefaultCaseBlock = nullptr; - // This can point either to a try or a __try block. The frontend forbids - // mixing both kinds in one function, so having one for both is enough. + // This can point to either a C++ try, an Objective-C @try, or an SEH __try. + // try and @try can be mixed and generally work the same. + // The frontend forbids mixing SEH __try with either try or @try. + // So having one for all three is enough. CFGBlock *TryTerminatedBlock = nullptr; // Current position in local scope. @@ -542,6 +544,7 @@ private: // Visitors to walk an AST and construct the CFG. CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc); CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); + CFGBlock *VisitAttributedStmt(AttributedStmt *A, AddStmtChoice asc); CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); CFGBlock *VisitCallExpr(CallExpr *C, AddStmtChoice asc); @@ -1798,16 +1801,11 @@ void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B, autoCreateBlock(); // object with trivial destructor end their lifetime last (when storage // duration ends) - for (SmallVectorImpl::reverse_iterator I = DeclsTrivial.rbegin(), - E = DeclsTrivial.rend(); - I != E; ++I) - appendLifetimeEnds(Block, *I, S); + for (VarDecl *VD : llvm::reverse(DeclsTrivial)) + appendLifetimeEnds(Block, VD, S); - for (SmallVectorImpl::reverse_iterator - I = DeclsNonTrivial.rbegin(), - E = DeclsNonTrivial.rend(); - I != E; ++I) - appendLifetimeEnds(Block, *I, S); + for (VarDecl *VD : llvm::reverse(DeclsNonTrivial)) + appendLifetimeEnds(Block, VD, S); } /// Add to current block markers for ending scopes. @@ -1820,9 +1818,8 @@ void CFGBuilder::addScopesEnd(LocalScope::const_iterator B, autoCreateBlock(); - for (auto I = DeclsWithEndedScope.rbegin(), E = DeclsWithEndedScope.rend(); - I != E; ++I) - appendScopeEnd(Block, *I, S); + for (VarDecl *VD : llvm::reverse(DeclsWithEndedScope)) + appendScopeEnd(Block, VD, S); return; } @@ -1847,24 +1844,22 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, for (LocalScope::const_iterator I = B; I != E; ++I) Decls.push_back(*I); - for (SmallVectorImpl::reverse_iterator I = Decls.rbegin(), - E = Decls.rend(); - I != E; ++I) { - if (hasTrivialDestructor(*I)) { + for (VarDecl *VD : llvm::reverse(Decls)) { + if (hasTrivialDestructor(VD)) { // If AddScopes is enabled and *I is a first variable in a scope, add a // ScopeEnd marker in a Block. - if (BuildOpts.AddScopes && DeclsWithEndedScope.count(*I)) { + if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD)) { autoCreateBlock(); - appendScopeEnd(Block, *I, S); + appendScopeEnd(Block, VD, S); } continue; } // If this destructor is marked as a no-return destructor, we need to // create a new block for the destructor which does not have as a successor // anything built thus far: control won't flow out of this block. - QualType Ty = (*I)->getType(); + QualType Ty = VD->getType(); if (Ty->isReferenceType()) { - Ty = getReferenceInitTemporaryType((*I)->getInit()); + Ty = getReferenceInitTemporaryType(VD->getInit()); } Ty = Context->getBaseElementType(Ty); @@ -1874,9 +1869,9 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, autoCreateBlock(); // Add ScopeEnd just after automatic obj destructor. - if (BuildOpts.AddScopes && DeclsWithEndedScope.count(*I)) - appendScopeEnd(Block, *I, S); - appendAutomaticObjDtor(Block, *I, S); + if (BuildOpts.AddScopes && DeclsWithEndedScope.count(VD)) + appendScopeEnd(Block, VD, S); + appendAutomaticObjDtor(Block, VD, S); } } @@ -2149,6 +2144,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc, case Stmt::InitListExprClass: return VisitInitListExpr(cast(S), asc); + case Stmt::AttributedStmtClass: + return VisitAttributedStmt(cast(S), asc); + case Stmt::AddrLabelExprClass: return VisitAddrLabelExpr(cast(S), asc); @@ -2282,7 +2280,7 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc, return VisitObjCAtCatchStmt(cast(S)); case Stmt::ObjCAutoreleasePoolStmtClass: - return VisitObjCAutoreleasePoolStmt(cast(S)); + return VisitObjCAutoreleasePoolStmt(cast(S)); case Stmt::ObjCAtSynchronizedStmtClass: return VisitObjCAtSynchronizedStmt(cast(S)); @@ -2398,8 +2396,32 @@ CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, return Block; } -CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, - AddStmtChoice asc) { +static bool isFallthroughStatement(const AttributedStmt *A) { + bool isFallthrough = hasSpecificAttr(A->getAttrs()); + assert((!isFallthrough || isa(A->getSubStmt())) && + "expected fallthrough not to have children"); + return isFallthrough; +} + +CFGBlock *CFGBuilder::VisitAttributedStmt(AttributedStmt *A, + AddStmtChoice asc) { + // AttributedStmts for [[likely]] can have arbitrary statements as children, + // and the current visitation order here would add the AttributedStmts + // for [[likely]] after the child nodes, which is undesirable: For example, + // if the child contains an unconditional return, the [[likely]] would be + // considered unreachable. + // So only add the AttributedStmt for FallThrough, which has CFG effects and + // also no children, and omit the others. None of the other current StmtAttrs + // have semantic meaning for the CFG. + if (isFallthroughStatement(A) && asc.alwaysAdd(*this, A)) { + autoCreateBlock(); + appendStmt(Block, A); + } + + return VisitChildren(A); +} + +CFGBlock *CFGBuilder::VisitUnaryOperator(UnaryOperator *U, AddStmtChoice asc) { if (asc.alwaysAdd(*this, U)) { autoCreateBlock(); appendStmt(Block, U); @@ -2711,7 +2733,8 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, return addStmt(C->getCond()); } -CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C, bool ExternallyDestructed) { +CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C, + bool ExternallyDestructed) { LocalScope::const_iterator scopeBeginPos = ScopePos; addLocalScopeForStmt(C); @@ -2723,11 +2746,10 @@ CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C, bool ExternallyDestruct CFGBlock *LastBlock = Block; - for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); - I != E; ++I ) { + for (Stmt *S : llvm::reverse(C->body())) { // If we hit a segment of code just containing ';' (NullStmts), we can // get a null block back. In such cases, just use the LastBlock - CFGBlock *newBlock = Visit(*I, AddStmtChoice::AlwaysAdd, + CFGBlock *newBlock = Visit(S, AddStmtChoice::AlwaysAdd, ExternallyDestructed); if (newBlock) @@ -3047,7 +3069,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { // control-flow transfer of '&&' or '||' go directly into the then/else // blocks directly. BinaryOperator *Cond = - I->getConditionVariable() + (I->isConsteval() || I->getConditionVariable()) ? nullptr : dyn_cast(I->getCond()->IgnoreParens()); CFGBlock *LastBlock; @@ -3061,7 +3083,9 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { Block->setTerminator(I); // See if this is a known constant. - const TryResult &KnownVal = tryEvaluateBool(I->getCond()); + TryResult KnownVal; + if (!I->isConsteval()) + KnownVal = tryEvaluateBool(I->getCond()); // Add the successors. If we know that specific branches are // unreachable, inform addSuccessor() of that knowledge. @@ -3122,9 +3146,9 @@ CFGBlock *CFGBuilder::VisitReturnStmt(Stmt *S) { if (Expr *O = RS->getRetValue()) return Visit(O, AddStmtChoice::AlwaysAdd, /*ExternallyDestructed=*/true); return Block; - } else { // co_return - return VisitChildren(S); } + // co_return + return VisitChildren(S); } CFGBlock *CFGBuilder::VisitSEHExceptStmt(SEHExceptStmt *ES) { @@ -3223,8 +3247,7 @@ CFGBlock *CFGBuilder::VisitSEHTryStmt(SEHTryStmt *Terminator) { Succ = SEHTrySuccessor; // Save the current "__try" context. - SaveAndRestore save_try(TryTerminatedBlock, - NewTryTerminatedBlock); + SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock); cfg->addTryDispatchBlock(TryTerminatedBlock); // Save the current value for the __leave target. @@ -3258,7 +3281,7 @@ CFGBlock *CFGBuilder::VisitLabelStmt(LabelStmt *L) { if (badCFG) return nullptr; - // We set Block to NULL to allow lazy creation of a new block (if necessary); + // We set Block to NULL to allow lazy creation of a new block (if necessary). Block = nullptr; // This block is now the implicit successor of other blocks. @@ -3670,11 +3693,6 @@ CFGBlock *CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { return addStmt(S->getSynchExpr()); } -CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { - // FIXME - return NYS(); -} - CFGBlock *CFGBuilder::VisitPseudoObjectExpr(PseudoObjectExpr *E) { autoCreateBlock(); @@ -3835,16 +3853,37 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { return EntryConditionBlock; } -CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { - // FIXME: For now we pretend that @catch and the code it contains does not - // exit. - return Block; +CFGBlock *CFGBuilder::VisitObjCAtCatchStmt(ObjCAtCatchStmt *CS) { + // ObjCAtCatchStmt are treated like labels, so they are the first statement + // in a block. + + // Save local scope position because in case of exception variable ScopePos + // won't be restored when traversing AST. + SaveAndRestore save_scope_pos(ScopePos); + + if (CS->getCatchBody()) + addStmt(CS->getCatchBody()); + + CFGBlock *CatchBlock = Block; + if (!CatchBlock) + CatchBlock = createBlock(); + + appendStmt(CatchBlock, CS); + + // Also add the ObjCAtCatchStmt as a label, like with regular labels. + CatchBlock->setLabel(CS); + + // Bail out if the CFG is bad. + if (badCFG) + return nullptr; + + // We set Block to NULL to allow lazy creation of a new block (if necessary). + Block = nullptr; + + return CatchBlock; } CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { - // FIXME: This isn't complete. We basically treat @throw like a return - // statement. - // If we were in the middle of a block we stop processing that block. if (badCFG) return nullptr; @@ -3852,14 +3891,77 @@ CFGBlock *CFGBuilder::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { // Create the new block. Block = createBlock(false); - // The Exit block is the only successor. - addSuccessor(Block, &cfg->getExit()); + if (TryTerminatedBlock) + // The current try statement is the only successor. + addSuccessor(Block, TryTerminatedBlock); + else + // otherwise the Exit block is the only successor. + addSuccessor(Block, &cfg->getExit()); // Add the statement to the block. This may create new blocks if S contains // control-flow (short-circuit operations). return VisitStmt(S, AddStmtChoice::AlwaysAdd); } +CFGBlock *CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt *Terminator) { + // "@try"/"@catch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock *TrySuccessor = nullptr; + + if (Block) { + if (badCFG) + return nullptr; + TrySuccessor = Block; + } else + TrySuccessor = Succ; + + // FIXME: Implement @finally support. + if (Terminator->getFinallyStmt()) + return NYS(); + + CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock; + + // Create a new block that will contain the try statement. + CFGBlock *NewTryTerminatedBlock = createBlock(false); + // Add the terminator in the try block. + NewTryTerminatedBlock->setTerminator(Terminator); + + bool HasCatchAll = false; + for (ObjCAtCatchStmt *CS : Terminator->catch_stmts()) { + // The code after the try is the implicit successor. + Succ = TrySuccessor; + if (CS->hasEllipsis()) { + HasCatchAll = true; + } + Block = nullptr; + CFGBlock *CatchBlock = VisitObjCAtCatchStmt(CS); + if (!CatchBlock) + return nullptr; + // Add this block to the list of successors for the block with the try + // statement. + addSuccessor(NewTryTerminatedBlock, CatchBlock); + } + + // FIXME: This needs updating when @finally support is added. + if (!HasCatchAll) { + if (PrevTryTerminatedBlock) + addSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock); + else + addSuccessor(NewTryTerminatedBlock, &cfg->getExit()); + } + + // The code after the try is the implicit successor. + Succ = TrySuccessor; + + // Save the current "try" context. + SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock); + cfg->addTryDispatchBlock(TryTerminatedBlock); + + assert(Terminator->getTryBody() && "try must contain a non-NULL body"); + Block = nullptr; + return addStmt(Terminator->getTryBody()); +} + CFGBlock *CFGBuilder::VisitObjCMessageExpr(ObjCMessageExpr *ME, AddStmtChoice asc) { findConstructionContextsForArguments(ME); @@ -4244,7 +4346,7 @@ CFGBlock *CFGBuilder::VisitCaseStmt(CaseStmt *CS) { shouldAddCase(switchExclusivelyCovered, switchCond, CS, *Context)); - // We set Block to NULL to allow lazy creation of a new block (if necessary) + // We set Block to NULL to allow lazy creation of a new block (if necessary). Block = nullptr; if (TopBlock) { @@ -4280,7 +4382,7 @@ CFGBlock *CFGBuilder::VisitDefaultStmt(DefaultStmt *Terminator) { // (including a fall-through to the code after the switch statement) to always // be the last successor of a switch-terminated block. - // We set Block to NULL to allow lazy creation of a new block (if necessary) + // We set Block to NULL to allow lazy creation of a new block (if necessary). Block = nullptr; // This block is now the implicit successor of other blocks. @@ -4298,7 +4400,8 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { if (badCFG) return nullptr; TrySuccessor = Block; - } else TrySuccessor = Succ; + } else + TrySuccessor = Succ; CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock; @@ -4308,10 +4411,10 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { NewTryTerminatedBlock->setTerminator(Terminator); bool HasCatchAll = false; - for (unsigned h = 0; h getNumHandlers(); ++h) { + for (unsigned I = 0, E = Terminator->getNumHandlers(); I != E; ++I) { // The code after the try is the implicit successor. Succ = TrySuccessor; - CXXCatchStmt *CS = Terminator->getHandler(h); + CXXCatchStmt *CS = Terminator->getHandler(I); if (CS->getExceptionDecl() == nullptr) { HasCatchAll = true; } @@ -4334,7 +4437,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { Succ = TrySuccessor; // Save the current "try" context. - SaveAndRestore save_try(TryTerminatedBlock, NewTryTerminatedBlock); + SaveAndRestore SaveTry(TryTerminatedBlock, NewTryTerminatedBlock); cfg->addTryDispatchBlock(TryTerminatedBlock); assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); @@ -4379,7 +4482,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { if (badCFG) return nullptr; - // We set Block to NULL to allow lazy creation of a new block (if necessary) + // We set Block to NULL to allow lazy creation of a new block (if necessary). Block = nullptr; return CatchBlock; @@ -5287,13 +5390,11 @@ public: Terminator->getCond()->printPretty(OS, Helper, Policy); } - void VisitCXXTryStmt(CXXTryStmt *CS) { - OS << "try ..."; - } + void VisitCXXTryStmt(CXXTryStmt *) { OS << "try ..."; } - void VisitSEHTryStmt(SEHTryStmt *CS) { - OS << "__try ..."; - } + void VisitObjCAtTryStmt(ObjCAtTryStmt *) { OS << "@try ..."; } + + void VisitSEHTryStmt(SEHTryStmt *CS) { OS << "__try ..."; } void VisitAbstractConditionalOperator(AbstractConditionalOperator* C) { if (Stmt *Cond = C->getCond()) @@ -5609,7 +5710,8 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, } case CFGElement::Kind::TemporaryDtor: { - const CXXBindTemporaryExpr *BT = E.castAs().getBindTemporaryExpr(); + const CXXBindTemporaryExpr *BT = + E.castAs().getBindTemporaryExpr(); OS << "~"; BT->getType().print(OS, PrintingPolicy(Helper.getLangOpts())); OS << "() (Temporary object destructor)\n"; @@ -5653,21 +5755,25 @@ static void print_block(raw_ostream &OS, const CFG* cfg, OS << L->getName(); else if (CaseStmt *C = dyn_cast(Label)) { OS << "case "; - if (C->getLHS()) - C->getLHS()->printPretty(OS, &Helper, - PrintingPolicy(Helper.getLangOpts())); - if (C->getRHS()) { + if (const Expr *LHS = C->getLHS()) + LHS->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts())); + if (const Expr *RHS = C->getRHS()) { OS << " ... "; - C->getRHS()->printPretty(OS, &Helper, - PrintingPolicy(Helper.getLangOpts())); + RHS->printPretty(OS, &Helper, PrintingPolicy(Helper.getLangOpts())); } } else if (isa(Label)) OS << "default"; else if (CXXCatchStmt *CS = dyn_cast(Label)) { OS << "catch ("; - if (CS->getExceptionDecl()) - CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper.getLangOpts()), - 0); + if (const VarDecl *ED = CS->getExceptionDecl()) + ED->print(OS, PrintingPolicy(Helper.getLangOpts()), 0); + else + OS << "..."; + OS << ")"; + } else if (ObjCAtCatchStmt *CS = dyn_cast(Label)) { + OS << "@catch ("; + if (const VarDecl *PD = CS->getCatchParamDecl()) + PD->print(OS, PrintingPolicy(Helper.getLangOpts()), 0); else OS << "..."; OS << ")"; @@ -5882,7 +5988,7 @@ static bool isImmediateSinkBlock(const CFGBlock *Blk) { // at least for now, but once we have better support for exceptions, // we'd need to carefully handle the case when the throw is being // immediately caught. - if (std::any_of(Blk->begin(), Blk->end(), [](const CFGElement &Elm) { + if (llvm::any_of(*Blk, [](const CFGElement &Elm) { if (Optional StmtElm = Elm.getAs()) if (isa(StmtElm->getStmt())) return true; diff --git a/clang/lib/Analysis/CloneDetection.cpp b/clang/lib/Analysis/CloneDetection.cpp index 0a1122bd5a4..65ac4ad6a5e 100644 --- a/clang/lib/Analysis/CloneDetection.cpp +++ b/clang/lib/Analysis/CloneDetection.cpp @@ -147,9 +147,8 @@ void OnlyLargestCloneConstraint::constrain( // Erasing a list of indexes from the vector should be done with decreasing // indexes. As IndexesToRemove is constructed with increasing values, we just // reverse iterate over it to get the desired order. - for (auto I = IndexesToRemove.rbegin(); I != IndexesToRemove.rend(); ++I) { - Result.erase(Result.begin() + *I); - } + for (unsigned I : llvm::reverse(IndexesToRemove)) + Result.erase(Result.begin() + I); } bool FilenamePatternConstraint::isAutoGenerated( diff --git a/clang/lib/Analysis/ObjCNoReturn.cpp b/clang/lib/Analysis/ObjCNoReturn.cpp index fe1edb49685..9d7c365c3b9 100644 --- a/clang/lib/Analysis/ObjCNoReturn.cpp +++ b/clang/lib/Analysis/ObjCNoReturn.cpp @@ -54,12 +54,9 @@ bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) { } if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) { - if (isSubclass(ID, NSExceptionII)) { - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { - if (S == NSExceptionInstanceRaiseSelectors[i]) - return true; - } - } + if (isSubclass(ID, NSExceptionII) && + llvm::is_contained(NSExceptionInstanceRaiseSelectors, S)) + return true; } return false; diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 221d137dadb..5be8180113d 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -87,10 +87,8 @@ static bool isDeadReturn(const CFGBlock *B, const Stmt *S) { // block, or may be in a subsequent block because of destructors. const CFGBlock *Current = B; while (true) { - for (CFGBlock::const_reverse_iterator I = Current->rbegin(), - E = Current->rend(); - I != E; ++I) { - if (Optional CS = I->getAs()) { + for (const CFGElement &CE : llvm::reverse(*Current)) { + if (Optional CS = CE.getAs()) { if (const ReturnStmt *RS = dyn_cast(CS->getStmt())) { if (RS == S) return true; @@ -227,7 +225,8 @@ static bool isConfigurationValue(const Stmt *S, if (IncludeIntegers) { if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid()) *SilenceableCondVal = E->getSourceRange(); - return WrappedInParens || isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO); + return WrappedInParens || + isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO); } return false; } @@ -530,12 +529,11 @@ unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, // earliest location. if (!DeferredLocs.empty()) { llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp); - for (DeferredLocsTy::iterator I = DeferredLocs.begin(), - E = DeferredLocs.end(); I != E; ++I) { - const CFGBlock *Block = I->first; + for (const auto &I : DeferredLocs) { + const CFGBlock *Block = I.first; if (Reachable[Block->getBlockID()]) continue; - reportDeadCode(Block, I->second, CB); + reportDeadCode(Block, I.second, CB); count += scanMaybeReachableFromBlock(Block, PP, Reachable); } } @@ -694,18 +692,15 @@ void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, // If there aren't explicit EH edges, we should include the 'try' dispatch // blocks as roots. if (!AC.getCFGBuildOptions().AddEHEdges) { - for (CFG::try_block_iterator I = cfg->try_blocks_begin(), - E = cfg->try_blocks_end() ; I != E; ++I) { - numReachable += scanMaybeReachableFromBlock(*I, PP, reachable); - } + for (const CFGBlock *B : cfg->try_blocks()) + numReachable += scanMaybeReachableFromBlock(B, PP, reachable); if (numReachable == cfg->getNumBlockIDs()) return; } // There are some unreachable blocks. We need to find the root blocks that // contain code that should be considered unreachable. - for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) { - const CFGBlock *block = *I; + for (const CFGBlock *block : *cfg) { // A block may have been marked reachable during this loop. if (reachable[block->getBlockID()]) continue; diff --git a/clang/lib/Analysis/RetainSummaryManager.cpp b/clang/lib/Analysis/RetainSummaryManager.cpp index 7ed1e40333f..1d7b968e994 100644 --- a/clang/lib/Analysis/RetainSummaryManager.cpp +++ b/clang/lib/Analysis/RetainSummaryManager.cpp @@ -397,8 +397,7 @@ const RetainSummary *RetainSummaryManager::getSummaryForObjCOrCFObject( ArgEffect(DoNothing), ArgEffect(DoNothing)); } else if (FName.startswith("NSLog")) { return getDoNothingSummary(); - } else if (FName.startswith("NS") && - (FName.find("Insert") != StringRef::npos)) { + } else if (FName.startswith("NS") && FName.contains("Insert")) { // Whitelist NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. (radar://11152419) ScratchArgs = AF.add(ScratchArgs, 1, ArgEffect(StopTracking)); diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 5b2c882c423..b196ffa73cb 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -86,11 +86,9 @@ class CapExprSet : public SmallVector { public: /// Push M onto list, but discard duplicates. void push_back_nodup(const CapabilityExpr &CapE) { - iterator It = std::find_if(begin(), end(), - [=](const CapabilityExpr &CapE2) { - return CapE.equals(CapE2); - }); - if (It == end()) + if (llvm::none_of(*this, [=](const CapabilityExpr &CapE2) { + return CapE.equals(CapE2); + })) push_back(CapE); } }; @@ -849,6 +847,11 @@ static void findBlockLocations(CFG *CFGraph, // location. CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = BlockInfo[(*CurrBlock->pred_begin())->getBlockID()].ExitLoc; + } else if (CurrBlock->succ_size() == 1 && *CurrBlock->succ_begin()) { + // The block is empty, and has a single successor. Use its entry + // location. + CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = + BlockInfo[(*CurrBlock->succ_begin())->getBlockID()].EntryLoc; } } } @@ -1050,7 +1053,7 @@ public: const CFGBlock* PredBlock, const CFGBlock *CurrBlock); - bool join(const FactEntry &a, const FactEntry &b); + bool join(const FactEntry &a, const FactEntry &b, bool CanModify); void intersectAndWarn(FactSet &EntrySet, const FactSet &ExitSet, SourceLocation JoinLoc, LockErrorKind EntryLEK, @@ -2188,25 +2191,28 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) { } } -/// Given two facts merging on a join point, decide whether to warn and which -/// one to keep. +/// Given two facts merging on a join point, possibly warn and decide whether to +/// keep or replace. /// -/// \return false if we should keep \p A, true if we should keep \p B. -bool ThreadSafetyAnalyzer::join(const FactEntry &A, const FactEntry &B) { +/// \param CanModify Whether we can replace \p A by \p B. +/// \return false if we should keep \p A, true if we should take \p B. +bool ThreadSafetyAnalyzer::join(const FactEntry &A, const FactEntry &B, + bool CanModify) { if (A.kind() != B.kind()) { // For managed capabilities, the destructor should unlock in the right mode // anyway. For asserted capabilities no unlocking is needed. if ((A.managed() || A.asserted()) && (B.managed() || B.asserted())) { - // The shared capability subsumes the exclusive capability. - return B.kind() == LK_Shared; - } else { - Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc()); - // Take the exclusive capability to reduce further warnings. - return B.kind() == LK_Exclusive; + // The shared capability subsumes the exclusive capability, if possible. + bool ShouldTakeB = B.kind() == LK_Shared; + if (CanModify || !ShouldTakeB) + return ShouldTakeB; } + Handler.handleExclusiveAndShared("mutex", B.toString(), B.loc(), A.loc()); + // Take the exclusive capability to reduce further warnings. + return CanModify && B.kind() == LK_Exclusive; } else { // The non-asserted capability is the one we want to track. - return A.asserted() && !B.asserted(); + return CanModify && A.asserted() && !B.asserted(); } } @@ -2237,8 +2243,8 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &EntrySet, FactSet::iterator EntryIt = EntrySet.findLockIter(FactMan, ExitFact); if (EntryIt != EntrySet.end()) { - if (join(FactMan[*EntryIt], ExitFact) && - EntryLEK == LEK_LockedSomePredecessors) + if (join(FactMan[*EntryIt], ExitFact, + EntryLEK != LEK_LockedSomeLoopIterations)) *EntryIt = Fact; } else if (!ExitFact.managed()) { ExitFact.handleRemovalFromIntersection(ExitSet, FactMan, JoinLoc, @@ -2412,7 +2418,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // union because the real error is probably that we forgot to unlock M on // all code paths. bool LocksetInitialized = false; - SmallVector SpecialBlocks; for (CFGBlock::const_pred_iterator PI = CurrBlock->pred_begin(), PE = CurrBlock->pred_end(); PI != PE; ++PI) { // if *PI -> CurrBlock is a back edge @@ -2429,17 +2434,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { // Okay, we can reach this block from the entry. CurrBlockInfo->Reachable = true; - // If the previous block ended in a 'continue' or 'break' statement, then - // a difference in locksets is probably due to a bug in that block, rather - // than in some other predecessor. In that case, keep the other - // predecessor's lockset. - if (const Stmt *Terminator = (*PI)->getTerminatorStmt()) { - if (isa(Terminator) || isa(Terminator)) { - SpecialBlocks.push_back(*PI); - continue; - } - } - FactSet PrevLockset; getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock); @@ -2447,9 +2441,14 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { CurrBlockInfo->EntrySet = PrevLockset; LocksetInitialized = true; } else { - intersectAndWarn(CurrBlockInfo->EntrySet, PrevLockset, - CurrBlockInfo->EntryLoc, - LEK_LockedSomePredecessors); + // Surprisingly 'continue' doesn't always produce back edges, because + // the CFG has empty "transition" blocks where they meet with the end + // of the regular loop body. We still want to diagnose them as loop. + intersectAndWarn( + CurrBlockInfo->EntrySet, PrevLockset, CurrBlockInfo->EntryLoc, + isa_and_nonnull((*PI)->getTerminatorStmt()) + ? LEK_LockedSomeLoopIterations + : LEK_LockedSomePredecessors); } } @@ -2457,35 +2456,6 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (!CurrBlockInfo->Reachable) continue; - // Process continue and break blocks. Assume that the lockset for the - // resulting block is unaffected by any discrepancies in them. - for (const auto *PrevBlock : SpecialBlocks) { - unsigned PrevBlockID = PrevBlock->getBlockID(); - CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; - - if (!LocksetInitialized) { - CurrBlockInfo->EntrySet = PrevBlockInfo->ExitSet; - LocksetInitialized = true; - } else { - // Determine whether this edge is a loop terminator for diagnostic - // purposes. FIXME: A 'break' statement might be a loop terminator, but - // it might also be part of a switch. Also, a subsequent destructor - // might add to the lockset, in which case the real issue might be a - // double lock on the other path. - const Stmt *Terminator = PrevBlock->getTerminatorStmt(); - bool IsLoop = Terminator && isa(Terminator); - - FactSet PrevLockset; - getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, - PrevBlock, CurrBlock); - - // Do not update EntrySet. - intersectAndWarn( - CurrBlockInfo->EntrySet, PrevLockset, PrevBlockInfo->ExitLoc, - IsLoop ? LEK_LockedSomeLoopIterations : LEK_LockedSomePredecessors); - } - } - BuildLockset LocksetBuilder(this, *CurrBlockInfo); // Visit all the statements in the basic block. diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index 7118aa9dc21..2b0f4071662 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -72,7 +72,7 @@ bool Builtin::Context::builtinIsSupported(const Builtin::Info &BuiltinInfo, bool OclC1Unsupported = (LangOpts.OpenCLVersion / 100) != 1 && (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES ) == OCLC1X_LANG; bool OclC2Unsupported = - (LangOpts.OpenCLVersion != 200 && !LangOpts.OpenCLCPlusPlus) && + (LangOpts.getOpenCLCompatibleVersion() != 200) && (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES) == OCLC20_LANG; bool OclCUnsupported = !LangOpts.OpenCL && (BuiltinInfo.Langs & ALL_OCLC_LANGUAGES); diff --git a/clang/lib/Basic/CLWarnings.cpp b/clang/lib/Basic/CLWarnings.cpp new file mode 100644 index 00000000000..0cf367d9f7f --- /dev/null +++ b/clang/lib/Basic/CLWarnings.cpp @@ -0,0 +1,28 @@ +//===--- CLWarnings.h - Maps some cl.exe warning ids -----------*- 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 implements the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/CLWarnings.h" +#include "clang/Basic/DiagnosticCategories.h" + +using namespace clang; + +llvm::Optional +clang::diagGroupFromCLWarningID(unsigned CLWarningID) { + switch (CLWarningID) { + case 4005: return diag::Group::MacroRedefined; + case 4018: return diag::Group::SignCompare; + case 4100: return diag::Group::UnusedParameter; + case 4910: return diag::Group::DllexportExplicitInstantiationDecl; + case 4996: return diag::Group::DeprecatedDeclarations; + } + return {}; +} diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index 766135bcb37..e82a3a705e7 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -36,6 +36,14 @@ const char *CudaVersionToString(CudaVersion V) { return "11.1"; case CudaVersion::CUDA_112: return "11.2"; + case CudaVersion::CUDA_113: + return "11.3"; + case CudaVersion::CUDA_114: + return "11.4"; + case CudaVersion::CUDA_115: + return "11.5"; + case CudaVersion::NEW: + return ""; } llvm_unreachable("invalid enum"); } @@ -54,6 +62,9 @@ CudaVersion CudaStringToVersion(const llvm::Twine &S) { .Case("11.0", CudaVersion::CUDA_110) .Case("11.1", CudaVersion::CUDA_111) .Case("11.2", CudaVersion::CUDA_112) + .Case("11.3", CudaVersion::CUDA_113) + .Case("11.4", CudaVersion::CUDA_114) + .Case("11.5", CudaVersion::CUDA_115) .Default(CudaVersion::UNKNOWN); } @@ -186,7 +197,7 @@ CudaVersion MinVersionForCudaArch(CudaArch A) { CudaVersion MaxVersionForCudaArch(CudaArch A) { // AMD GPUs do not depend on CUDA versions. if (IsAMDGpuArch(A)) - return CudaVersion::LATEST; + return CudaVersion::NEW; switch (A) { case CudaArch::UNKNOWN: @@ -194,8 +205,10 @@ CudaVersion MaxVersionForCudaArch(CudaArch A) { case CudaArch::SM_20: case CudaArch::SM_21: return CudaVersion::CUDA_80; + case CudaArch::SM_30: + return CudaVersion::CUDA_110; default: - return CudaVersion::LATEST; + return CudaVersion::NEW; } } @@ -227,6 +240,12 @@ CudaVersion ToCudaVersion(llvm::VersionTuple Version) { return CudaVersion::CUDA_111; case 112: return CudaVersion::CUDA_112; + case 113: + return CudaVersion::CUDA_113; + case 114: + return CudaVersion::CUDA_114; + case 115: + return CudaVersion::CUDA_115; default: return CudaVersion::UNKNOWN; } diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index d3b2122e9c5..9b7ad96b949 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -408,6 +408,14 @@ bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, return false; } +bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor, + diag::Group Group, + diag::Severity Map, + SourceLocation Loc) { + return setSeverityForGroup(Flavor, Diags->getWarningOptionForGroup(Group), + Map, Loc); +} + bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled) { // If we are enabling this feature, just set the diagnostic mappings to map to @@ -924,7 +932,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, } // ---- INTEGERS ---- case DiagnosticsEngine::ak_sint: { - int Val = getArgSInt(ArgNo); + int64_t Val = getArgSInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, @@ -943,7 +951,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, break; } case DiagnosticsEngine::ak_uint: { - unsigned Val = getArgUInt(ArgNo); + uint64_t Val = getArgUInt(ArgNo); if (ModifierIs(Modifier, ModifierLen, "select")) { HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr); diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index c333076d2ef..88801c683e8 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -609,17 +609,23 @@ namespace { // Second the table of options, sorted by name for fast binary lookup. static const WarningOption OptionTable[] = { -#define GET_DIAG_TABLE +#define DIAG_ENTRY(GroupName, FlagNameOffset, Members, SubGroups) \ + {FlagNameOffset, Members, SubGroups}, #include "clang/Basic/DiagnosticGroups.inc" -#undef GET_DIAG_TABLE +#undef DIAG_ENTRY }; +StringRef DiagnosticIDs::getWarningOptionForGroup(diag::Group Group) { + return OptionTable[static_cast(Group)].getName(); +} + /// getWarningOptionForDiag - Return the lowest-level warning option that /// enables the specified diagnostic. If there is no -Wfoo flag that controls /// the diagnostic, this returns null. StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { if (const StaticDiagInfoRec *Info = GetDiagInfo(DiagID)) - return OptionTable[Info->getOptionGroupIndex()].getName(); + return getWarningOptionForGroup( + static_cast(Info->getOptionGroupIndex())); return StringRef(); } diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 74cd2f295be..f4cf27848d7 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -123,16 +123,16 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { DirName != llvm::sys::path::root_path(DirName) && llvm::sys::path::is_separator(DirName.back())) DirName = DirName.substr(0, DirName.size()-1); -#ifdef _WIN32 - // Fixing a problem with "clang C:test.c" on Windows. - // Stat("C:") does not recognize "C:" as a valid directory - std::string DirNameStr; - if (DirName.size() > 1 && DirName.back() == ':' && - DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) { - DirNameStr = DirName.str() + '.'; - DirName = DirNameStr; + Optional DirNameStr; + if (is_style_windows(llvm::sys::path::Style::native)) { + // Fixing a problem with "clang C:test.c" on Windows. + // Stat("C:") does not recognize "C:" as a valid directory + if (DirName.size() > 1 && DirName.back() == ':' && + DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) { + DirNameStr = DirName.str() + '.'; + DirName = *DirNameStr; + } } -#endif ++NumDirLookups; @@ -276,6 +276,18 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { } else { // Name mismatch. We need a redirect. First grab the actual entry we want // to return. + // + // This redirection logic intentionally leaks the external name of a + // redirected file that uses 'use-external-name' in \a + // vfs::RedirectionFileSystem. This allows clang to report the external + // name to users (in diagnostics) and to tools that don't have access to + // the VFS (in debug info and dependency '.d' files). + // + // FIXME: This is pretty complicated. It's also inconsistent with how + // "real" filesystems behave and confuses parts of clang expect to see the + // name-as-accessed on the \a FileEntryRef. Maybe the returned \a + // FileEntryRef::getName() could return the accessed name unmodified, but + // make the external name available via a separate API. auto &Redirection = *SeenFileEntries .insert({Status.getName(), FileEntryRef::MapValue(UFE, DirInfo)}) diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index dc392d5352a..b6dc73d6630 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -11,6 +11,8 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" using namespace clang; @@ -45,9 +47,37 @@ bool LangOptions::isNoBuiltinFunc(StringRef FuncName) const { VersionTuple LangOptions::getOpenCLVersionTuple() const { const int Ver = OpenCLCPlusPlus ? OpenCLCPlusPlusVersion : OpenCLVersion; + if (OpenCLCPlusPlus && Ver != 100) + return VersionTuple(Ver / 100); return VersionTuple(Ver / 100, (Ver % 100) / 10); } +unsigned LangOptions::getOpenCLCompatibleVersion() const { + if (!OpenCLCPlusPlus) + return OpenCLVersion; + if (OpenCLCPlusPlusVersion == 100) + return 200; + if (OpenCLCPlusPlusVersion == 202100) + return 300; + llvm_unreachable("Unknown OpenCL version"); +} + +void LangOptions::remapPathPrefix(SmallString<256> &Path) const { + for (const auto &Entry : MacroPrefixMap) + if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) + break; +} + +std::string LangOptions::getOpenCLVersionString() const { + std::string Result; + { + llvm::raw_string_ostream Out(Result); + Out << (OpenCLCPlusPlus ? "C++ for OpenCL" : "OpenCL C") << " version " + << getOpenCLVersionTuple().getAsString(); + } + return Result; +} + FPOptions FPOptions::defaultWithoutTrailingStorage(const LangOptions &LO) { FPOptions result(LO); return result; diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index b6cf1624ef0..09bd3251fea 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -121,9 +121,7 @@ static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, .Default(Target.hasFeature(Feature) || isPlatformEnvironment(Target, Feature)); if (!HasFeature) - HasFeature = std::find(LangOpts.ModuleFeatures.begin(), - LangOpts.ModuleFeatures.end(), - Feature) != LangOpts.ModuleFeatures.end(); + HasFeature = llvm::is_contained(LangOpts.ModuleFeatures, Feature); return HasFeature; } @@ -203,7 +201,7 @@ static void printModuleId(raw_ostream &OS, InputIter Begin, InputIter End, OS << "."; StringRef Name = getModuleNameFromComponent(*It); - if (!AllowStringLiterals || isValidIdentifier(Name)) + if (!AllowStringLiterals || isValidAsciiIdentifier(Name)) OS << Name; else { OS << '"'; diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp index 2e215b185f6..b7408f39bda 100644 --- a/clang/lib/Basic/OpenCLOptions.cpp +++ b/clang/lib/Basic/OpenCLOptions.cpp @@ -111,7 +111,9 @@ bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies( // Feature pairs. First feature in a pair requires the second one to be // supported. static const llvm::StringMap DependentFeaturesMap = { - {"__opencl_c_read_write_images", "__opencl_c_images"}}; + {"__opencl_c_read_write_images", "__opencl_c_images"}, + {"__opencl_c_3d_image_writes", "__opencl_c_images"}, + {"__opencl_c_pipes", "__opencl_c_generic_address_space"}}; auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); @@ -130,7 +132,8 @@ bool OpenCLOptions::diagnoseFeatureExtensionDifferences( const TargetInfo &TI, DiagnosticsEngine &Diags) { // Extensions and equivalent feature pairs. static const llvm::StringMap FeatureExtensionMap = { - {"cl_khr_fp64", "__opencl_c_fp64"}}; + {"cl_khr_fp64", "__opencl_c_fp64"}, + {"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}}; auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts(); diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index cfdba09eb1e..9e74e05bd86 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -21,7 +21,7 @@ using namespace clang; using namespace llvm::omp; unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, - unsigned OpenMPVersion) { + const LangOptions &LangOpts) { switch (Kind) { case OMPC_default: return llvm::StringSwitch(Str) @@ -59,7 +59,9 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, .Case(#Name, static_cast(OMPC_MAP_MODIFIER_##Name)) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_MAP_unknown); - if (OpenMPVersion < 51 && Type == OMPC_MAP_MODIFIER_present) + if (LangOpts.OpenMP < 51 && Type == OMPC_MAP_MODIFIER_present) + return OMPC_MAP_MODIFIER_unknown; + if (!LangOpts.OpenMPExtensions && Type == OMPC_MAP_MODIFIER_ompx_hold) return OMPC_MAP_MODIFIER_unknown; return Type; } @@ -70,7 +72,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, .Case(#Name, static_cast(OMPC_MOTION_MODIFIER_##Name)) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_MOTION_MODIFIER_unknown); - if (OpenMPVersion < 51 && Type == OMPC_MOTION_MODIFIER_present) + if (LangOpts.OpenMP < 51 && Type == OMPC_MOTION_MODIFIER_present) return OMPC_MOTION_MODIFIER_unknown; return Type; } @@ -123,6 +125,16 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, #define OPENMP_REDUCTION_MODIFIER(Name) .Case(#Name, OMPC_REDUCTION_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_REDUCTION_unknown); + case OMPC_adjust_args: + return llvm::StringSwitch(Str) +#define OPENMP_ADJUST_ARGS_KIND(Name) .Case(#Name, OMPC_ADJUST_ARGS_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_ADJUST_ARGS_unknown); + case OMPC_bind: + return llvm::StringSwitch(Str) +#define OPENMP_BIND_KIND(Name) .Case(#Name, OMPC_BIND_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_BIND_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -183,6 +195,8 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str, case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_append_args: break; default: break; @@ -366,6 +380,26 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'reduction' clause modifier"); + case OMPC_adjust_args: + switch (Type) { + case OMPC_ADJUST_ARGS_unknown: + return "unknown"; +#define OPENMP_ADJUST_ARGS_KIND(Name) \ + case OMPC_ADJUST_ARGS_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'adjust_args' clause kind"); + case OMPC_bind: + switch (Type) { + case OMPC_BIND_unknown: + return "unknown"; +#define OPENMP_BIND_KIND(Name) \ + case OMPC_BIND_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'bind' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -426,6 +460,8 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_append_args: break; default: break; @@ -453,7 +489,7 @@ bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) { DKind == OMPD_target_teams_distribute_parallel_for || DKind == OMPD_target_teams_distribute_parallel_for_simd || DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile || - DKind == OMPD_unroll; + DKind == OMPD_unroll || DKind == OMPD_loop; } bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { @@ -556,6 +592,10 @@ bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) { Kind == OMPD_target_teams_distribute_simd; } +bool clang::isOpenMPGenericLoopDirective(OpenMPDirectiveKind Kind) { + return Kind == OMPD_loop; +} + bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { return Kind == OMPC_private || Kind == OMPC_firstprivate || Kind == OMPC_lastprivate || Kind == OMPC_linear || @@ -589,6 +629,9 @@ void clang::getOpenMPCaptureRegions( OpenMPDirectiveKind DKind) { assert(unsigned(DKind) < llvm::omp::Directive_enumSize); switch (DKind) { + case OMPD_metadirective: + CaptureRegions.push_back(OMPD_metadirective); + break; case OMPD_parallel: case OMPD_parallel_for: case OMPD_parallel_for_simd: @@ -651,6 +694,10 @@ void clang::getOpenMPCaptureRegions( CaptureRegions.push_back(OMPD_teams); CaptureRegions.push_back(OMPD_parallel); break; + case OMPD_loop: + // TODO: 'loop' may require different capture regions depending on the bind + // clause or the parent directive when there is no bind clause. Use + // OMPD_unknown for now. case OMPD_simd: case OMPD_for: case OMPD_for_simd: diff --git a/clang/lib/Basic/ProfileList.cpp b/clang/lib/Basic/ProfileList.cpp index 2cb05c1c3c0..9c88559d1c3 100644 --- a/clang/lib/Basic/ProfileList.cpp +++ b/clang/lib/Basic/ProfileList.cpp @@ -58,7 +58,7 @@ ProfileSpecialCaseList::createOrDie(const std::vector &Paths, std::string Error; if (auto PSCL = create(Paths, VFS, Error)) return PSCL; - llvm::report_fatal_error(Error); + llvm::report_fatal_error(llvm::Twine(Error)); } } diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 8cba379aa0f..c2e7b684cfd 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -207,28 +207,30 @@ void LineTableInfo::AddLineNote(FileID FID, unsigned Offset, unsigned LineNo, SrcMgr::CharacteristicKind FileKind) { std::vector &Entries = LineEntries[FID]; - // An unspecified FilenameID means use the last filename if available, or the - // main source file otherwise. - if (FilenameID == -1 && !Entries.empty()) - FilenameID = Entries.back().FilenameID; - assert((Entries.empty() || Entries.back().FileOffset < Offset) && "Adding line entries out of order!"); unsigned IncludeOffset = 0; - if (EntryExit == 0) { // No #include stack change. - IncludeOffset = Entries.empty() ? 0 : Entries.back().IncludeOffset; - } else if (EntryExit == 1) { + if (EntryExit == 1) { + // Push #include IncludeOffset = Offset-1; - } else if (EntryExit == 2) { - assert(!Entries.empty() && Entries.back().IncludeOffset && - "PPDirectives should have caught case when popping empty include stack"); - - // Get the include loc of the last entries' include loc as our include loc. - IncludeOffset = 0; - if (const LineEntry *PrevEntry = - FindNearestLineEntry(FID, Entries.back().IncludeOffset)) + } else { + const auto *PrevEntry = Entries.empty() ? nullptr : &Entries.back(); + if (EntryExit == 2) { + // Pop #include + assert(PrevEntry && PrevEntry->IncludeOffset && + "PPDirectives should have caught case when popping empty include " + "stack"); + PrevEntry = FindNearestLineEntry(FID, PrevEntry->IncludeOffset); + } + if (PrevEntry) { IncludeOffset = PrevEntry->IncludeOffset; + if (FilenameID == -1) { + // An unspecified FilenameID means use the previous (or containing) + // filename if available, or the main source file otherwise. + FilenameID = PrevEntry->FilenameID; + } + } } Entries.push_back(LineEntry::get(Offset, LineNo, FilenameID, FileKind, diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index b647a2fb8a6..646bbe8b738 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -34,8 +34,11 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { NoAsmVariants = false; HasLegalHalfType = false; HasFloat128 = false; + HasIbm128 = false; HasFloat16 = false; HasBFloat16 = false; + HasLongDouble = true; + HasFPReturn = true; HasStrictFP = false; PointerWidth = PointerAlign = 32; BoolWidth = BoolAlign = 8; @@ -83,6 +86,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { LongDoubleWidth = 64; LongDoubleAlign = 64; Float128Align = 128; + Ibm128Align = 128; LargeArrayMinWidth = 0; LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; @@ -113,6 +117,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { DoubleFormat = &llvm::APFloat::IEEEdouble(); LongDoubleFormat = &llvm::APFloat::IEEEdouble(); Float128Format = &llvm::APFloat::IEEEquad(); + Ibm128Format = &llvm::APFloat::PPCDoubleDouble(); MCountName = "mcount"; UserLabelPrefix = "_"; RegParmMax = 0; @@ -276,32 +281,36 @@ TargetInfo::IntType TargetInfo::getLeastIntTypeByWidth(unsigned BitWidth, return NoInt; } -TargetInfo::RealType TargetInfo::getRealTypeByWidth(unsigned BitWidth, - bool ExplicitIEEE) const { +FloatModeKind TargetInfo::getRealTypeByWidth(unsigned BitWidth, + FloatModeKind ExplicitType) const { if (getFloatWidth() == BitWidth) - return Float; + return FloatModeKind::Float; if (getDoubleWidth() == BitWidth) - return Double; + return FloatModeKind::Double; switch (BitWidth) { case 96: if (&getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended()) - return LongDouble; + return FloatModeKind::LongDouble; break; case 128: // The caller explicitly asked for an IEEE compliant type but we still // have to check if the target supports it. - if (ExplicitIEEE) - return hasFloat128Type() ? Float128 : NoFloat; + if (ExplicitType == FloatModeKind::Float128) + return hasFloat128Type() ? FloatModeKind::Float128 + : FloatModeKind::NoFloat; + if (ExplicitType == FloatModeKind::Ibm128) + return hasIbm128Type() ? FloatModeKind::Ibm128 + : FloatModeKind::NoFloat; if (&getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble() || &getLongDoubleFormat() == &llvm::APFloat::IEEEquad()) - return LongDouble; + return FloatModeKind::LongDouble; if (hasFloat128Type()) - return Float128; + return FloatModeKind::Float128; break; } - return NoFloat; + return FloatModeKind::NoFloat; } /// getTypeAlign - Return the alignment (in bits) of the specified integer type @@ -400,14 +409,18 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) { // OpenCL C v3.0 s6.7.5 - The generic address space requires support for // OpenCL C 2.0 or OpenCL C 3.0 with the __opencl_c_generic_address_space // feature - // FIXME: OpenCLGenericAddressSpace is also defined in setLangDefaults() + // OpenCL C v3.0 s6.2.1 - OpenCL pipes require support of OpenCL C 2.0 + // or later and __opencl_c_pipes feature + // FIXME: These language options are also defined in setLangDefaults() // for OpenCL C 2.0 but with no access to target capabilities. Target - // should be immutable once created and thus this language option needs + // should be immutable once created and thus these language options need // to be defined only once. - if (Opts.OpenCLVersion >= 300) { + if (Opts.getOpenCLCompatibleVersion() == 300) { const auto &OpenCLFeaturesMap = getSupportedOpenCLOpts(); Opts.OpenCLGenericAddressSpace = hasFeatureEnabled( OpenCLFeaturesMap, "__opencl_c_generic_address_space"); + Opts.OpenCLPipes = + hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes"); } } diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index ba91d043996..994a491cddf 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -606,6 +606,18 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, return nullptr; return new SPIR64TargetInfo(Triple, Opts); } + case llvm::Triple::spirv32: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIRV32TargetInfo(Triple, Opts); + } + case llvm::Triple::spirv64: { + if (os != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIRV64TargetInfo(Triple, Opts); + } case llvm::Triple::wasm32: if (Triple.getSubArch() != llvm::Triple::NoSubArch || Triple.getVendor() != llvm::Triple::UnknownVendor || @@ -745,7 +757,7 @@ bool TargetInfo::validateOpenCLTarget(const LangOptions &Opts, // Validate that feature macros are set properly for OpenCL C 3.0. // In other cases assume that target is always valid. - if (Opts.OpenCLCPlusPlus || Opts.OpenCLVersion < 300) + if (Opts.getOpenCLCompatibleVersion() < 300) return true; return OpenCLOptions::diagnoseUnsupportedFeatureDependencies(*this, Diags) && diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 4070ac727d1..f75b8ffcb53 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -40,6 +40,26 @@ const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { #include "clang/Basic/BuiltinsAArch64.def" }; +static StringRef getArchVersionString(llvm::AArch64::ArchKind Kind) { + switch (Kind) { + case llvm::AArch64::ArchKind::ARMV9A: + case llvm::AArch64::ArchKind::ARMV9_1A: + case llvm::AArch64::ArchKind::ARMV9_2A: + return "9"; + default: + return "8"; + } +} + +StringRef AArch64TargetInfo::getArchProfile() const { + switch (ArchKind) { + case llvm::AArch64::ArchKind::ARMV8R: + return "R"; + default: + return "A"; + } +} + AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple), ABI("aapcs") { @@ -203,6 +223,24 @@ void AArch64TargetInfo::getTargetDefinesARMV87A(const LangOptions &Opts, getTargetDefinesARMV86A(Opts, Builder); } +void AArch64TargetInfo::getTargetDefinesARMV9A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9-A maps to Armv8.5-A + getTargetDefinesARMV85A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV91A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.1-A maps to Armv8.6-A + getTargetDefinesARMV86A(Opts, Builder); +} + +void AArch64TargetInfo::getTargetDefinesARMV92A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Armv9.2-A maps to Armv8.7-A + getTargetDefinesARMV87A(Opts, Builder); +} + void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. @@ -227,8 +265,8 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, // ACLE predefines. Many can only have one possible value on v8 AArch64. Builder.defineMacro("__ARM_ACLE", "200"); - Builder.defineMacro("__ARM_ARCH", "8"); - Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); + Builder.defineMacro("__ARM_ARCH", getArchVersionString(ArchKind)); + Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + getArchProfile() + "'"); Builder.defineMacro("__ARM_64BIT_STATE", "1"); Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); @@ -405,6 +443,15 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::AArch64::ArchKind::ARMV8_7A: getTargetDefinesARMV87A(Opts, Builder); break; + case llvm::AArch64::ArchKind::ARMV9A: + getTargetDefinesARMV9A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9_1A: + getTargetDefinesARMV91A(Opts, Builder); + break; + case llvm::AArch64::ArchKind::ARMV9_2A: + getTargetDefinesARMV92A(Opts, Builder); + break; } // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. @@ -413,8 +460,8 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); - if (Opts.ArmSveVectorBits) { - Builder.defineMacro("__ARM_FEATURE_SVE_BITS", Twine(Opts.ArmSveVectorBits)); + if (Opts.VScaleMin && Opts.VScaleMin == Opts.VScaleMax) { + Builder.defineMacro("__ARM_FEATURE_SVE_BITS", Twine(Opts.VScaleMin * 128)); Builder.defineMacro("__ARM_FEATURE_SVE_VECTOR_OPERATORS"); } } @@ -424,6 +471,16 @@ ArrayRef AArch64TargetInfo::getTargetBuiltins() const { Builtin::FirstTSBuiltin); } +Optional> +AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const { + if (LangOpts.VScaleMin || LangOpts.VScaleMax) + return std::pair(LangOpts.VScaleMin, + LangOpts.VScaleMax); + if (hasFeature("sve")) + return std::pair(0, 16); + return None; +} + bool AArch64TargetInfo::hasFeature(StringRef Feature) const { return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || (Feature == "neon" && (FPU & NeonMode)) || @@ -431,7 +488,8 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const { Feature == "sve2-aes" || Feature == "sve2-sha3" || Feature == "sve2-sm4" || Feature == "f64mm" || Feature == "f32mm" || Feature == "i8mm" || Feature == "bf16") && - (FPU & SveMode)); + (FPU & SveMode)) || + (Feature == "ls64" && HasLS64); } bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, @@ -462,7 +520,7 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, HasMatmulFP32 = false; HasLSE = false; - ArchKind = llvm::AArch64::ArchKind::ARMV8A; + ArchKind = llvm::AArch64::ArchKind::INVALID; for (const auto &Feature : Features) { if (Feature == "+neon") @@ -524,6 +582,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, HasSM4 = true; if (Feature == "+strict-align") HasUnaligned = false; + if (Feature == "+v8a") + ArchKind = llvm::AArch64::ArchKind::ARMV8A; if (Feature == "+v8.1a") ArchKind = llvm::AArch64::ArchKind::ARMV8_1A; if (Feature == "+v8.2a") @@ -538,6 +598,12 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, ArchKind = llvm::AArch64::ArchKind::ARMV8_6A; if (Feature == "+v8.7a") ArchKind = llvm::AArch64::ArchKind::ARMV8_7A; + if (Feature == "+v9a") + ArchKind = llvm::AArch64::ArchKind::ARMV9A; + if (Feature == "+v9.1a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_1A; + if (Feature == "+v9.2a") + ArchKind = llvm::AArch64::ArchKind::ARMV9_2A; if (Feature == "+v8r") ArchKind = llvm::AArch64::ArchKind::ARMV8R; if (Feature == "+fullfp16") @@ -752,6 +818,9 @@ bool AArch64TargetInfo::validateConstraintModifier( if (Size == 64) return true; + if (Size == 512) + return HasLS64; + SuggestedModifier = "w"; return false; } diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 46882a80833..dea59a9b015 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -59,6 +59,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; std::string ABI; + StringRef getArchProfile() const; public: AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts); @@ -91,11 +92,20 @@ public: MacroBuilder &Builder) const; void getTargetDefinesARMV87A(const LangOptions &Opts, MacroBuilder &Builder) const; + void getTargetDefinesARMV9A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV91A(const LangOptions &Opts, + MacroBuilder &Builder) const; + void getTargetDefinesARMV92A(const LangOptions &Opts, + MacroBuilder &Builder) const; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; ArrayRef getTargetBuiltins() const override; + Optional> + getVScaleRange(const LangOptions &LangOpts) const override; + bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index fac786dbcf9..ba7ffa34c73 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Frontend/OpenMP/OMPGridValues.h" using namespace clang; using namespace clang::targets; @@ -335,7 +334,6 @@ AMDGPUTargetInfo::AMDGPUTargetInfo(const llvm::Triple &Triple, llvm::AMDGPU::getArchAttrR600(GPUKind)) { resetDataLayout(isAMDGCN(getTriple()) ? DataLayoutStringAMDGCN : DataLayoutStringR600); - GridValues = llvm::omp::AMDGPUGpuGridValues; setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || !isAMDGCN(Triple)); diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index 244a6e04469..8b9d7ce79c1 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -310,9 +310,12 @@ public: Opts["cl_khr_mipmap_image"] = true; Opts["cl_khr_mipmap_image_writes"] = true; Opts["cl_khr_subgroups"] = true; - Opts["cl_khr_3d_image_writes"] = true; Opts["cl_amd_media_ops"] = true; Opts["cl_amd_media_ops2"] = true; + + Opts["__opencl_c_images"] = true; + Opts["__opencl_c_3d_image_writes"] = true; + Opts["cl_khr_3d_image_writes"] = true; } } @@ -349,13 +352,35 @@ public: } LangAS getCUDABuiltinAddressSpace(unsigned AS) const override { - return LangAS::Default; + switch (AS) { + case 0: + return LangAS::Default; + case 1: + return LangAS::cuda_device; + case 3: + return LangAS::cuda_shared; + case 4: + return LangAS::cuda_constant; + default: + return getLangASFromTargetAS(AS); + } } llvm::Optional getConstantAddressSpace() const override { return getLangASFromTargetAS(Constant); } + const llvm::omp::GV &getGridValue() const override { + switch (WavefrontSize) { + case 32: + return llvm::omp::getAMDGPUGridValues<32>(); + case 64: + return llvm::omp::getAMDGPUGridValues<64>(); + default: + llvm_unreachable("getGridValue not implemented for this wavesize"); + } + } + /// \returns Target specific vtbl ptr address space. unsigned getVtblPtrAddressSpace() const override { return static_cast(Constant); @@ -415,7 +440,7 @@ public: WavefrontSize = 64; bool IsOn = F.front() == '+'; StringRef Name = StringRef(F).drop_front(); - if (llvm::find(TargetIDFeatures, Name) == TargetIDFeatures.end()) + if (!llvm::is_contained(TargetIDFeatures, Name)) return; assert(OffloadArchFeatures.find(Name) == OffloadArchFeatures.end()); OffloadArchFeatures[Name] = IsOn; diff --git a/clang/lib/Basic/Targets/ARC.h b/clang/lib/Basic/Targets/ARC.h index b314c42be1e..3c0c5f6df2f 100644 --- a/clang/lib/Basic/Targets/ARC.h +++ b/clang/lib/Basic/Targets/ARC.h @@ -67,6 +67,8 @@ public: } bool hasExtIntType() const override { return true; } + + bool isCLZForZeroUndef() const override { return false; } }; } // namespace targets diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 0e4048f8d5f..fc6b01c87fd 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -212,6 +212,12 @@ StringRef ARMTargetInfo::getCPUAttr() const { return "8_6A"; case llvm::ARM::ArchKind::ARMV8_7A: return "8_7A"; + case llvm::ARM::ArchKind::ARMV9A: + return "9A"; + case llvm::ARM::ArchKind::ARMV9_1A: + return "9_1A"; + case llvm::ARM::ArchKind::ARMV9_2A: + return "9_2A"; case llvm::ARM::ArchKind::ARMV8MBaseline: return "8M_BASE"; case llvm::ARM::ArchKind::ARMV8MMainline: @@ -440,6 +446,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, HasFloat16 = true; ARMCDECoprocMask = 0; HasBFloat16 = false; + FPRegsDisabled = false; // This does not diagnose illegal cases like having both // "+vfpv2" and "+vfpv3" or having "+neon" and "-fp64". @@ -516,6 +523,8 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, ARMCDECoprocMask |= (1U << Coproc); } else if (Feature == "+bf16") { HasBFloat16 = true; + } else if (Feature == "-fpregs") { + FPRegsDisabled = true; } } @@ -535,6 +544,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; break; case 8: + case 9: LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B; } @@ -877,6 +887,9 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::ARM::ArchKind::ARMV8_4A: case llvm::ARM::ArchKind::ARMV8_5A: case llvm::ARM::ArchKind::ARMV8_6A: + case llvm::ARM::ArchKind::ARMV9A: + case llvm::ARM::ArchKind::ARMV9_1A: + case llvm::ARM::ArchKind::ARMV9_2A: getTargetDefinesARMV83A(Opts, Builder); break; } @@ -968,6 +981,8 @@ bool ARMTargetInfo::validateAsmConstraint( case 't': // s0-s31, d0-d31, or q0-q15 case 'w': // s0-s15, d0-d7, or q0-q3 case 'x': // s0-s31, d0-d15, or q0-q7 + if (FPRegsDisabled) + return false; Info.setAllowsRegister(); return true; case 'j': // An immediate integer between 0 and 65535 (valid for MOVW) diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 0910064a033..d54a049042d 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -78,6 +78,7 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { unsigned Unaligned : 1; unsigned DotProd : 1; unsigned HasMatMul : 1; + unsigned FPRegsDisabled : 1; enum { LDREX_B = (1 << 0), /// byte (8-bit) diff --git a/clang/lib/Basic/Targets/AVR.cpp b/clang/lib/Basic/Targets/AVR.cpp index e87b7338c4d..50b0fc07b31 100644 --- a/clang/lib/Basic/Targets/AVR.cpp +++ b/clang/lib/Basic/Targets/AVR.cpp @@ -223,7 +223,7 @@ static MCUInfo AVRMcus[] = { {"atmega256rfr2", "__AVR_ATmega256RFR2__"}, {"atmega2564rfr2", "__AVR_ATmega2564RFR2__"}, {"atxmega16a4", "__AVR_ATxmega16A4__"}, - {"atxmega16a4u", "__AVR_ATxmega16a4U__"}, + {"atxmega16a4u", "__AVR_ATxmega16A4U__"}, {"atxmega16c4", "__AVR_ATxmega16C4__"}, {"atxmega16d4", "__AVR_ATxmega16D4__"}, {"atxmega32a4", "__AVR_ATxmega32A4__"}, @@ -265,7 +265,7 @@ static MCUInfo AVRMcus[] = { {"atxmega384d3", "__AVR_ATxmega384D3__"}, {"atxmega128a1", "__AVR_ATxmega128A1__"}, {"atxmega128a1u", "__AVR_ATxmega128A1U__"}, - {"atxmega128a4u", "__AVR_ATxmega128a4U__"}, + {"atxmega128a4u", "__AVR_ATxmega128A4U__"}, {"attiny4", "__AVR_ATtiny4__"}, {"attiny5", "__AVR_ATtiny5__"}, {"attiny9", "__AVR_ATtiny9__"}, @@ -274,6 +274,31 @@ static MCUInfo AVRMcus[] = { {"attiny40", "__AVR_ATtiny40__"}, {"attiny102", "__AVR_ATtiny102__"}, {"attiny104", "__AVR_ATtiny104__"}, + {"attiny202", "__AVR_ATtiny202__"}, + {"attiny402", "__AVR_ATtiny402__"}, + {"attiny204", "__AVR_ATtiny204__"}, + {"attiny404", "__AVR_ATtiny404__"}, + {"attiny804", "__AVR_ATtiny804__"}, + {"attiny1604", "__AVR_ATtiny1604__"}, + {"attiny406", "__AVR_ATtiny406__"}, + {"attiny806", "__AVR_ATtiny806__"}, + {"attiny1606", "__AVR_ATtiny1606__"}, + {"attiny807", "__AVR_ATtiny807__"}, + {"attiny1607", "__AVR_ATtiny1607__"}, + {"attiny212", "__AVR_ATtiny212__"}, + {"attiny412", "__AVR_ATtiny412__"}, + {"attiny214", "__AVR_ATtiny214__"}, + {"attiny414", "__AVR_ATtiny414__"}, + {"attiny814", "__AVR_ATtiny814__"}, + {"attiny1614", "__AVR_ATtiny1614__"}, + {"attiny416", "__AVR_ATtiny416__"}, + {"attiny816", "__AVR_ATtiny816__"}, + {"attiny1616", "__AVR_ATtiny1616__"}, + {"attiny3216", "__AVR_ATtiny3216__"}, + {"attiny417", "__AVR_ATtiny417__"}, + {"attiny817", "__AVR_ATtiny817__"}, + {"attiny1617", "__AVR_ATtiny1617__"}, + {"attiny3217", "__AVR_ATtiny3217__"}, }; } // namespace targets @@ -286,13 +311,10 @@ static constexpr llvm::StringLiteral ValidFamilyNames[] = { "avrxmega6", "avrxmega7", "avrtiny"}; bool AVRTargetInfo::isValidCPUName(StringRef Name) const { - bool IsFamily = - llvm::find(ValidFamilyNames, Name) != std::end(ValidFamilyNames); + bool IsFamily = llvm::is_contained(ValidFamilyNames, Name); - bool IsMCU = - llvm::find_if(AVRMcus, [&](const MCUInfo &Info) { - return Info.Name == Name; - }) != std::end(AVRMcus); + bool IsMCU = llvm::any_of( + AVRMcus, [&](const MCUInfo &Info) { return Info.Name == Name; }); return IsFamily || IsMCU; } diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp index 0b0298df30a..2dfe21564cc 100644 --- a/clang/lib/Basic/Targets/BPF.cpp +++ b/clang/lib/Basic/Targets/BPF.cpp @@ -35,7 +35,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = {"generic", "v1", "v2", "v3", "probe"}; bool BPFTargetInfo::isValidCPUName(StringRef Name) const { - return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); + return llvm::is_contained(ValidCPUNames, Name); } void BPFTargetInfo::fillValidCPUList(SmallVectorImpl &Values) const { diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index 31cb36d3763..c0cd8fa90ed 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -37,8 +37,8 @@ M68kTargetInfo::M68kTargetInfo(const llvm::Triple &Triple, // FIXME how to wire it with the used object format? Layout += "-m:e"; - // M68k pointers are always 32 bit wide even for 16 bit cpus - Layout += "-p:32:32"; + // M68k pointers are always 32 bit wide even for 16-bit CPUs + Layout += "-p:32:16:32"; // M68k integer data types Layout += "-i8:8:8-i16:16:16-i32:16:32"; diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index 3a32fd492c6..39246f650cc 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -50,7 +50,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = { {"octeon"}, {"octeon+"}, {"p5600"}}; bool MipsTargetInfo::isValidCPUName(StringRef Name) const { - return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); + return llvm::is_contained(ValidCPUNames, Name); } void MipsTargetInfo::fillValidCPUList( diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index 56f8a179db3..3561b22677b 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Frontend/OpenMP/OMPGridValues.h" using namespace clang; using namespace clang::targets; @@ -45,6 +44,9 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, if (!Feature.startswith("+ptx")) continue; PTXVersion = llvm::StringSwitch(Feature) + .Case("+ptx75", 75) + .Case("+ptx74", 74) + .Case("+ptx73", 73) .Case("+ptx72", 72) .Case("+ptx71", 71) .Case("+ptx70", 70) @@ -65,7 +67,6 @@ NVPTXTargetInfo::NVPTXTargetInfo(const llvm::Triple &Triple, TLSSupported = false; VLASupported = false; AddrSpaceMap = &NVPTXAddrSpaceMap; - GridValues = llvm::omp::NVPTXGpuGridValues; UseAddrSpaceMapMangling = true; // Define available target features diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index c7db3cdaaf1..ef751b8e1a8 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -147,6 +147,10 @@ public: Opts["cl_khr_local_int32_extended_atomics"] = true; } + const llvm::omp::GV &getGridValue() const override { + return llvm::omp::NVPTXGridValues; + } + /// \returns If a target requires an address within a target specific address /// space \p AddressSpace to be converted in order to be used, then return the /// corresponding target specific DWARF address space. diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index e24fb5cf082..7fbe2cbc565 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -179,6 +179,8 @@ protected: Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); Builder.defineMacro("__tune_i386__"); DefineStd(Builder, "unix", Opts); + if (this->HasFloat128) + Builder.defineMacro("__FLOAT128__"); } public: @@ -188,6 +190,7 @@ public: default: case llvm::Triple::x86: case llvm::Triple::x86_64: + this->HasFloat128 = true; this->MCountName = ".mcount"; break; } @@ -460,6 +463,9 @@ protected: Builder.defineMacro("_REENTRANT"); if (this->HasFloat128) Builder.defineMacro("__FLOAT128__"); + + if (Opts.C11) + Builder.defineMacro("__STDC_NO_THREADS__"); } public: @@ -673,9 +679,11 @@ protected: DefineStd(Builder, "unix", Opts); Builder.defineMacro("_IBMR2"); Builder.defineMacro("_POWER"); + Builder.defineMacro("__THW_BIG_ENDIAN__"); Builder.defineMacro("_AIX"); Builder.defineMacro("__TOS_AIX__"); + Builder.defineMacro("__HOS_AIX__"); if (Opts.C11) { Builder.defineMacro("__STDC_NO_ATOMICS__"); @@ -736,7 +744,6 @@ public: // AIX sets FLT_EVAL_METHOD to be 1. unsigned getFloatEvalMethod() const override { return 1; } - bool hasInt128Type() const override { return false; } bool defaultsToAIXPowerAlignment() const override { return true; } }; @@ -796,7 +803,6 @@ public: this->UseZeroLengthBitfieldAlignment = true; this->UseLeadingZeroLengthBitfield = false; this->ZeroLengthBitfieldBoundary = 32; - this->DefaultAlignForAttributeAligned = 128; } }; @@ -884,6 +890,9 @@ protected: // Required by the libc++ locale support. if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); + Builder.defineMacro("__Fuchsia_API_level__", Twine(Opts.FuchsiaAPILevel)); + this->PlatformName = "fuchsia"; + this->PlatformMinVersion = VersionTuple(Opts.FuchsiaAPILevel); } public: @@ -943,6 +952,7 @@ class LLVM_LIBRARY_VISIBILITY EmscriptenTargetInfo void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const final { WebAssemblyOSTargetInfo::getOSDefines(Opts, Triple, Builder); + DefineStd(Builder, "unix", Opts); Builder.defineMacro("__EMSCRIPTEN__"); if (Opts.POSIXThreads) Builder.defineMacro("__EMSCRIPTEN_PTHREADS__"); diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index 59656888e25..c3c61ed443c 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -73,6 +73,8 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector &Features, HasROPProtect = true; } else if (Feature == "+privileged") { HasPrivileged = true; + } else if (Feature == "+isa-v206-instructions") { + IsISA2_06 = true; } else if (Feature == "+isa-v207-instructions") { IsISA2_07 = true; } else if (Feature == "+isa-v30-instructions") { @@ -236,6 +238,15 @@ static void defineXLCompatMacros(MacroBuilder &Builder) { Builder.defineMacro("__frsqrtes", "__builtin_ppc_frsqrtes"); Builder.defineMacro("__fsqrt", "__builtin_ppc_fsqrt"); Builder.defineMacro("__fsqrts", "__builtin_ppc_fsqrts"); + Builder.defineMacro("__addex", "__builtin_ppc_addex"); + Builder.defineMacro("__cmplxl", "__builtin_complex"); + Builder.defineMacro("__compare_exp_uo", "__builtin_ppc_compare_exp_uo"); + Builder.defineMacro("__compare_exp_lt", "__builtin_ppc_compare_exp_lt"); + Builder.defineMacro("__compare_exp_gt", "__builtin_ppc_compare_exp_gt"); + Builder.defineMacro("__compare_exp_eq", "__builtin_ppc_compare_exp_eq"); + Builder.defineMacro("__test_data_class", "__builtin_ppc_test_data_class"); + Builder.defineMacro("__swdiv", "__builtin_ppc_swdiv"); + Builder.defineMacro("__swdivs", "__builtin_ppc_swdivs"); } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific @@ -243,7 +254,10 @@ static void defineXLCompatMacros(MacroBuilder &Builder) { void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - defineXLCompatMacros(Builder); + // We define the XLC compatibility macros only on AIX and Linux since XLC + // was never available on any other platforms. + if (getTriple().isOSAIX() || getTriple().isOSLinux()) + defineXLCompatMacros(Builder); // Target identification. Builder.defineMacro("__ppc__"); @@ -256,6 +270,15 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__powerpc64__"); Builder.defineMacro("__ppc64__"); Builder.defineMacro("__PPC64__"); + } else if (getTriple().isOSAIX()) { + // The XL compilers on AIX define _ARCH_PPC64 for both 32 and 64-bit modes. + Builder.defineMacro("_ARCH_PPC64"); + } + if (getTriple().isOSAIX()) { + Builder.defineMacro("__THW_PPC__"); + // Define __PPC and __powerpc for AIX XL C/C++ compatibility + Builder.defineMacro("__PPC"); + Builder.defineMacro("__powerpc"); } // Target properties. @@ -367,8 +390,6 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__MMA__"); if (HasROPProtect) Builder.defineMacro("__ROP_PROTECT__"); - if (HasPrivileged) - Builder.defineMacro("__PRIVILEGED__"); if (HasP10Vector) Builder.defineMacro("__POWER10_VECTOR__"); if (HasPCRelativeMemops) @@ -416,11 +437,11 @@ static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, const std::vector &FeaturesVec) { // vsx was not explicitly turned off. - if (llvm::find(FeaturesVec, "-vsx") == FeaturesVec.end()) + if (!llvm::is_contained(FeaturesVec, "-vsx")) return true; auto FindVSXSubfeature = [&](StringRef Feature, StringRef Option) { - if (llvm::find(FeaturesVec, Feature) != FeaturesVec.end()) { + if (llvm::is_contained(FeaturesVec, Feature)) { Diags.Report(diag::err_opt_not_valid_with_opt) << Option << "-mno-vsx"; return true; } @@ -507,6 +528,13 @@ bool PPCTargetInfo::initFeatureMap( .Case("e500", true) .Default(false); + Features["isa-v206-instructions"] = llvm::StringSwitch(CPU) + .Case("ppc64le", true) + .Case("pwr9", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["isa-v207-instructions"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) @@ -534,28 +562,50 @@ bool PPCTargetInfo::initFeatureMap( return false; if (!(ArchDefs & ArchDefinePwr9) && (ArchDefs & ArchDefinePpcgr) && - llvm::find(FeaturesVec, "+float128") != FeaturesVec.end()) { + llvm::is_contained(FeaturesVec, "+float128")) { // We have __float128 on PPC but not power 9 and above. Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << CPU; return false; } - if (!(ArchDefs & ArchDefinePwr10) && - llvm::find(FeaturesVec, "+mma") != FeaturesVec.end()) { - // We have MMA on PPC but not power 10 and above. - Diags.Report(diag::err_opt_not_valid_with_opt) << "-mmma" << CPU; - return false; + if (!(ArchDefs & ArchDefinePwr10)) { + if (llvm::find(FeaturesVec, "+mma") != FeaturesVec.end()) { + // MMA operations are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_with_opt) << "-mmma" << CPU; + return false; + } + if (llvm::find(FeaturesVec, "+pcrel") != FeaturesVec.end()) { + // PC-Relative instructions are not available pre-Power10, + // and these instructions also require prefixed instructions support. + Diags.Report(diag::err_opt_not_valid_without_opt) + << "-mpcrel" + << "-mcpu=pwr10 -mprefixed"; + return false; + } + if (llvm::find(FeaturesVec, "+prefixed") != FeaturesVec.end()) { + // Prefixed instructions are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_without_opt) << "-mprefixed" + << "-mcpu=pwr10"; + return false; + } + if (llvm::find(FeaturesVec, "+paired-vector-memops") != FeaturesVec.end()) { + // Paired vector memops are not available pre-Power10. + Diags.Report(diag::err_opt_not_valid_without_opt) + << "-mpaired-vector-memops" + << "-mcpu=pwr10"; + return false; + } } if (!(ArchDefs & ArchDefinePwr8) && - llvm::find(FeaturesVec, "+rop-protect") != FeaturesVec.end()) { + llvm::is_contained(FeaturesVec, "+rop-protect")) { // We can turn on ROP Protect on Power 8 and above. Diags.Report(diag::err_opt_not_valid_with_opt) << "-mrop-protect" << CPU; return false; } if (!(ArchDefs & ArchDefinePwr8) && - llvm::find(FeaturesVec, "+privileged") != FeaturesVec.end()) { + llvm::is_contained(FeaturesVec, "+privileged")) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mprivileged" << CPU; return false; } @@ -603,6 +653,7 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .Case("mma", HasMMA) .Case("rop-protect", HasROPProtect) .Case("privileged", HasPrivileged) + .Case("isa-v206-instructions", IsISA2_06) .Case("isa-v207-instructions", IsISA2_07) .Case("isa-v30-instructions", IsISA3_0) .Case("isa-v31-instructions", IsISA3_1) @@ -753,7 +804,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = { {"powerpc64le"}, {"ppc64le"}, {"future"}}; bool PPCTargetInfo::isValidCPUName(StringRef Name) const { - return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); + return llvm::is_contained(ValidCPUNames, Name); } void PPCTargetInfo::fillValidCPUList(SmallVectorImpl &Values) const { diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 7c14a4eb941..f19d3ebbc06 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -74,6 +74,7 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { bool HasP10Vector = false; bool HasPCRelativeMemops = false; bool HasPrefixInstrs = false; + bool IsISA2_06 = false; bool IsISA2_07 = false; bool IsISA3_0 = false; bool IsISA3_1 = false; @@ -89,6 +90,7 @@ public: LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); HasStrictFP = true; + HasIbm128 = true; } // Set the language option for altivec based on our value. @@ -347,6 +349,7 @@ public: : "u9__ieee128"; } const char *getFloat128Mangling() const override { return "u9__ieee128"; } + const char *getIbm128Mangling() const override { return "g"; } bool hasExtIntType() const override { return true; } diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index 9705129b39d..93562dde2f5 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -11,10 +11,12 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/raw_ostream.h" using namespace clang; using namespace clang::targets; @@ -105,7 +107,7 @@ std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const { std::string R; switch (*Constraint) { case 'v': - R = std::string("v"); + R = std::string("^") + std::string(Constraint, 2); Constraint += 1; break; default: @@ -122,6 +124,7 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32"); StringRef CodeModel = getTargetOpts().CodeModel; + unsigned FLen = ISAInfo->getFLen(); if (CodeModel == "default") CodeModel = "small"; @@ -142,17 +145,23 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__riscv_abi_rve"); Builder.defineMacro("__riscv_arch_test"); - Builder.defineMacro("__riscv_i", "2000000"); - if (HasM) { - Builder.defineMacro("__riscv_m", "2000000"); + for (auto &Extension : ISAInfo->getExtensions()) { + auto ExtName = Extension.first; + auto ExtInfo = Extension.second; + unsigned Version = + (ExtInfo.MajorVersion * 1000000) + (ExtInfo.MinorVersion * 1000); + + Builder.defineMacro(Twine("__riscv_", ExtName), Twine(Version)); + } + + if (ISAInfo->hasExtension("m")) { Builder.defineMacro("__riscv_mul"); Builder.defineMacro("__riscv_div"); Builder.defineMacro("__riscv_muldiv"); } - if (HasA) { - Builder.defineMacro("__riscv_a", "2000000"); + if (ISAInfo->hasExtension("a")) { Builder.defineMacro("__riscv_atomic"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -161,75 +170,25 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } - if (HasF || HasD) { - Builder.defineMacro("__riscv_f", "2000000"); - Builder.defineMacro("__riscv_flen", HasD ? "64" : "32"); + if (FLen) { + Builder.defineMacro("__riscv_flen", Twine(FLen)); Builder.defineMacro("__riscv_fdiv"); Builder.defineMacro("__riscv_fsqrt"); } - if (HasD) - Builder.defineMacro("__riscv_d", "2000000"); - - if (HasC) { - Builder.defineMacro("__riscv_c", "2000000"); + if (ISAInfo->hasExtension("c")) Builder.defineMacro("__riscv_compressed"); - } - if (HasB) { - Builder.defineMacro("__riscv_b", "93000"); - Builder.defineMacro("__riscv_bitmanip"); - } - - if (HasV) { - Builder.defineMacro("__riscv_v", "10000"); + if (ISAInfo->hasExtension("v")) Builder.defineMacro("__riscv_vector"); - } - - if (HasZba) - Builder.defineMacro("__riscv_zba", "93000"); - - if (HasZbb) - Builder.defineMacro("__riscv_zbb", "93000"); - - if (HasZbc) - Builder.defineMacro("__riscv_zbc", "93000"); - - if (HasZbe) - Builder.defineMacro("__riscv_zbe", "93000"); - - if (HasZbf) - Builder.defineMacro("__riscv_zbf", "93000"); - - if (HasZbm) - Builder.defineMacro("__riscv_zbm", "93000"); - - if (HasZbp) - Builder.defineMacro("__riscv_zbp", "93000"); - - if (HasZbproposedc) - Builder.defineMacro("__riscv_zbproposedc", "93000"); - - if (HasZbr) - Builder.defineMacro("__riscv_zbr", "93000"); - - if (HasZbs) - Builder.defineMacro("__riscv_zbs", "93000"); - - if (HasZbt) - Builder.defineMacro("__riscv_zbt", "93000"); - - if (HasZfh) - Builder.defineMacro("__riscv_zfh", "1000"); - - if (HasZvamo) - Builder.defineMacro("__riscv_zvamo", "10000"); - - if (HasZvlsseg) - Builder.defineMacro("__riscv_zvlsseg", "10000"); } const Builtin::Info RISCVTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsRISCVVector.def" #define BUILTIN(ID, TYPE, ATTRS) \ {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ @@ -255,81 +214,36 @@ bool RISCVTargetInfo::initFeatureMap( /// Return true if has this feature, need to sync with handleTargetFeatures. bool RISCVTargetInfo::hasFeature(StringRef Feature) const { bool Is64Bit = getTriple().getArch() == llvm::Triple::riscv64; - return llvm::StringSwitch(Feature) - .Case("riscv", true) - .Case("riscv32", !Is64Bit) - .Case("riscv64", Is64Bit) - .Case("64bit", Is64Bit) - .Case("m", HasM) - .Case("a", HasA) - .Case("f", HasF) - .Case("d", HasD) - .Case("c", HasC) - .Case("experimental-b", HasB) - .Case("experimental-v", HasV) - .Case("experimental-zba", HasZba) - .Case("experimental-zbb", HasZbb) - .Case("experimental-zbc", HasZbc) - .Case("experimental-zbe", HasZbe) - .Case("experimental-zbf", HasZbf) - .Case("experimental-zbm", HasZbm) - .Case("experimental-zbp", HasZbp) - .Case("experimental-zbproposedc", HasZbproposedc) - .Case("experimental-zbr", HasZbr) - .Case("experimental-zbs", HasZbs) - .Case("experimental-zbt", HasZbt) - .Case("experimental-zfh", HasZfh) - .Case("experimental-zvamo", HasZvamo) - .Case("experimental-zvlsseg", HasZvlsseg) - .Default(false); + auto Result = llvm::StringSwitch>(Feature) + .Case("riscv", true) + .Case("riscv32", !Is64Bit) + .Case("riscv64", Is64Bit) + .Case("64bit", Is64Bit) + .Default(None); + if (Result.hasValue()) + return Result.getValue(); + + if (ISAInfo->isSupportedExtensionFeature(Feature)) + return ISAInfo->hasExtension(Feature); + + return false; } /// Perform initialization based on the user configured set of features. bool RISCVTargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { - for (const auto &Feature : Features) { - if (Feature == "+m") - HasM = true; - else if (Feature == "+a") - HasA = true; - else if (Feature == "+f") - HasF = true; - else if (Feature == "+d") - HasD = true; - else if (Feature == "+c") - HasC = true; - else if (Feature == "+experimental-b") - HasB = true; - else if (Feature == "+experimental-v") - HasV = true; - else if (Feature == "+experimental-zba") - HasZba = true; - else if (Feature == "+experimental-zbb") - HasZbb = true; - else if (Feature == "+experimental-zbc") - HasZbc = true; - else if (Feature == "+experimental-zbe") - HasZbe = true; - else if (Feature == "+experimental-zbf") - HasZbf = true; - else if (Feature == "+experimental-zbm") - HasZbm = true; - else if (Feature == "+experimental-zbp") - HasZbp = true; - else if (Feature == "+experimental-zbproposedc") - HasZbproposedc = true; - else if (Feature == "+experimental-zbr") - HasZbr = true; - else if (Feature == "+experimental-zbs") - HasZbs = true; - else if (Feature == "+experimental-zbt") - HasZbt = true; - else if (Feature == "+experimental-zfh") - HasZfh = true; - else if (Feature == "+experimental-zvamo") - HasZvamo = true; - else if (Feature == "+experimental-zvlsseg") - HasZvlsseg = true; + unsigned XLen = getTriple().isArch64Bit() ? 64 : 32; + auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features); + if (!ParseResult) { + std::string Buffer; + llvm::raw_string_ostream OutputErrMsg(Buffer); + handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) { + OutputErrMsg << ErrMsg.getMessage(); + }); + Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str(); + return false; + } else { + ISAInfo = std::move(*ParseResult); } return true; diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index 7e0846581ca..f7ffe9febcd 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -17,6 +17,7 @@ #include "clang/Basic/TargetOptions.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/RISCVISAInfo.h" namespace clang { namespace targets { @@ -25,28 +26,7 @@ namespace targets { class RISCVTargetInfo : public TargetInfo { protected: std::string ABI, CPU; - bool HasM = false; - bool HasA = false; - bool HasF = false; - bool HasD = false; - bool HasC = false; - bool HasB = false; - bool HasV = false; - bool HasZba = false; - bool HasZbb = false; - bool HasZbc = false; - bool HasZbe = false; - bool HasZbf = false; - bool HasZbm = false; - bool HasZbp = false; - bool HasZbproposedc = false; - bool HasZbr = false; - bool HasZbs = false; - bool HasZbt = false; - bool HasZfh = false; - bool HasZvamo = false; - bool HasZvlsseg = false; - + std::unique_ptr ISAInfo; static const Builtin::Info BuiltinInfo[]; public: @@ -82,6 +62,11 @@ public: const char *getClobbers() const override { return ""; } + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + ArrayRef getGCCRegNames() const override; int getEHDataRegisterNumber(unsigned RegNo) const override { @@ -138,7 +123,7 @@ public: void setMaxAtomicWidth() override { MaxAtomicPromoteWidth = 128; - if (HasA) + if (ISAInfo->hasExtension("a")) MaxAtomicInlineWidth = 32; } }; @@ -167,7 +152,7 @@ public: void setMaxAtomicWidth() override { MaxAtomicPromoteWidth = 128; - if (HasA) + if (ISAInfo->hasExtension("a")) MaxAtomicInlineWidth = 64; } }; diff --git a/clang/lib/Basic/Targets/SPIR.cpp b/clang/lib/Basic/Targets/SPIR.cpp index 9b7aab85314..09d482a8b9e 100644 --- a/clang/lib/Basic/Targets/SPIR.cpp +++ b/clang/lib/Basic/Targets/SPIR.cpp @@ -1,4 +1,4 @@ -//===--- SPIR.cpp - Implement SPIR target feature support -----------------===// +//===--- SPIR.cpp - Implement SPIR and SPIR-V target feature support ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements SPIR TargetInfo objects. +// This file implements SPIR and SPIR-V TargetInfo objects. // //===----------------------------------------------------------------------===// @@ -32,3 +32,20 @@ void SPIR64TargetInfo::getTargetDefines(const LangOptions &Opts, SPIRTargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "SPIR64", Opts); } + +void SPIRVTargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "SPIRV", Opts); +} + +void SPIRV32TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRVTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIRV32", Opts); +} + +void SPIRV64TargetInfo::getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + SPIRVTargetInfo::getTargetDefines(Opts, Builder); + DefineStd(Builder, "SPIRV64", Opts); +} diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 50f34abd663..704b1843dfe 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -1,4 +1,4 @@ -//===--- SPIR.h - Declare SPIR target feature support -----------*- C++ -*-===// +//===--- SPIR.h - Declare SPIR and SPIR-V target feature support *- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file declares SPIR TargetInfo objects. +// This file declares SPIR and SPIR-V TargetInfo objects. // //===----------------------------------------------------------------------===// @@ -21,6 +21,7 @@ namespace clang { namespace targets { +// Used by both the SPIR and SPIR-V targets. static const unsigned SPIRDefIsPrivMap[] = { 0, // Default 1, // opencl_global @@ -44,6 +45,7 @@ static const unsigned SPIRDefIsPrivMap[] = { 0 // ptr64 }; +// Used by both the SPIR and SPIR-V targets. static const unsigned SPIRDefIsGenMap[] = { 4, // Default // OpenCL address space values for this map are dummy and they can't be used @@ -67,14 +69,15 @@ static const unsigned SPIRDefIsGenMap[] = { 0 // ptr64 }; -class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { -public: - SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) +// Base class for SPIR and SPIR-V target info. +class LLVM_LIBRARY_VISIBILITY BaseSPIRTargetInfo : public TargetInfo { +protected: + BaseSPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { assert(getTriple().getOS() == llvm::Triple::UnknownOS && - "SPIR target must use unknown OS"); + "SPIR(-V) target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && - "SPIR target must use unknown environment type"); + "SPIR(-V) target must use unknown environment type"); TLSSupported = false; VLASupported = false; LongWidth = LongAlign = 64; @@ -87,13 +90,7 @@ public: NoAsmVariants = true; } - void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override; - - bool hasFeature(StringRef Feature) const override { - return Feature == "spir"; - } - +public: // SPIR supports the half type and the only llvm intrinsic allowed in SPIR is // memcpy as per section 3 of the SPIR spec. bool useFP16ConversionIntrinsics() const override { return false; } @@ -149,7 +146,7 @@ public: void setSupportedOpenCLOpts() override { // Assume all OpenCL extensions and optional core features are supported - // for SPIR since it is a generic target. + // for SPIR and SPIR-V since they are generic targets. supportAllOpenCLOpts(); } @@ -158,6 +155,24 @@ public: bool hasInt128Type() const override { return false; } }; +class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public BaseSPIRTargetInfo { +public: + SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : BaseSPIRTargetInfo(Triple, Opts) { + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR target must use unknown environment type"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spir"; + } +}; + class LLVM_LIBRARY_VISIBILITY SPIR32TargetInfo : public SPIRTargetInfo { public: SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) @@ -187,6 +202,55 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; }; + +class LLVM_LIBRARY_VISIBILITY SPIRVTargetInfo : public BaseSPIRTargetInfo { +public: + SPIRVTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : BaseSPIRTargetInfo(Triple, Opts) { + assert(getTriple().getOS() == llvm::Triple::UnknownOS && + "SPIR-V target must use unknown OS"); + assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && + "SPIR-V target must use unknown environment type"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; + + bool hasFeature(StringRef Feature) const override { + return Feature == "spirv"; + } +}; + +class LLVM_LIBRARY_VISIBILITY SPIRV32TargetInfo : public SPIRVTargetInfo { +public: + SPIRV32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRVTargetInfo(Triple, Opts) { + PointerWidth = PointerAlign = 32; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = IntPtrType = TargetInfo::SignedInt; + resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + +class LLVM_LIBRARY_VISIBILITY SPIRV64TargetInfo : public SPIRVTargetInfo { +public: + SPIRV64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : SPIRVTargetInfo(Triple, Opts) { + PointerWidth = PointerAlign = 64; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = IntPtrType = TargetInfo::SignedLong; + resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" + "v96:128-v192:256-v256:256-v512:512-v1024:1024"); + } + + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override; +}; + } // namespace targets } // namespace clang #endif // LLVM_CLANG_LIB_BASIC_TARGETS_SPIR_H diff --git a/clang/lib/Basic/Targets/Sparc.h b/clang/lib/Basic/Targets/Sparc.h index 07844abafe1..22a1621fcb9 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -39,10 +39,8 @@ public: bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { // Check if software floating point is enabled - auto Feature = llvm::find(Features, "+soft-float"); - if (Feature != Features.end()) { + if (llvm::is_contained(Features, "+soft-float")) SoftFloat = true; - } return true; } void getTargetDefines(const LangOptions &Opts, diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index b749c3f75d1..d3e3ed50dd4 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -46,7 +46,17 @@ public: LongDoubleFormat = &llvm::APFloat::IEEEquad(); DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; - resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); + if (Triple.isOSzOS()) { + // All vector types are default aligned on an 8-byte boundary, even if the + // vector facility is not available. That is different from Linux. + MaxVectorAlign = 64; + // Compared to Linux/ELF, the data layout differs only in some details: + // - name mangling is GOFF + // - 128 bit vector types are 64 bit aligned + resetDataLayout( + "E-m:l-i1:8:16-i8:8:16-i64:64-f128:64-v128:64-a:8:16-n32:64"); + } else + resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; HasStrictFP = true; } @@ -129,7 +139,7 @@ public: HasVector &= !SoftFloat; // If we use the vector ABI, vector types are 64-bit aligned. - if (HasVector) { + if (HasVector && !getTriple().isOSzOS()) { MaxVectorAlign = 64; resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" "-v128:64-a:8:16-n32:64"); diff --git a/clang/lib/Basic/Targets/WebAssembly.cpp b/clang/lib/Basic/Targets/WebAssembly.cpp index 7ef79849cb7..4cba861f61d 100644 --- a/clang/lib/Basic/Targets/WebAssembly.cpp +++ b/clang/lib/Basic/Targets/WebAssembly.cpp @@ -46,6 +46,7 @@ bool WebAssemblyTargetInfo::setABI(const std::string &Name) { bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("simd128", SIMDLevel >= SIMD128) + .Case("relaxed-simd", SIMDLevel >= RelaxedSIMD) .Case("nontrapping-fptoint", HasNontrappingFPToInt) .Case("sign-ext", HasSignExt) .Case("exception-handling", HasExceptionHandling) @@ -59,7 +60,7 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const { } bool WebAssemblyTargetInfo::isValidCPUName(StringRef Name) const { - return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); + return llvm::is_contained(ValidCPUNames, Name); } void WebAssemblyTargetInfo::fillValidCPUList( @@ -72,6 +73,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts, defineCPUMacros(Builder, "wasm", /*Tuning=*/false); if (SIMDLevel >= SIMD128) Builder.defineMacro("__wasm_simd128__"); + if (SIMDLevel >= RelaxedSIMD) + Builder.defineMacro("__wasm_relaxed_simd__"); if (HasNontrappingFPToInt) Builder.defineMacro("__wasm_nontrapping_fptoint__"); if (HasSignExt) @@ -96,6 +99,9 @@ void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap &Features, SIMDEnum Level, bool Enabled) { if (Enabled) { switch (Level) { + case RelaxedSIMD: + Features["relaxed-simd"] = true; + LLVM_FALLTHROUGH; case SIMD128: Features["simd128"] = true; LLVM_FALLTHROUGH; @@ -109,6 +115,9 @@ void WebAssemblyTargetInfo::setSIMDLevel(llvm::StringMap &Features, case NoSIMD: case SIMD128: Features["simd128"] = false; + LLVM_FALLTHROUGH; + case RelaxedSIMD: + Features["relaxed-simd"] = false; break; } } @@ -118,6 +127,8 @@ void WebAssemblyTargetInfo::setFeatureEnabled(llvm::StringMap &Features, bool Enabled) const { if (Name == "simd128") setSIMDLevel(Features, SIMD128, Enabled); + else if (Name == "relaxed-simd") + setSIMDLevel(Features, RelaxedSIMD, Enabled); else Features[Name] = Enabled; } @@ -149,6 +160,14 @@ bool WebAssemblyTargetInfo::handleTargetFeatures( SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); continue; } + if (Feature == "+relaxed-simd") { + SIMDLevel = std::max(SIMDLevel, RelaxedSIMD); + continue; + } + if (Feature == "-relaxed-simd") { + SIMDLevel = std::min(SIMDLevel, SIMDEnum(RelaxedSIMD - 1)); + continue; + } if (Feature == "+nontrapping-fptoint") { HasNontrappingFPToInt = true; continue; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 4a5ba25c75e..16534d3ef99 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -27,6 +27,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo { enum SIMDEnum { NoSIMD, SIMD128, + RelaxedSIMD, } SIMDLevel = NoSIMD; bool HasNontrappingFPToInt = false; @@ -150,9 +151,11 @@ public: const TargetOptions &Opts) : WebAssemblyTargetInfo(T, Opts) { if (T.isOSEmscripten()) - resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20"); + resetDataLayout("e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" + "S128-ni:1:10:20"); else - resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"); + resetDataLayout( + "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); } protected: @@ -172,9 +175,11 @@ public: PtrDiffType = SignedLong; IntPtrType = SignedLong; if (T.isOSEmscripten()) - resetDataLayout("e-m:e-p:64:64-i64:64-f128:64-n32:64-S128-ni:1:10:20"); + resetDataLayout("e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-" + "S128-ni:1:10:20"); else - resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128-ni:1:10:20"); + resetDataLayout( + "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"); } protected: diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 9db96c20250..5e368689371 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -139,22 +139,28 @@ bool X86TargetInfo::initFeatureMap( // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. auto I = Features.find("sse4.2"); if (I != Features.end() && I->getValue() && - llvm::find(UpdatedFeaturesVec, "-popcnt") == UpdatedFeaturesVec.end()) + !llvm::is_contained(UpdatedFeaturesVec, "-popcnt")) Features["popcnt"] = true; // Additionally, if SSE is enabled and mmx is not explicitly disabled, // then enable MMX. I = Features.find("sse"); if (I != Features.end() && I->getValue() && - llvm::find(UpdatedFeaturesVec, "-mmx") == UpdatedFeaturesVec.end()) + !llvm::is_contained(UpdatedFeaturesVec, "-mmx")) Features["mmx"] = true; // Enable xsave if avx is enabled and xsave is not explicitly disabled. I = Features.find("avx"); if (I != Features.end() && I->getValue() && - llvm::find(UpdatedFeaturesVec, "-xsave") == UpdatedFeaturesVec.end()) + !llvm::is_contained(UpdatedFeaturesVec, "-xsave")) Features["xsave"] = true; + // Enable CRC32 if SSE4.2 is enabled and CRC32 is not explicitly disabled. + I = Features.find("sse4.2"); + if (I != Features.end() && I->getValue() && + !llvm::is_contained(UpdatedFeaturesVec, "-crc32")) + Features["crc32"] = true; + return true; } @@ -231,8 +237,11 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasAVX512BF16 = true; } else if (Feature == "+avx512er") { HasAVX512ER = true; + } else if (Feature == "+avx512fp16") { + HasAVX512FP16 = true; } else if (Feature == "+avx512pf") { HasAVX512PF = true; + HasLegalHalfType = true; } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bitalg") { @@ -327,6 +336,10 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, HasTSXLDTRK = true; } else if (Feature == "+uintr") { HasUINTR = true; + } else if (Feature == "+crc32") { + HasCRC32 = true; + } else if (Feature == "+x87") { + HasX87 = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) @@ -356,6 +369,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, .Default(NoXOP); XOPLevel = std::max(XOPLevel, XLevel); } + // Turn on _float16 for x86 (feature sse2) + HasFloat16 = SSELevel >= SSE2; // LLVM doesn't have a separate switch for fpmath, so only accept it if it // matches the selected sse level. @@ -368,6 +383,14 @@ bool X86TargetInfo::handleTargetFeatures(std::vector &Features, SimdDefaultAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; + + if (!HasX87) { + if (LongDoubleFormat == &llvm::APFloat::x87DoubleExtended()) + HasLongDouble = false; + if (getTriple().getArch() == llvm::Triple::x86) + HasFPReturn = false; + } + return true; } @@ -668,6 +691,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__AVX512BF16__"); if (HasAVX512ER) Builder.defineMacro("__AVX512ER__"); + if (HasAVX512FP16) + Builder.defineMacro("__AVX512FP16__"); if (HasAVX512PF) Builder.defineMacro("__AVX512PF__"); if (HasAVX512DQ) @@ -753,6 +778,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__TSXLDTRK__"); if (HasUINTR) Builder.defineMacro("__UINTR__"); + if (HasCRC32) + Builder.defineMacro("__CRC32__"); // Each case falls through to the previous one here. switch (SSELevel) { @@ -856,6 +883,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("avx512vnni", true) .Case("avx512bf16", true) .Case("avx512er", true) + .Case("avx512fp16", true) .Case("avx512pf", true) .Case("avx512dq", true) .Case("avx512bitalg", true) @@ -872,6 +900,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const { .Case("clflushopt", true) .Case("clwb", true) .Case("clzero", true) + .Case("crc32", true) .Case("cx16", true) .Case("enqcmd", true) .Case("f16c", true) @@ -948,6 +977,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("avx512vnni", HasAVX512VNNI) .Case("avx512bf16", HasAVX512BF16) .Case("avx512er", HasAVX512ER) + .Case("avx512fp16", HasAVX512FP16) .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) .Case("avx512bitalg", HasAVX512BITALG) @@ -963,6 +993,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("clflushopt", HasCLFLUSHOPT) .Case("clwb", HasCLWB) .Case("clzero", HasCLZERO) + .Case("crc32", HasCRC32) .Case("cx8", HasCX8) .Case("cx16", HasCX16) .Case("enqcmd", HasENQCMD) @@ -1019,6 +1050,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("x86", true) .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) + .Case("x87", HasX87) .Case("xop", XOPLevel >= XOP) .Case("xsave", HasXSAVE) .Case("xsavec", HasXSAVEC) @@ -1034,35 +1066,22 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { // X86TargetInfo::hasFeature for a somewhat comprehensive list). bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { return llvm::StringSwitch(FeatureStr) -#define X86_FEATURE_COMPAT(ENUM, STR) .Case(STR, true) +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) .Case(STR, true) #include "llvm/Support/X86TargetParser.def" .Default(false); } static llvm::X86::ProcessorFeatures getFeature(StringRef Name) { return llvm::StringSwitch(Name) -#define X86_FEATURE_COMPAT(ENUM, STR) .Case(STR, llvm::X86::FEATURE_##ENUM) +#define X86_FEATURE_COMPAT(ENUM, STR, PRIORITY) \ + .Case(STR, llvm::X86::FEATURE_##ENUM) + #include "llvm/Support/X86TargetParser.def" ; // Note, this function should only be used after ensuring the value is // correct, so it asserts if the value is out of range. } -static unsigned getFeaturePriority(llvm::X86::ProcessorFeatures Feat) { - enum class FeatPriority { -#define FEATURE(FEAT) FEAT, -#include "clang/Basic/X86Target.def" - }; - switch (Feat) { -#define FEATURE(FEAT) \ - case llvm::X86::FEAT: \ - return static_cast(FeatPriority::FEAT); -#include "clang/Basic/X86Target.def" - default: - llvm_unreachable("No Feature Priority for non-CPUSupports Features"); - } -} - unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const { // Valid CPUs have a 'key feature' that compares just better than its key // feature. @@ -1082,21 +1101,21 @@ bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const { return llvm::StringSwitch(Name) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, true) #define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, true) -#include "clang/Basic/X86Target.def" +#include "llvm/Support/X86TargetParser.def" .Default(false); } static StringRef CPUSpecificCPUDispatchNameDealias(StringRef Name) { return llvm::StringSwitch(Name) #define CPU_SPECIFIC_ALIAS(NEW_NAME, NAME) .Case(NEW_NAME, NAME) -#include "clang/Basic/X86Target.def" +#include "llvm/Support/X86TargetParser.def" .Default(Name); } char X86TargetInfo::CPUSpecificManglingCharacter(StringRef Name) const { return llvm::StringSwitch(CPUSpecificCPUDispatchNameDealias(Name)) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, MANGLING) -#include "clang/Basic/X86Target.def" +#include "llvm/Support/X86TargetParser.def" .Default(0); } @@ -1105,7 +1124,7 @@ void X86TargetInfo::getCPUSpecificCPUDispatchFeatures( StringRef WholeList = llvm::StringSwitch(CPUSpecificCPUDispatchNameDealias(Name)) #define CPU_SPECIFIC(NAME, MANGLING, FEATURES) .Case(NAME, FEATURES) -#include "clang/Basic/X86Target.def" +#include "llvm/Support/X86TargetParser.def" .Default(""); WholeList.split(Features, ',', /*MaxSplit=*/-1, /*KeepEmpty=*/false); } diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index fcaaf50624e..b9b2ac79815 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -92,6 +92,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasAVX512CD = false; bool HasAVX512VPOPCNTDQ = false; bool HasAVX512VNNI = false; + bool HasAVX512FP16 = false; bool HasAVX512BF16 = false; bool HasAVX512ER = false; bool HasAVX512PF = false; @@ -142,6 +143,8 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { bool HasSERIALIZE = false; bool HasTSXLDTRK = false; bool HasUINTR = false; + bool HasCRC32 = false; + bool HasX87 = false; protected: llvm::X86::CPUKind CPU = llvm::X86::CK_None; @@ -410,8 +413,8 @@ public: // Use fpret for all types. RealTypeUsesObjCFPRet = - ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | - (1 << TargetInfo::LongDouble)); + ((1 << (int)FloatModeKind::Float) | (1 << (int)FloatModeKind::Double) | + (1 << (int)FloatModeKind::LongDouble)); // x86-32 has atomics up to 8 bytes MaxAtomicPromoteWidth = 64; @@ -690,7 +693,7 @@ public: "64-i64:64-f80:128-n8:16:32:64-S128"); // Use fpret only for long double. - RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); + RealTypeUsesObjCFPRet = (1 << (int)FloatModeKind::LongDouble); // Use fp2ret for _Complex long double. ComplexLongDoubleUsesFP2Ret = true; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 481f5347d97..648c7b3df8e 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -38,6 +38,7 @@ #include "llvm/LTO/LTOBackend.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/SubtargetFeature.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Passes/PassBuilder.h" #include "llvm/Passes/PassPlugin.h" #include "llvm/Passes/StandardInstrumentations.h" @@ -45,7 +46,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" #include "llvm/Support/ToolOutputFile.h" @@ -147,6 +147,14 @@ class EmitAssemblyHelper { return F; } + void + RunOptimizationPipeline(BackendAction Action, + std::unique_ptr &OS, + std::unique_ptr &ThinLinkOS); + void RunCodegenPipeline(BackendAction Action, + std::unique_ptr &OS, + std::unique_ptr &DwoOS); + public: EmitAssemblyHelper(DiagnosticsEngine &_Diags, const HeaderSearchOptions &HeaderSearchOpts, @@ -164,11 +172,16 @@ public: std::unique_ptr TM; + // Emit output using the legacy pass manager for the optimization pipeline. + // This will be removed soon when using the legacy pass manager for the + // optimization pipeline is no longer supported. + void EmitAssemblyWithLegacyPassManager(BackendAction Action, + std::unique_ptr OS); + + // Emit output using the new pass manager for the optimization pipeline. This + // is the default. void EmitAssembly(BackendAction Action, std::unique_ptr OS); - - void EmitAssemblyWithNewPassManager(BackendAction Action, - std::unique_ptr OS); }; // We need this wrapper to access LangOpts and CGOpts from extension functions @@ -234,6 +247,8 @@ getSancovOptsFromCGOpts(const CodeGenOptions &CGOpts) { Opts.InlineBoolFlag = CGOpts.SanitizeCoverageInlineBoolFlag; Opts.PCTable = CGOpts.SanitizeCoveragePCTable; Opts.StackDepth = CGOpts.SanitizeCoverageStackDepth; + Opts.TraceLoads = CGOpts.SanitizeCoverageTraceLoads; + Opts.TraceStores = CGOpts.SanitizeCoverageTraceStores; return Opts; } @@ -474,6 +489,11 @@ static CodeGenFileType getCodeGenFileType(BackendAction Action) { } } +static bool actionRequiresCodeGen(BackendAction Action) { + return Action != Backend_EmitNothing && Action != Backend_EmitBC && + Action != Backend_EmitLL; +} + static bool initTargetOptions(DiagnosticsEngine &Diags, llvm::TargetOptions &Options, const CodeGenOptions &CodeGenOpts, @@ -539,6 +559,7 @@ static bool initTargetOptions(DiagnosticsEngine &Diags, Options.NoNaNsFPMath = LangOpts.NoHonorNaNs; Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; Options.UnsafeFPMath = LangOpts.UnsafeFPMath; + Options.ApproxFuncFPMath = LangOpts.ApproxFunc; Options.BBSections = llvm::StringSwitch(CodeGenOpts.BBSections) @@ -576,10 +597,25 @@ static bool initTargetOptions(DiagnosticsEngine &Diags, Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection; Options.EmitCallSiteInfo = CodeGenOpts.EmitCallSiteInfo; Options.EnableAIXExtendedAltivecABI = CodeGenOpts.EnableAIXExtendedAltivecABI; - Options.PseudoProbeForProfiling = CodeGenOpts.PseudoProbeForProfiling; Options.ValueTrackingVariableLocations = CodeGenOpts.ValueTrackingVariableLocations; Options.XRayOmitFunctionIndex = CodeGenOpts.XRayOmitFunctionIndex; + Options.LoopAlignment = CodeGenOpts.LoopAlignment; + + switch (CodeGenOpts.getSwiftAsyncFramePointer()) { + case CodeGenOptions::SwiftAsyncFramePointerKind::Auto: + Options.SwiftAsyncFramePointer = + SwiftAsyncFramePointerMode::DeploymentBased; + break; + + case CodeGenOptions::SwiftAsyncFramePointerKind::Always: + Options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Always; + break; + + case CodeGenOptions::SwiftAsyncFramePointerKind::Never: + Options.SwiftAsyncFramePointer = SwiftAsyncFramePointerMode::Never; + break; + } Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile; Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll; @@ -942,15 +978,13 @@ bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses, return true; } -void EmitAssemblyHelper::EmitAssembly(BackendAction Action, - std::unique_ptr OS) { +void EmitAssemblyHelper::EmitAssemblyWithLegacyPassManager( + BackendAction Action, std::unique_ptr OS) { TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr); setCommandLineOpts(CodeGenOpts); - bool UsesCodeGen = (Action != Backend_EmitNothing && - Action != Backend_EmitBC && - Action != Backend_EmitLL); + bool UsesCodeGen = actionRequiresCodeGen(Action); CreateTargetMachine(UsesCodeGen); if (UsesCodeGen && !TM) @@ -977,6 +1011,12 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, CreatePasses(PerModulePasses, PerFunctionPasses); + // Add a verifier pass if requested. We don't have to do this if the action + // requires code generation because there will already be a verifier pass in + // the code-generation pipeline. + if (!UsesCodeGen && CodeGenOpts.VerifyModule) + PerModulePasses.add(createVerifierPass()); + legacy::PassManager CodeGenPasses; CodeGenPasses.add( createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); @@ -1069,16 +1109,16 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, DwoOS->keep(); } -static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) { +static OptimizationLevel mapToLevel(const CodeGenOptions &Opts) { switch (Opts.OptimizationLevel) { default: llvm_unreachable("Invalid optimization level!"); case 0: - return PassBuilder::OptimizationLevel::O0; + return OptimizationLevel::O0; case 1: - return PassBuilder::OptimizationLevel::O1; + return OptimizationLevel::O1; case 2: switch (Opts.OptimizeSize) { @@ -1086,17 +1126,17 @@ static PassBuilder::OptimizationLevel mapToLevel(const CodeGenOptions &Opts) { llvm_unreachable("Invalid optimization level for size!"); case 0: - return PassBuilder::OptimizationLevel::O2; + return OptimizationLevel::O2; case 1: - return PassBuilder::OptimizationLevel::Os; + return OptimizationLevel::Os; case 2: - return PassBuilder::OptimizationLevel::Oz; + return OptimizationLevel::Oz; } case 3: - return PassBuilder::OptimizationLevel::O3; + return OptimizationLevel::O3; } } @@ -1104,7 +1144,7 @@ static void addSanitizers(const Triple &TargetTriple, const CodeGenOptions &CodeGenOpts, const LangOptions &LangOpts, PassBuilder &PB) { PB.registerOptimizerLastEPCallback([&](ModulePassManager &MPM, - PassBuilder::OptimizationLevel Level) { + OptimizationLevel Level) { if (CodeGenOpts.hasSanitizeCoverage()) { auto SancovOpts = getSancovOptsFromCGOpts(CodeGenOpts); MPM.addPass(ModuleSanitizerCoveragePass( @@ -1118,11 +1158,11 @@ static void addSanitizers(const Triple &TargetTriple, bool Recover = CodeGenOpts.SanitizeRecover.has(Mask); MPM.addPass( - MemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); + ModuleMemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); FunctionPassManager FPM; FPM.addPass( MemorySanitizerPass({TrackOrigins, Recover, CompileKernel})); - if (Level != PassBuilder::OptimizationLevel::O0) { + if (Level != OptimizationLevel::O0) { // MemorySanitizer inserts complex instrumentation that mostly // follows the logic of the original code, but operates on // "shadow" values. It can benefit from re-running some @@ -1141,26 +1181,24 @@ static void addSanitizers(const Triple &TargetTriple, MSanPass(SanitizerKind::KernelMemory, true); if (LangOpts.Sanitize.has(SanitizerKind::Thread)) { - MPM.addPass(ThreadSanitizerPass()); + MPM.addPass(ModuleThreadSanitizerPass()); MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); } auto ASanPass = [&](SanitizerMask Mask, bool CompileKernel) { if (LangOpts.Sanitize.has(Mask)) { - bool Recover = CodeGenOpts.SanitizeRecover.has(Mask); - bool UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope; - bool ModuleUseAfterScope = asanUseGlobalsGC(TargetTriple, CodeGenOpts); + bool UseGlobalGC = asanUseGlobalsGC(TargetTriple, CodeGenOpts); bool UseOdrIndicator = CodeGenOpts.SanitizeAddressUseOdrIndicator; llvm::AsanDtorKind DestructorKind = CodeGenOpts.getSanitizeAddressDtor(); - llvm::AsanDetectStackUseAfterReturnMode UseAfterReturn = - CodeGenOpts.getSanitizeAddressUseAfterReturn(); + AddressSanitizerOptions Opts; + Opts.CompileKernel = CompileKernel; + Opts.Recover = CodeGenOpts.SanitizeRecover.has(Mask); + Opts.UseAfterScope = CodeGenOpts.SanitizeAddressUseAfterScope; + Opts.UseAfterReturn = CodeGenOpts.getSanitizeAddressUseAfterReturn(); MPM.addPass(RequireAnalysisPass()); MPM.addPass(ModuleAddressSanitizerPass( - CompileKernel, Recover, ModuleUseAfterScope, UseOdrIndicator, - DestructorKind)); - MPM.addPass(createModuleToFunctionPassAdaptor(AddressSanitizerPass( - CompileKernel, Recover, UseAfterScope, UseAfterReturn))); + Opts, UseGlobalGC, UseOdrIndicator, DestructorKind)); } }; ASanPass(SanitizerKind::Address, false); @@ -1170,8 +1208,8 @@ static void addSanitizers(const Triple &TargetTriple, if (LangOpts.Sanitize.has(Mask)) { bool Recover = CodeGenOpts.SanitizeRecover.has(Mask); MPM.addPass(HWAddressSanitizerPass( - CompileKernel, Recover, - /*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0)); + {CompileKernel, Recover, + /*DisableOptimization=*/CodeGenOpts.OptimizationLevel == 0})); } }; HWASanPass(SanitizerKind::HWAddress, false); @@ -1183,29 +1221,9 @@ static void addSanitizers(const Triple &TargetTriple, }); } -/// A clean version of `EmitAssembly` that uses the new pass manager. -/// -/// Not all features are currently supported in this system, but where -/// necessary it falls back to the legacy pass manager to at least provide -/// basic functionality. -/// -/// This API is planned to have its functionality finished and then to replace -/// `EmitAssembly` at some point in the future when the default switches. -void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( - BackendAction Action, std::unique_ptr OS) { - TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr); - setCommandLineOpts(CodeGenOpts); - - bool RequiresCodeGen = (Action != Backend_EmitNothing && - Action != Backend_EmitBC && - Action != Backend_EmitLL); - CreateTargetMachine(RequiresCodeGen); - - if (RequiresCodeGen && !TM) - return; - if (TM) - TheModule->setDataLayout(TM->createDataLayout()); - +void EmitAssemblyHelper::RunOptimizationPipeline( + BackendAction Action, std::unique_ptr &OS, + std::unique_ptr &ThinLinkOS) { Optional PGOOpt; if (CodeGenOpts.hasProfileIRInstr()) @@ -1260,6 +1278,8 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( "", PGOOptions::NoAction, PGOOptions::CSIRInstr, CodeGenOpts.DebugInfoForProfiling); } + if (TM) + TM->setPGOOption(PGOOpt); PipelineTuningOptions PTO; PTO.LoopUnrolling = CodeGenOpts.UnrollLoops; @@ -1303,9 +1323,6 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); #include "llvm/Support/Extension.def" - // Register the AA manager first so that our version is the one used. - FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); - // Register the target library analysis directly and give it a customized // preset TLI. Triple TargetTriple(TheModule->getTargetTriple()); @@ -1325,26 +1342,26 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( if (!CodeGenOpts.DisableLLVMPasses) { // Map our optimization levels into one of the distinct levels used to // configure the pipeline. - PassBuilder::OptimizationLevel Level = mapToLevel(CodeGenOpts); + OptimizationLevel Level = mapToLevel(CodeGenOpts); bool IsThinLTO = CodeGenOpts.PrepareForThinLTO; bool IsLTO = CodeGenOpts.PrepareForLTO; if (LangOpts.ObjCAutoRefCount) { PB.registerPipelineStartEPCallback( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - if (Level != PassBuilder::OptimizationLevel::O0) + [](ModulePassManager &MPM, OptimizationLevel Level) { + if (Level != OptimizationLevel::O0) MPM.addPass( createModuleToFunctionPassAdaptor(ObjCARCExpandPass())); }); PB.registerPipelineEarlySimplificationEPCallback( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { - if (Level != PassBuilder::OptimizationLevel::O0) + [](ModulePassManager &MPM, OptimizationLevel Level) { + if (Level != OptimizationLevel::O0) MPM.addPass(ObjCARCAPElimPass()); }); PB.registerScalarOptimizerLateEPCallback( - [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { - if (Level != PassBuilder::OptimizationLevel::O0) + [](FunctionPassManager &FPM, OptimizationLevel Level) { + if (Level != OptimizationLevel::O0) FPM.addPass(ObjCARCOptPass()); }); } @@ -1357,7 +1374,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // vtables so that codegen doesn't complain. if (IsThinLTOPostLink) PB.registerPipelineStartEPCallback( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + [](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(LowerTypeTestsPass(/*ExportSummary=*/nullptr, /*ImportSummary=*/nullptr, /*DropTypeTests=*/true)); @@ -1368,12 +1385,12 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( CodeGenOpts.InstrumentFunctionsAfterInlining || CodeGenOpts.InstrumentForProfiling) { PB.registerPipelineStartEPCallback( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + [](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(createModuleToFunctionPassAdaptor( EntryExitInstrumenterPass(/*PostInlining=*/false))); }); PB.registerOptimizerLastEPCallback( - [](ModulePassManager &MPM, PassBuilder::OptimizationLevel Level) { + [](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(createModuleToFunctionPassAdaptor( EntryExitInstrumenterPass(/*PostInlining=*/true))); }); @@ -1383,7 +1400,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // of the pipeline. if (LangOpts.Sanitize.has(SanitizerKind::LocalBounds)) PB.registerScalarOptimizerLateEPCallback( - [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) { + [](FunctionPassManager &FPM, OptimizationLevel Level) { FPM.addPass(BoundsCheckingPass()); }); @@ -1394,15 +1411,13 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( if (Optional Options = getGCOVOptions(CodeGenOpts, LangOpts)) PB.registerPipelineStartEPCallback( - [Options](ModulePassManager &MPM, - PassBuilder::OptimizationLevel Level) { + [Options](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(GCOVProfilerPass(*Options)); }); if (Optional Options = getInstrProfOptions(CodeGenOpts, LangOpts)) PB.registerPipelineStartEPCallback( - [Options](ModulePassManager &MPM, - PassBuilder::OptimizationLevel Level) { + [Options](ModulePassManager &MPM, OptimizationLevel Level) { MPM.addPass(InstrProfiling(*Options, false)); }); @@ -1422,17 +1437,13 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( } } - // FIXME: We still use the legacy pass manager to do code generation. We - // create that pass manager here and use it as needed below. - legacy::PassManager CodeGenPasses; - bool NeedCodeGen = false; - std::unique_ptr ThinLinkOS, DwoOS; + // Add a verifier pass if requested. We don't have to do this if the action + // requires code generation because there will already be a verifier pass in + // the code-generation pipeline. + if (!actionRequiresCodeGen(Action) && CodeGenOpts.VerifyModule) + MPM.addPass(VerifierPass()); - // Append any output we need to the pass manager. switch (Action) { - case Backend_EmitNothing: - break; - case Backend_EmitBC: if (CodeGenOpts.PrepareForThinLTO && !CodeGenOpts.DisableLLVMPasses) { if (!CodeGenOpts.ThinLinkBitcodeFile.empty()) { @@ -1448,8 +1459,7 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // Emit a module summary by default for Regular LTO except for ld64 // targets bool EmitLTOSummary = - (CodeGenOpts.PrepareForLTO && - !CodeGenOpts.DisableLLVMPasses && + (CodeGenOpts.PrepareForLTO && !CodeGenOpts.DisableLLVMPasses && llvm::Triple(TheModule->getTargetTriple()).getVendor() != llvm::Triple::Apple); if (EmitLTOSummary) { @@ -1467,10 +1477,28 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( MPM.addPass(PrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists)); break; + default: + break; + } + + // Now that we have all of the passes ready, run them. + PrettyStackTraceString CrashInfo("Optimizer"); + MPM.run(*TheModule, MAM); +} + +void EmitAssemblyHelper::RunCodegenPipeline( + BackendAction Action, std::unique_ptr &OS, + std::unique_ptr &DwoOS) { + // We still use the legacy PM to run the codegen pipeline since the new PM + // does not work with the codegen pipeline. + // FIXME: make the new PM work with the codegen pipeline. + legacy::PassManager CodeGenPasses; + + // Append any output we need to the pass manager. + switch (Action) { case Backend_EmitAssembly: case Backend_EmitMCNull: case Backend_EmitObj: - NeedCodeGen = true; CodeGenPasses.add( createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); if (!CodeGenOpts.SplitDwarfOutput.empty()) { @@ -1483,22 +1511,41 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( // FIXME: Should we handle this error differently? return; break; + default: + return; } + PrettyStackTraceString CrashInfo("Code generation"); + CodeGenPasses.run(*TheModule); +} + +/// A clean version of `EmitAssembly` that uses the new pass manager. +/// +/// Not all features are currently supported in this system, but where +/// necessary it falls back to the legacy pass manager to at least provide +/// basic functionality. +/// +/// This API is planned to have its functionality finished and then to replace +/// `EmitAssembly` at some point in the future when the default switches. +void EmitAssemblyHelper::EmitAssembly(BackendAction Action, + std::unique_ptr OS) { + TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : nullptr); + setCommandLineOpts(CodeGenOpts); + + bool RequiresCodeGen = actionRequiresCodeGen(Action); + CreateTargetMachine(RequiresCodeGen); + + if (RequiresCodeGen && !TM) + return; + if (TM) + TheModule->setDataLayout(TM->createDataLayout()); + // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); - // Now that we have all of the passes ready, run them. - { - PrettyStackTraceString CrashInfo("Optimizer"); - MPM.run(*TheModule, MAM); - } - - // Now if needed, run the legacy PM for codegen. - if (NeedCodeGen) { - PrettyStackTraceString CrashInfo("Code generation"); - CodeGenPasses.run(*TheModule); - } + std::unique_ptr ThinLinkOS, DwoOS; + RunOptimizationPipeline(Action, OS, ThinLinkOS); + RunCodegenPipeline(Action, OS, DwoOS); if (ThinLinkOS) ThinLinkOS->keep(); @@ -1526,7 +1573,7 @@ static void runThinLTOBackend( return; auto AddStream = [&](size_t Task) { - return std::make_unique(std::move(OS)); + return std::make_unique(std::move(OS)); }; lto::Config Conf; if (CGOpts.SaveTempsFilePrefix != "") { @@ -1622,16 +1669,17 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, // If we are performing a ThinLTO importing compile, load the function index // into memory and pass it into runThinLTOBackend, which will run the // function importer and invoke LTO passes. - Expected> IndexOrErr = - llvm::getModuleSummaryIndexForFile(CGOpts.ThinLTOIndexFile, - /*IgnoreEmptyThinLTOIndexFile*/true); - if (!IndexOrErr) { - logAllUnhandledErrors(IndexOrErr.takeError(), errs(), + std::unique_ptr CombinedIndex; + if (Error E = llvm::getModuleSummaryIndexForFile( + CGOpts.ThinLTOIndexFile, + /*IgnoreEmptyThinLTOIndexFile*/ true) + .moveInto(CombinedIndex)) { + logAllUnhandledErrors(std::move(E), errs(), "Error loading index file '" + CGOpts.ThinLTOIndexFile + "': "); return; } - std::unique_ptr CombinedIndex = std::move(*IndexOrErr); + // A null CombinedIndex means we should skip ThinLTO compilation // (LLVM will optionally ignore empty index files, returning null instead // of an error). @@ -1656,8 +1704,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, EmitAssemblyHelper AsmHelper(Diags, HeaderOpts, CGOpts, TOpts, LOpts, M); - if (!CGOpts.LegacyPassManager) - AsmHelper.EmitAssemblyWithNewPassManager(Action, std::move(OS)); + if (CGOpts.LegacyPassManager) + AsmHelper.EmitAssemblyWithLegacyPassManager(Action, std::move(OS)); else AsmHelper.EmitAssembly(Action, std::move(OS)); diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index b6722ad4e4f..326ca8d5053 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -664,6 +664,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, case AtomicExpr::AO__atomic_nand_fetch: PostOp = llvm::Instruction::And; // the NOT is special cased below LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__atomic_fetch_nand: Op = llvm::AtomicRMWInst::Nand; break; @@ -906,6 +907,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_and: @@ -972,6 +974,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_or: + case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__atomic_fetch_nand: case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_sub: @@ -1211,6 +1214,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__atomic_nand_fetch: PostOp = llvm::Instruction::And; // the NOT is special cased below LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__atomic_fetch_nand: LibCallName = "__atomic_fetch_nand"; AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index f39a56f81d4..2da2014345d 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -2695,8 +2695,8 @@ const BlockByrefInfo &CodeGenFunction::getBlockByrefInfo(const VarDecl *D) { size = varOffset; // Conversely, we might have to prevent LLVM from inserting padding. - } else if (CGM.getDataLayout().getABITypeAlignment(varTy) - > varAlign.getQuantity()) { + } else if (CGM.getDataLayout().getABITypeAlignment(varTy) > + uint64_t(varAlign.getQuantity())) { packed = true; } types.push_back(varTy); @@ -2910,8 +2910,8 @@ llvm::Constant *CodeGenModule::getNSConcreteGlobalBlock() { if (NSConcreteGlobalBlock) return NSConcreteGlobalBlock; - NSConcreteGlobalBlock = - GetOrCreateLLVMGlobal("_NSConcreteGlobalBlock", Int8PtrTy, 0, nullptr); + NSConcreteGlobalBlock = GetOrCreateLLVMGlobal( + "_NSConcreteGlobalBlock", Int8PtrTy, LangAS::Default, nullptr); configureBlocksRuntimeObject(*this, NSConcreteGlobalBlock); return NSConcreteGlobalBlock; } @@ -2920,8 +2920,8 @@ llvm::Constant *CodeGenModule::getNSConcreteStackBlock() { if (NSConcreteStackBlock) return NSConcreteStackBlock; - NSConcreteStackBlock = - GetOrCreateLLVMGlobal("_NSConcreteStackBlock", Int8PtrTy, 0, nullptr); + NSConcreteStackBlock = GetOrCreateLLVMGlobal( + "_NSConcreteStackBlock", Int8PtrTy, LangAS::Default, nullptr); configureBlocksRuntimeObject(*this, NSConcreteStackBlock); return NSConcreteStackBlock; } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d9b2a5fe16b..849423c8b9b 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3101,6 +3101,88 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(V); } + case Builtin::BI__builtin_elementwise_abs: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Result; + if (Op0->getType()->isIntOrIntVectorTy()) + Result = Builder.CreateBinaryIntrinsic( + llvm::Intrinsic::abs, Op0, Builder.getFalse(), nullptr, "elt.abs"); + else + Result = Builder.CreateUnaryIntrinsic(llvm::Intrinsic::fabs, Op0, nullptr, + "elt.abs"); + return RValue::get(Result); + } + case Builtin::BI__builtin_elementwise_max: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Op1 = EmitScalarExpr(E->getArg(1)); + Value *Result; + if (Op0->getType()->isIntOrIntVectorTy()) { + QualType Ty = E->getArg(0)->getType(); + if (auto *VecTy = Ty->getAs()) + Ty = VecTy->getElementType(); + Result = Builder.CreateBinaryIntrinsic(Ty->isSignedIntegerType() + ? llvm::Intrinsic::smax + : llvm::Intrinsic::umax, + Op0, Op1, nullptr, "elt.max"); + } else + Result = Builder.CreateMaxNum(Op0, Op1, "elt.max"); + return RValue::get(Result); + } + case Builtin::BI__builtin_elementwise_min: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Op1 = EmitScalarExpr(E->getArg(1)); + Value *Result; + if (Op0->getType()->isIntOrIntVectorTy()) { + QualType Ty = E->getArg(0)->getType(); + if (auto *VecTy = Ty->getAs()) + Ty = VecTy->getElementType(); + Result = Builder.CreateBinaryIntrinsic(Ty->isSignedIntegerType() + ? llvm::Intrinsic::smin + : llvm::Intrinsic::umin, + Op0, Op1, nullptr, "elt.min"); + } else + Result = Builder.CreateMinNum(Op0, Op1, "elt.min"); + return RValue::get(Result); + } + + case Builtin::BI__builtin_reduce_max: { + auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) { + if (IrTy->isIntOrIntVectorTy()) { + if (auto *VecTy = QT->getAs()) + QT = VecTy->getElementType(); + if (QT->isSignedIntegerType()) + return llvm::Intrinsic::vector_reduce_smax; + else + return llvm::Intrinsic::vector_reduce_umax; + } + return llvm::Intrinsic::vector_reduce_fmax; + }; + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Result = Builder.CreateUnaryIntrinsic( + GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr, + "rdx.min"); + return RValue::get(Result); + } + + case Builtin::BI__builtin_reduce_min: { + auto GetIntrinsicID = [](QualType QT, llvm::Type *IrTy) { + if (IrTy->isIntOrIntVectorTy()) { + if (auto *VecTy = QT->getAs()) + QT = VecTy->getElementType(); + if (QT->isSignedIntegerType()) + return llvm::Intrinsic::vector_reduce_smin; + else + return llvm::Intrinsic::vector_reduce_umin; + } + return llvm::Intrinsic::vector_reduce_fmin; + }; + Value *Op0 = EmitScalarExpr(E->getArg(0)); + Value *Result = Builder.CreateUnaryIntrinsic( + GetIntrinsicID(E->getArg(0)->getType(), Op0->getType()), Op0, nullptr, + "rdx.min"); + return RValue::get(Result); + } + case Builtin::BI__builtin_matrix_transpose: { const auto *MatrixTy = E->getArg(0)->getType()->getAs(); Value *MatValue = EmitScalarExpr(E->getArg(0)); @@ -5024,11 +5106,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Builder.CreateFPExt(HalfVal, Builder.getFloatTy())); } case Builtin::BIprintf: - if (getTarget().getTriple().isNVPTX()) - return EmitNVPTXDevicePrintfCallExpr(E, ReturnValue); - if (getTarget().getTriple().getArch() == Triple::amdgcn && - getLangOpts().HIP) - return EmitAMDGPUDevicePrintfCallExpr(E, ReturnValue); + if (getTarget().getTriple().isNVPTX() || + getTarget().getTriple().isAMDGCN()) { + if (getLangOpts().OpenMPIsDevice) + return EmitOpenMPDevicePrintfCallExpr(E); + if (getTarget().getTriple().isNVPTX()) + return EmitNVPTXDevicePrintfCallExpr(E); + if (getTarget().getTriple().isAMDGCN() && getLangOpts().HIP) + return EmitAMDGPUDevicePrintfCallExpr(E); + } + break; case Builtin::BI__builtin_canonicalize: case Builtin::BI__builtin_canonicalizef: @@ -8399,7 +8486,7 @@ Value *CodeGenFunction::vectorWrapScalar16(Value *Op) { /// SVEBuiltinMemEltTy - Returns the memory element type for this memory /// access builtin. Only required if it can't be inferred from the base pointer /// operand. -llvm::Type *CodeGenFunction::SVEBuiltinMemEltTy(SVETypeFlags TypeFlags) { +llvm::Type *CodeGenFunction::SVEBuiltinMemEltTy(const SVETypeFlags &TypeFlags) { switch (TypeFlags.getMemEltType()) { case SVETypeFlags::MemEltTyDefault: return getEltType(TypeFlags); @@ -8415,7 +8502,7 @@ llvm::Type *CodeGenFunction::SVEBuiltinMemEltTy(SVETypeFlags TypeFlags) { llvm_unreachable("Unknown MemEltType"); } -llvm::Type *CodeGenFunction::getEltType(SVETypeFlags TypeFlags) { +llvm::Type *CodeGenFunction::getEltType(const SVETypeFlags &TypeFlags) { switch (TypeFlags.getEltType()) { default: llvm_unreachable("Invalid SVETypeFlag!"); @@ -8450,7 +8537,7 @@ llvm::Type *CodeGenFunction::getEltType(SVETypeFlags TypeFlags) { // Return the llvm predicate vector type corresponding to the specified element // TypeFlags. llvm::ScalableVectorType * -CodeGenFunction::getSVEPredType(SVETypeFlags TypeFlags) { +CodeGenFunction::getSVEPredType(const SVETypeFlags &TypeFlags) { switch (TypeFlags.getEltType()) { default: llvm_unreachable("Unhandled SVETypeFlag!"); @@ -8519,7 +8606,8 @@ CodeGenFunction::getSVEType(const SVETypeFlags &TypeFlags) { } } -llvm::Value *CodeGenFunction::EmitSVEAllTruePred(SVETypeFlags TypeFlags) { +llvm::Value * +CodeGenFunction::EmitSVEAllTruePred(const SVETypeFlags &TypeFlags) { Function *Ptrue = CGM.getIntrinsic(Intrinsic::aarch64_sve_ptrue, getSVEPredType(TypeFlags)); return Builder.CreateCall(Ptrue, {Builder.getInt32(/*SV_ALL*/ 31)}); @@ -8563,7 +8651,7 @@ Value *CodeGenFunction::EmitSVEPredicateCast(Value *Pred, return C; } -Value *CodeGenFunction::EmitSVEGatherLoad(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID) { auto *ResultTy = getSVEType(TypeFlags); @@ -8615,7 +8703,7 @@ Value *CodeGenFunction::EmitSVEGatherLoad(SVETypeFlags TypeFlags, : Builder.CreateSExt(Call, ResultTy); } -Value *CodeGenFunction::EmitSVEScatterStore(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEScatterStore(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID) { auto *SrcDataTy = getSVEType(TypeFlags); @@ -8670,7 +8758,7 @@ Value *CodeGenFunction::EmitSVEScatterStore(SVETypeFlags TypeFlags, return Builder.CreateCall(F, Ops); } -Value *CodeGenFunction::EmitSVEGatherPrefetch(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEGatherPrefetch(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID) { // The gather prefetches are overloaded on the vector input - this can either @@ -8703,7 +8791,7 @@ Value *CodeGenFunction::EmitSVEGatherPrefetch(SVETypeFlags TypeFlags, return Builder.CreateCall(F, Ops); } -Value *CodeGenFunction::EmitSVEStructLoad(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEStructLoad(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID) { llvm::ScalableVectorType *VTy = getSVEType(TypeFlags); @@ -8737,7 +8825,7 @@ Value *CodeGenFunction::EmitSVEStructLoad(SVETypeFlags TypeFlags, return Builder.CreateCall(F, { Predicate, BasePtr }); } -Value *CodeGenFunction::EmitSVEStructStore(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEStructStore(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID) { llvm::ScalableVectorType *VTy = getSVEType(TypeFlags); @@ -8784,7 +8872,7 @@ Value *CodeGenFunction::EmitSVEStructStore(SVETypeFlags TypeFlags, // SVE2's svpmullb and svpmullt builtins are similar to the svpmullb_pair and // svpmullt_pair intrinsics, with the exception that their results are bitcast // to a wider type. -Value *CodeGenFunction::EmitSVEPMull(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEPMull(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned BuiltinID) { // Splat scalar operand to vector (intrinsics with _n infix) @@ -8802,14 +8890,14 @@ Value *CodeGenFunction::EmitSVEPMull(SVETypeFlags TypeFlags, return EmitSVEReinterpret(Call, Ty); } -Value *CodeGenFunction::EmitSVEMovl(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEMovl(const SVETypeFlags &TypeFlags, ArrayRef Ops, unsigned BuiltinID) { llvm::Type *OverloadedTy = getSVEType(TypeFlags); Function *F = CGM.getIntrinsic(BuiltinID, OverloadedTy); return Builder.CreateCall(F, {Ops[0], Builder.getInt32(0)}); } -Value *CodeGenFunction::EmitSVEPrefetchLoad(SVETypeFlags TypeFlags, +Value *CodeGenFunction::EmitSVEPrefetchLoad(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned BuiltinID) { auto *MemEltTy = SVEBuiltinMemEltTy(TypeFlags); @@ -8918,8 +9006,10 @@ static void InsertExplicitUndefOperand(CGBuilderTy &Builder, llvm::Type *Ty, Ops.insert(Ops.begin(), SplatUndef); } -SmallVector CodeGenFunction::getSVEOverloadTypes( - SVETypeFlags TypeFlags, llvm::Type *ResultType, ArrayRef Ops) { +SmallVector +CodeGenFunction::getSVEOverloadTypes(const SVETypeFlags &TypeFlags, + llvm::Type *ResultType, + ArrayRef Ops) { if (TypeFlags.isOverloadNone()) return {}; @@ -9732,6 +9822,29 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F); } + if (BuiltinID == AArch64::BI__mulh || BuiltinID == AArch64::BI__umulh) { + llvm::Type *ResType = ConvertType(E->getType()); + llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128); + + bool IsSigned = BuiltinID == AArch64::BI__mulh; + Value *LHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(0)), Int128Ty, IsSigned); + Value *RHS = + Builder.CreateIntCast(EmitScalarExpr(E->getArg(1)), Int128Ty, IsSigned); + + Value *MulResult, *HigherBits; + if (IsSigned) { + MulResult = Builder.CreateNSWMul(LHS, RHS); + HigherBits = Builder.CreateAShr(MulResult, 64); + } else { + MulResult = Builder.CreateNUWMul(LHS, RHS); + HigherBits = Builder.CreateLShr(MulResult, 64); + } + HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned); + + return HigherBits; + } + // Handle MSVC intrinsics before argument evaluation to prevent double // evaluation. if (Optional MsvcIntId = translateAarch64ToMsvcIntrin(BuiltinID)) @@ -12044,6 +12157,22 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E, Intrinsic::ID IID = Intrinsic::not_intrinsic; switch (BuiltinID) { default: break; + case clang::X86::BI__builtin_ia32_vfmsubph512_mask3: + Subtract = true; + LLVM_FALLTHROUGH; + case clang::X86::BI__builtin_ia32_vfmaddph512_mask: + case clang::X86::BI__builtin_ia32_vfmaddph512_maskz: + case clang::X86::BI__builtin_ia32_vfmaddph512_mask3: + IID = llvm::Intrinsic::x86_avx512fp16_vfmadd_ph_512; + break; + case clang::X86::BI__builtin_ia32_vfmsubaddph512_mask3: + Subtract = true; + LLVM_FALLTHROUGH; + case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask: + case clang::X86::BI__builtin_ia32_vfmaddsubph512_maskz: + case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask3: + IID = llvm::Intrinsic::x86_avx512fp16_vfmaddsub_ph_512; + break; case clang::X86::BI__builtin_ia32_vfmsubps512_mask3: Subtract = true; LLVM_FALLTHROUGH; @@ -12107,22 +12236,30 @@ static Value *EmitX86FMAExpr(CodeGenFunction &CGF, const CallExpr *E, // Handle any required masking. Value *MaskFalseVal = nullptr; switch (BuiltinID) { + case clang::X86::BI__builtin_ia32_vfmaddph512_mask: case clang::X86::BI__builtin_ia32_vfmaddps512_mask: case clang::X86::BI__builtin_ia32_vfmaddpd512_mask: + case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask: case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask: case clang::X86::BI__builtin_ia32_vfmaddsubpd512_mask: MaskFalseVal = Ops[0]; break; + case clang::X86::BI__builtin_ia32_vfmaddph512_maskz: case clang::X86::BI__builtin_ia32_vfmaddps512_maskz: case clang::X86::BI__builtin_ia32_vfmaddpd512_maskz: + case clang::X86::BI__builtin_ia32_vfmaddsubph512_maskz: case clang::X86::BI__builtin_ia32_vfmaddsubps512_maskz: case clang::X86::BI__builtin_ia32_vfmaddsubpd512_maskz: MaskFalseVal = Constant::getNullValue(Ops[0]->getType()); break; + case clang::X86::BI__builtin_ia32_vfmsubph512_mask3: + case clang::X86::BI__builtin_ia32_vfmaddph512_mask3: case clang::X86::BI__builtin_ia32_vfmsubps512_mask3: case clang::X86::BI__builtin_ia32_vfmaddps512_mask3: case clang::X86::BI__builtin_ia32_vfmsubpd512_mask3: case clang::X86::BI__builtin_ia32_vfmaddpd512_mask3: + case clang::X86::BI__builtin_ia32_vfmsubaddph512_mask3: + case clang::X86::BI__builtin_ia32_vfmaddsubph512_mask3: case clang::X86::BI__builtin_ia32_vfmsubaddps512_mask3: case clang::X86::BI__builtin_ia32_vfmaddsubps512_mask3: case clang::X86::BI__builtin_ia32_vfmsubaddpd512_mask3: @@ -12153,9 +12290,21 @@ static Value *EmitScalarFMAExpr(CodeGenFunction &CGF, const CallExpr *E, Ops[2] = CGF.Builder.CreateExtractElement(Ops[2], (uint64_t)0); Value *Res; if (Rnd != 4) { - Intrinsic::ID IID = Ops[0]->getType()->getPrimitiveSizeInBits() == 32 ? - Intrinsic::x86_avx512_vfmadd_f32 : - Intrinsic::x86_avx512_vfmadd_f64; + Intrinsic::ID IID; + + switch (Ops[0]->getType()->getPrimitiveSizeInBits()) { + case 16: + IID = Intrinsic::x86_avx512fp16_vfmadd_f16; + break; + case 32: + IID = Intrinsic::x86_avx512_vfmadd_f32; + break; + case 64: + IID = Intrinsic::x86_avx512_vfmadd_f64; + break; + default: + llvm_unreachable("Unexpected size"); + } Res = CGF.Builder.CreateCall(CGF.CGM.getIntrinsic(IID), {Ops[0], Ops[1], Ops[2], Ops[4]}); } else if (CGF.Builder.getIsFPConstrained()) { @@ -12362,23 +12511,8 @@ Value *CodeGenFunction::EmitX86CpuSupports(const CallExpr *E) { return EmitX86CpuSupports(FeatureStr); } -uint64_t -CodeGenFunction::GetX86CpuSupportsMask(ArrayRef FeatureStrs) { - // Processor features and mapping to processor feature value. - uint64_t FeaturesMask = 0; - for (const StringRef &FeatureStr : FeatureStrs) { - unsigned Feature = - StringSwitch(FeatureStr) -#define X86_FEATURE_COMPAT(ENUM, STR) .Case(STR, llvm::X86::FEATURE_##ENUM) -#include "llvm/Support/X86TargetParser.def" - ; - FeaturesMask |= (1ULL << Feature); - } - return FeaturesMask; -} - Value *CodeGenFunction::EmitX86CpuSupports(ArrayRef FeatureStrs) { - return EmitX86CpuSupports(GetX86CpuSupportsMask(FeatureStrs)); + return EmitX86CpuSupports(llvm::X86::getCpuSupportsMask(FeatureStrs)); } llvm::Value *CodeGenFunction::EmitX86CpuSupports(uint64_t FeaturesMask) { @@ -12461,6 +12595,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, SmallVector Ops; bool IsMaskFCmp = false; + bool IsConjFMA = false; // Find out if any arguments are required to be integer constant expressions. unsigned ICEArguments = 0; @@ -12691,6 +12826,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_storeups512_mask: return EmitX86MaskedStore(*this, Ops, Align(1)); + case X86::BI__builtin_ia32_storesh128_mask: case X86::BI__builtin_ia32_storess128_mask: case X86::BI__builtin_ia32_storesd128_mask: return EmitX86MaskedStore(*this, Ops, Align(1)); @@ -12742,14 +12878,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_cvtdq2ps512_mask: case X86::BI__builtin_ia32_cvtqq2ps512_mask: case X86::BI__builtin_ia32_cvtqq2pd512_mask: + case X86::BI__builtin_ia32_vcvtw2ph512_mask: + case X86::BI__builtin_ia32_vcvtdq2ph512_mask: + case X86::BI__builtin_ia32_vcvtqq2ph512_mask: return EmitX86ConvertIntToFp(*this, E, Ops, /*IsSigned*/ true); case X86::BI__builtin_ia32_cvtudq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2pd512_mask: + case X86::BI__builtin_ia32_vcvtuw2ph512_mask: + case X86::BI__builtin_ia32_vcvtudq2ph512_mask: + case X86::BI__builtin_ia32_vcvtuqq2ph512_mask: return EmitX86ConvertIntToFp(*this, E, Ops, /*IsSigned*/ false); case X86::BI__builtin_ia32_vfmaddss3: case X86::BI__builtin_ia32_vfmaddsd3: + case X86::BI__builtin_ia32_vfmaddsh3_mask: case X86::BI__builtin_ia32_vfmaddss3_mask: case X86::BI__builtin_ia32_vfmaddsd3_mask: return EmitScalarFMAExpr(*this, E, Ops, Ops[0]); @@ -12757,20 +12900,28 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_vfmaddsd: return EmitScalarFMAExpr(*this, E, Ops, Constant::getNullValue(Ops[0]->getType())); + case X86::BI__builtin_ia32_vfmaddsh3_maskz: case X86::BI__builtin_ia32_vfmaddss3_maskz: case X86::BI__builtin_ia32_vfmaddsd3_maskz: return EmitScalarFMAExpr(*this, E, Ops, Ops[0], /*ZeroMask*/ true); + case X86::BI__builtin_ia32_vfmaddsh3_mask3: case X86::BI__builtin_ia32_vfmaddss3_mask3: case X86::BI__builtin_ia32_vfmaddsd3_mask3: return EmitScalarFMAExpr(*this, E, Ops, Ops[2], /*ZeroMask*/ false, 2); + case X86::BI__builtin_ia32_vfmsubsh3_mask3: case X86::BI__builtin_ia32_vfmsubss3_mask3: case X86::BI__builtin_ia32_vfmsubsd3_mask3: return EmitScalarFMAExpr(*this, E, Ops, Ops[2], /*ZeroMask*/ false, 2, /*NegAcc*/ true); + case X86::BI__builtin_ia32_vfmaddph: case X86::BI__builtin_ia32_vfmaddps: case X86::BI__builtin_ia32_vfmaddpd: + case X86::BI__builtin_ia32_vfmaddph256: case X86::BI__builtin_ia32_vfmaddps256: case X86::BI__builtin_ia32_vfmaddpd256: + case X86::BI__builtin_ia32_vfmaddph512_mask: + case X86::BI__builtin_ia32_vfmaddph512_maskz: + case X86::BI__builtin_ia32_vfmaddph512_mask3: case X86::BI__builtin_ia32_vfmaddps512_mask: case X86::BI__builtin_ia32_vfmaddps512_maskz: case X86::BI__builtin_ia32_vfmaddps512_mask3: @@ -12779,7 +12930,12 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_vfmaddpd512_maskz: case X86::BI__builtin_ia32_vfmaddpd512_mask3: case X86::BI__builtin_ia32_vfmsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubph512_mask3: return EmitX86FMAExpr(*this, E, Ops, BuiltinID, /*IsAddSub*/ false); + case X86::BI__builtin_ia32_vfmaddsubph512_mask: + case X86::BI__builtin_ia32_vfmaddsubph512_maskz: + case X86::BI__builtin_ia32_vfmaddsubph512_mask3: + case X86::BI__builtin_ia32_vfmsubaddph512_mask3: case X86::BI__builtin_ia32_vfmaddsubps512_mask: case X86::BI__builtin_ia32_vfmaddsubps512_maskz: case X86::BI__builtin_ia32_vfmaddsubps512_mask3: @@ -12826,6 +12982,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_loaddqudi512_mask: return EmitX86MaskedLoad(*this, Ops, Align(1)); + case X86::BI__builtin_ia32_loadsh128_mask: case X86::BI__builtin_ia32_loadss128_mask: case X86::BI__builtin_ia32_loadsd128_mask: return EmitX86MaskedLoad(*this, Ops, Align(1)); @@ -13705,6 +13862,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_selectq_128: case X86::BI__builtin_ia32_selectq_256: case X86::BI__builtin_ia32_selectq_512: + case X86::BI__builtin_ia32_selectph_128: + case X86::BI__builtin_ia32_selectph_256: + case X86::BI__builtin_ia32_selectph_512: case X86::BI__builtin_ia32_selectps_128: case X86::BI__builtin_ia32_selectps_256: case X86::BI__builtin_ia32_selectps_512: @@ -13712,6 +13872,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_selectpd_256: case X86::BI__builtin_ia32_selectpd_512: return EmitX86Select(*this, Ops[0], Ops[1], Ops[2]); + case X86::BI__builtin_ia32_selectsh_128: case X86::BI__builtin_ia32_selectss_128: case X86::BI__builtin_ia32_selectsd_128: { Value *A = Builder.CreateExtractElement(Ops[1], (uint64_t)0); @@ -13944,15 +14105,28 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } return Builder.CreateInsertElement(Ops[0], A, (uint64_t)0); } + case X86::BI__builtin_ia32_sqrtsh_round_mask: case X86::BI__builtin_ia32_sqrtsd_round_mask: case X86::BI__builtin_ia32_sqrtss_round_mask: { unsigned CC = cast(Ops[4])->getZExtValue(); // Support only if the rounding mode is 4 (AKA CUR_DIRECTION), // otherwise keep the intrinsic. if (CC != 4) { - Intrinsic::ID IID = BuiltinID == X86::BI__builtin_ia32_sqrtsd_round_mask ? - Intrinsic::x86_avx512_mask_sqrt_sd : - Intrinsic::x86_avx512_mask_sqrt_ss; + Intrinsic::ID IID; + + switch (BuiltinID) { + default: + llvm_unreachable("Unsupported intrinsic!"); + case X86::BI__builtin_ia32_sqrtsh_round_mask: + IID = Intrinsic::x86_avx512fp16_mask_sqrt_sh; + break; + case X86::BI__builtin_ia32_sqrtsd_round_mask: + IID = Intrinsic::x86_avx512_mask_sqrt_sd; + break; + case X86::BI__builtin_ia32_sqrtss_round_mask: + IID = Intrinsic::x86_avx512_mask_sqrt_ss; + break; + } return Builder.CreateCall(CGM.getIntrinsic(IID), Ops); } Value *A = Builder.CreateExtractElement(Ops[1], (uint64_t)0); @@ -13974,6 +14148,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_sqrtpd: case X86::BI__builtin_ia32_sqrtps256: case X86::BI__builtin_ia32_sqrtps: + case X86::BI__builtin_ia32_sqrtph256: + case X86::BI__builtin_ia32_sqrtph: + case X86::BI__builtin_ia32_sqrtph512: case X86::BI__builtin_ia32_sqrtps512: case X86::BI__builtin_ia32_sqrtpd512: { if (Ops.size() == 2) { @@ -13981,9 +14158,21 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, // Support only if the rounding mode is 4 (AKA CUR_DIRECTION), // otherwise keep the intrinsic. if (CC != 4) { - Intrinsic::ID IID = BuiltinID == X86::BI__builtin_ia32_sqrtps512 ? - Intrinsic::x86_avx512_sqrt_ps_512 : - Intrinsic::x86_avx512_sqrt_pd_512; + Intrinsic::ID IID; + + switch (BuiltinID) { + default: + llvm_unreachable("Unsupported intrinsic!"); + case X86::BI__builtin_ia32_sqrtph512: + IID = Intrinsic::x86_avx512fp16_sqrt_ph_512; + break; + case X86::BI__builtin_ia32_sqrtps512: + IID = Intrinsic::x86_avx512_sqrt_ps_512; + break; + case X86::BI__builtin_ia32_sqrtpd512: + IID = Intrinsic::x86_avx512_sqrt_pd_512; + break; + } return Builder.CreateCall(CGM.getIntrinsic(IID), Ops); } } @@ -14151,28 +14340,40 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, return Builder.CreateCall(F, {Ops[0]}); } case X86::BI__builtin_ia32_reduce_fadd_pd512: - case X86::BI__builtin_ia32_reduce_fadd_ps512: { + case X86::BI__builtin_ia32_reduce_fadd_ps512: + case X86::BI__builtin_ia32_reduce_fadd_ph512: + case X86::BI__builtin_ia32_reduce_fadd_ph256: + case X86::BI__builtin_ia32_reduce_fadd_ph128: { Function *F = CGM.getIntrinsic(Intrinsic::vector_reduce_fadd, Ops[1]->getType()); Builder.getFastMathFlags().setAllowReassoc(); return Builder.CreateCall(F, {Ops[0], Ops[1]}); } case X86::BI__builtin_ia32_reduce_fmul_pd512: - case X86::BI__builtin_ia32_reduce_fmul_ps512: { + case X86::BI__builtin_ia32_reduce_fmul_ps512: + case X86::BI__builtin_ia32_reduce_fmul_ph512: + case X86::BI__builtin_ia32_reduce_fmul_ph256: + case X86::BI__builtin_ia32_reduce_fmul_ph128: { Function *F = CGM.getIntrinsic(Intrinsic::vector_reduce_fmul, Ops[1]->getType()); Builder.getFastMathFlags().setAllowReassoc(); return Builder.CreateCall(F, {Ops[0], Ops[1]}); } case X86::BI__builtin_ia32_reduce_fmax_pd512: - case X86::BI__builtin_ia32_reduce_fmax_ps512: { + case X86::BI__builtin_ia32_reduce_fmax_ps512: + case X86::BI__builtin_ia32_reduce_fmax_ph512: + case X86::BI__builtin_ia32_reduce_fmax_ph256: + case X86::BI__builtin_ia32_reduce_fmax_ph128: { Function *F = CGM.getIntrinsic(Intrinsic::vector_reduce_fmax, Ops[0]->getType()); Builder.getFastMathFlags().setNoNaNs(); return Builder.CreateCall(F, {Ops[0]}); } case X86::BI__builtin_ia32_reduce_fmin_pd512: - case X86::BI__builtin_ia32_reduce_fmin_ps512: { + case X86::BI__builtin_ia32_reduce_fmin_ps512: + case X86::BI__builtin_ia32_reduce_fmin_ph512: + case X86::BI__builtin_ia32_reduce_fmin_ph256: + case X86::BI__builtin_ia32_reduce_fmin_ph128: { Function *F = CGM.getIntrinsic(Intrinsic::vector_reduce_fmin, Ops[0]->getType()); Builder.getFastMathFlags().setNoNaNs(); @@ -14288,6 +14489,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_fpclassps128_mask: case X86::BI__builtin_ia32_fpclassps256_mask: case X86::BI__builtin_ia32_fpclassps512_mask: + case X86::BI__builtin_ia32_fpclassph128_mask: + case X86::BI__builtin_ia32_fpclassph256_mask: + case X86::BI__builtin_ia32_fpclassph512_mask: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclasspd512_mask: { @@ -14299,6 +14503,15 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Intrinsic::ID ID; switch (BuiltinID) { default: llvm_unreachable("Unsupported intrinsic!"); + case X86::BI__builtin_ia32_fpclassph128_mask: + ID = Intrinsic::x86_avx512fp16_fpclass_ph_128; + break; + case X86::BI__builtin_ia32_fpclassph256_mask: + ID = Intrinsic::x86_avx512fp16_fpclass_ph_256; + break; + case X86::BI__builtin_ia32_fpclassph512_mask: + ID = Intrinsic::x86_avx512fp16_fpclass_ph_512; + break; case X86::BI__builtin_ia32_fpclassps128_mask: ID = Intrinsic::x86_avx512_fpclass_ps_128; break; @@ -14436,6 +14649,9 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__builtin_ia32_cmpordps: case X86::BI__builtin_ia32_cmpordpd: return getVectorFCmpIR(CmpInst::FCMP_ORD, /*IsSignaling*/false); + case X86::BI__builtin_ia32_cmpph128_mask: + case X86::BI__builtin_ia32_cmpph256_mask: + case X86::BI__builtin_ia32_cmpph512_mask: case X86::BI__builtin_ia32_cmpps128_mask: case X86::BI__builtin_ia32_cmpps256_mask: case X86::BI__builtin_ia32_cmpps512_mask: @@ -14777,7 +14993,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID), {Ops[0], Ops[1]}); - for (int i = 0; i < 6; ++i) { + for (int i = 0; i < 3; ++i) { Value *Extract = Builder.CreateExtractValue(Call, i + 1); Value *Ptr = Builder.CreateConstGEP1_32(Int8Ty, Ops[2], i * 16); Ptr = Builder.CreateBitCast( @@ -14793,7 +15009,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID), {Ops[0], Ops[1], Ops[2]}); - for (int i = 0; i < 7; ++i) { + for (int i = 0; i < 4; ++i) { Value *Extract = Builder.CreateExtractValue(Call, i + 1); Value *Ptr = Builder.CreateConstGEP1_32(Int8Ty, Ops[3], i * 16); Ptr = Builder.CreateBitCast( @@ -14918,6 +15134,36 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, Builder.SetInsertPoint(End); return Builder.CreateExtractValue(Call, 0); } + case X86::BI__builtin_ia32_vfcmaddcph512_mask: + IsConjFMA = true; + LLVM_FALLTHROUGH; + case X86::BI__builtin_ia32_vfmaddcph512_mask: { + Intrinsic::ID IID = IsConjFMA + ? Intrinsic::x86_avx512fp16_mask_vfcmadd_cph_512 + : Intrinsic::x86_avx512fp16_mask_vfmadd_cph_512; + Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID), Ops); + return EmitX86Select(*this, Ops[3], Call, Ops[0]); + } + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask: + IsConjFMA = true; + LLVM_FALLTHROUGH; + case X86::BI__builtin_ia32_vfmaddcsh_round_mask: { + Intrinsic::ID IID = IsConjFMA ? Intrinsic::x86_avx512fp16_mask_vfcmadd_csh + : Intrinsic::x86_avx512fp16_mask_vfmadd_csh; + Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID), Ops); + Value *And = Builder.CreateAnd(Ops[3], llvm::ConstantInt::get(Int8Ty, 1)); + return EmitX86Select(*this, And, Call, Ops[0]); + } + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3: + IsConjFMA = true; + LLVM_FALLTHROUGH; + case X86::BI__builtin_ia32_vfmaddcsh_round_mask3: { + Intrinsic::ID IID = IsConjFMA ? Intrinsic::x86_avx512fp16_mask_vfcmadd_csh + : Intrinsic::x86_avx512fp16_mask_vfmadd_csh; + Value *Call = Builder.CreateCall(CGM.getIntrinsic(IID), Ops); + static constexpr int Mask[] = {0, 5, 6, 7}; + return Builder.CreateShuffleVector(Call, Ops[2], Mask); + } } } @@ -14925,8 +15171,12 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { SmallVector Ops; - for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) - Ops.push_back(EmitScalarExpr(E->getArg(i))); + for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) { + if (E->getArg(i)->getType()->isArrayType()) + Ops.push_back(EmitArrayToPointerDecay(E->getArg(i)).getPointer()); + else + Ops.push_back(EmitScalarExpr(E->getArg(i))); + } Intrinsic::ID ID = Intrinsic::not_intrinsic; @@ -15496,6 +15746,12 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, Value *Rotate = Builder.CreateCall(F, {Ops[0], Ops[0], ShiftAmt}); return Builder.CreateAnd(Rotate, Ops[2]); } + case PPC::BI__builtin_ppc_load2r: { + Function *F = CGM.getIntrinsic(Intrinsic::ppc_load2r); + Ops[0] = Builder.CreateBitCast(Ops[0], Int8PtrTy); + Value *LoadIntrinsic = Builder.CreateCall(F, Ops); + return Builder.CreateTrunc(LoadIntrinsic, Int16Ty); + } // FMA variations case PPC::BI__builtin_vsx_xvmaddadp: case PPC::BI__builtin_vsx_xvmaddasp: @@ -15751,6 +16007,17 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, } return Call; } + if (BuiltinID == PPC::BI__builtin_vsx_build_pair || + BuiltinID == PPC::BI__builtin_mma_build_acc) { + // Reverse the order of the operands for LE, so the + // same builtin call can be used on both LE and BE + // without the need for the programmer to swap operands. + // The operands are reversed starting from the second argument, + // the first operand is the pointer to the pair/accumulator + // that is being built. + if (getTarget().isLittleEndian()) + std::reverse(Ops.begin() + 1, Ops.end()); + } bool Accumulate; switch (BuiltinID) { #define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ @@ -15808,7 +16075,7 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, // store. Value *LoadedVal = Pair.first.getScalarVal(); Builder.CreateStore(LoadedVal, OldValAddr); - return Pair.second; + return Builder.CreateZExt(Pair.second, Builder.getInt32Ty()); } case PPC::BI__builtin_ppc_fetch_and_add: case PPC::BI__builtin_ppc_fetch_and_addlp: { @@ -15907,6 +16174,21 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, *this, E, Intrinsic::sqrt, Intrinsic::experimental_constrained_sqrt)) .getScalarVal(); + case PPC::BI__builtin_ppc_test_data_class: { + llvm::Type *ArgType = EmitScalarExpr(E->getArg(0))->getType(); + unsigned IntrinsicID; + if (ArgType->isDoubleTy()) + IntrinsicID = Intrinsic::ppc_test_data_class_d; + else if (ArgType->isFloatTy()) + IntrinsicID = Intrinsic::ppc_test_data_class_f; + else + llvm_unreachable("Invalid Argument Type"); + return Builder.CreateCall(CGM.getIntrinsic(IntrinsicID), Ops, + "test_data_class"); + } + case PPC::BI__builtin_ppc_swdiv: + case PPC::BI__builtin_ppc_swdivs: + return Builder.CreateFDiv(Ops[0], Ops[1], "swdiv"); } } @@ -15917,11 +16199,9 @@ Value *EmitAMDGPUDispatchPtr(CodeGenFunction &CGF, const CallExpr *E = nullptr) { auto *F = CGF.CGM.getIntrinsic(Intrinsic::amdgcn_dispatch_ptr); auto *Call = CGF.Builder.CreateCall(F); - Call->addAttribute( - AttributeList::ReturnIndex, + Call->addRetAttr( Attribute::getWithDereferenceableBytes(Call->getContext(), 64)); - Call->addAttribute(AttributeList::ReturnIndex, - Attribute::getWithAlignment(Call->getContext(), Align(4))); + Call->addRetAttr(Attribute::getWithAlignment(Call->getContext(), Align(4))); if (!E) return Call; QualType BuiltinRetType = E->getType(); @@ -16197,6 +16477,74 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, Src0 = Builder.CreatePointerBitCastOrAddrSpaceCast(Src0, PTy); return Builder.CreateCall(F, { Src0, Src1, Src2, Src3, Src4 }); } + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f64: + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f32: + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_v2f16: + case AMDGPU::BI__builtin_amdgcn_global_atomic_fmin_f64: + case AMDGPU::BI__builtin_amdgcn_global_atomic_fmax_f64: + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fadd_f64: + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fmin_f64: + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fmax_f64: { + Intrinsic::ID IID; + llvm::Type *ArgTy = llvm::Type::getDoubleTy(getLLVMContext()); + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f32: + ArgTy = llvm::Type::getFloatTy(getLLVMContext()); + IID = Intrinsic::amdgcn_global_atomic_fadd; + break; + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_v2f16: + ArgTy = llvm::FixedVectorType::get( + llvm::Type::getHalfTy(getLLVMContext()), 2); + IID = Intrinsic::amdgcn_global_atomic_fadd; + break; + case AMDGPU::BI__builtin_amdgcn_global_atomic_fadd_f64: + IID = Intrinsic::amdgcn_global_atomic_fadd; + break; + case AMDGPU::BI__builtin_amdgcn_global_atomic_fmin_f64: + IID = Intrinsic::amdgcn_global_atomic_fmin; + break; + case AMDGPU::BI__builtin_amdgcn_global_atomic_fmax_f64: + IID = Intrinsic::amdgcn_global_atomic_fmax; + break; + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fadd_f64: + IID = Intrinsic::amdgcn_flat_atomic_fadd; + break; + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fmin_f64: + IID = Intrinsic::amdgcn_flat_atomic_fmin; + break; + case AMDGPU::BI__builtin_amdgcn_flat_atomic_fmax_f64: + IID = Intrinsic::amdgcn_flat_atomic_fmax; + break; + } + llvm::Value *Addr = EmitScalarExpr(E->getArg(0)); + llvm::Value *Val = EmitScalarExpr(E->getArg(1)); + llvm::Function *F = + CGM.getIntrinsic(IID, {ArgTy, Addr->getType(), Val->getType()}); + return Builder.CreateCall(F, {Addr, Val}); + } + case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f64: + case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f32: { + Intrinsic::ID IID; + llvm::Type *ArgTy; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f32: + ArgTy = llvm::Type::getFloatTy(getLLVMContext()); + IID = Intrinsic::amdgcn_ds_fadd; + break; + case AMDGPU::BI__builtin_amdgcn_ds_atomic_fadd_f64: + ArgTy = llvm::Type::getDoubleTy(getLLVMContext()); + IID = Intrinsic::amdgcn_ds_fadd; + break; + } + llvm::Value *Addr = EmitScalarExpr(E->getArg(0)); + llvm::Value *Val = EmitScalarExpr(E->getArg(1)); + llvm::Constant *ZeroI32 = llvm::ConstantInt::getIntegerValue( + llvm::Type::getInt32Ty(getLLVMContext()), APInt(32, 0, true)); + llvm::Constant *ZeroI1 = llvm::ConstantInt::getIntegerValue( + llvm::Type::getInt1Ty(getLLVMContext()), APInt(1, 0)); + llvm::Function *F = CGM.getIntrinsic(IID, {ArgTy}); + return Builder.CreateCall(F, {Addr, Val, ZeroI32, ZeroI32, ZeroI1}); + } case AMDGPU::BI__builtin_amdgcn_read_exec: { CallInst *CI = cast( EmitSpecialRegisterBuiltin(*this, E, Int64Ty, Int64Ty, NormalRead, "exec")); @@ -17726,6 +18074,22 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_pmin_f32x4: + case WebAssembly::BI__builtin_wasm_pmin_f64x2: { + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType())); + return Builder.CreateCall(Callee, {LHS, RHS}); + } + case WebAssembly::BI__builtin_wasm_pmax_f32x4: + case WebAssembly::BI__builtin_wasm_pmax_f64x2: { + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType())); + return Builder.CreateCall(Callee, {LHS, RHS}); + } case WebAssembly::BI__builtin_wasm_ceil_f32x4: case WebAssembly::BI__builtin_wasm_floor_f32x4: case WebAssembly::BI__builtin_wasm_trunc_f32x4: @@ -18012,6 +18376,93 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle); return Builder.CreateCall(Callee, Ops); } + case WebAssembly::BI__builtin_wasm_fma_f32x4: + case WebAssembly::BI__builtin_wasm_fms_f32x4: + case WebAssembly::BI__builtin_wasm_fma_f64x2: + case WebAssembly::BI__builtin_wasm_fms_f64x2: { + Value *A = EmitScalarExpr(E->getArg(0)); + Value *B = EmitScalarExpr(E->getArg(1)); + Value *C = EmitScalarExpr(E->getArg(2)); + unsigned IntNo; + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_fma_f32x4: + case WebAssembly::BI__builtin_wasm_fma_f64x2: + IntNo = Intrinsic::wasm_fma; + break; + case WebAssembly::BI__builtin_wasm_fms_f32x4: + case WebAssembly::BI__builtin_wasm_fms_f64x2: + IntNo = Intrinsic::wasm_fms; + break; + default: + llvm_unreachable("unexpected builtin ID"); + } + Function *Callee = CGM.getIntrinsic(IntNo, A->getType()); + return Builder.CreateCall(Callee, {A, B, C}); + } + case WebAssembly::BI__builtin_wasm_laneselect_i8x16: + case WebAssembly::BI__builtin_wasm_laneselect_i16x8: + case WebAssembly::BI__builtin_wasm_laneselect_i32x4: + case WebAssembly::BI__builtin_wasm_laneselect_i64x2: { + Value *A = EmitScalarExpr(E->getArg(0)); + Value *B = EmitScalarExpr(E->getArg(1)); + Value *C = EmitScalarExpr(E->getArg(2)); + Function *Callee = + CGM.getIntrinsic(Intrinsic::wasm_laneselect, A->getType()); + return Builder.CreateCall(Callee, {A, B, C}); + } + case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: { + Value *Src = EmitScalarExpr(E->getArg(0)); + Value *Indices = EmitScalarExpr(E->getArg(1)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle); + return Builder.CreateCall(Callee, {Src, Indices}); + } + case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: + case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: { + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + unsigned IntNo; + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2: + IntNo = Intrinsic::wasm_relaxed_min; + break; + case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: + IntNo = Intrinsic::wasm_relaxed_max; + break; + default: + llvm_unreachable("unexpected builtin ID"); + } + Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType()); + return Builder.CreateCall(Callee, {LHS, RHS}); + } + case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2: + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2: { + Value *Vec = EmitScalarExpr(E->getArg(0)); + unsigned IntNo; + switch (BuiltinID) { + case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4: + IntNo = Intrinsic::wasm_relaxed_trunc_signed; + break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4: + IntNo = Intrinsic::wasm_relaxed_trunc_unsigned; + break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_s_i32x4_f64x2: + IntNo = Intrinsic::wasm_relaxed_trunc_zero_signed; + break; + case WebAssembly::BI__builtin_wasm_relaxed_trunc_zero_u_i32x4_f64x2: + IntNo = Intrinsic::wasm_relaxed_trunc_zero_unsigned; + break; + default: + llvm_unreachable("unexpected builtin ID"); + } + Function *Callee = CGM.getIntrinsic(IntNo); + return Builder.CreateCall(Callee, {Vec}); + } default: return nullptr; } @@ -18272,6 +18723,7 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, Intrinsic::ID ID = Intrinsic::not_intrinsic; unsigned NF = 1; + constexpr unsigned TAIL_UNDISTURBED = 0; // Required for overloaded intrinsics. llvm::SmallVector IntrinsicTypes; diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 88030fee501..a1b4431ca8c 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -177,7 +177,7 @@ public: llvm::Function *finalizeModule() override; }; -} +} // end anonymous namespace std::string CGNVCUDARuntime::addPrefixToName(StringRef FuncName) const { if (CGM.getLangOpts().HIP) @@ -237,11 +237,10 @@ llvm::FunctionCallee CGNVCUDARuntime::getLaunchFn() const { // hipError_t hipLaunchByPtr(char *); return CGM.CreateRuntimeFunction( llvm::FunctionType::get(IntTy, CharPtrTy, false), "hipLaunchByPtr"); - } else { - // cudaError_t cudaLaunch(char *); - return CGM.CreateRuntimeFunction( - llvm::FunctionType::get(IntTy, CharPtrTy, false), "cudaLaunch"); } + // cudaError_t cudaLaunch(char *); + return CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IntTy, CharPtrTy, false), "cudaLaunch"); } llvm::FunctionType *CGNVCUDARuntime::getRegisterGlobalsFnTy() const { @@ -253,8 +252,8 @@ llvm::FunctionType *CGNVCUDARuntime::getCallbackFnTy() const { } llvm::FunctionType *CGNVCUDARuntime::getRegisterLinkedBinaryFnTy() const { - auto CallbackFnTy = getCallbackFnTy(); - auto RegisterGlobalsFnTy = getRegisterGlobalsFnTy(); + auto *CallbackFnTy = getCallbackFnTy(); + auto *RegisterGlobalsFnTy = getRegisterGlobalsFnTy(); llvm::Type *Params[] = {RegisterGlobalsFnTy->getPointerTo(), VoidPtrTy, VoidPtrTy, CallbackFnTy->getPointerTo()}; return llvm::FunctionType::get(VoidTy, Params, false); @@ -397,7 +396,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, QualType QT = cudaLaunchKernelFD->getType(); QualType CQT = QT.getCanonicalType(); llvm::Type *Ty = CGM.getTypes().ConvertType(CQT); - llvm::FunctionType *FTy = dyn_cast(Ty); + llvm::FunctionType *FTy = cast(Ty); const CGFunctionInfo &FI = CGM.getTypes().arrangeFunctionDeclaration(cudaLaunchKernelFD); @@ -473,7 +472,7 @@ static void replaceManagedVar(llvm::GlobalVariable *Var, // variable with instructions. for (auto &&Op : WorkItem) { auto *CE = cast(Op); - auto *NewInst = llvm::createReplacementInstr(CE, I); + auto *NewInst = CE->getAsInstruction(I); NewInst->replaceUsesOfWith(OldV, NewV); OldV = CE; NewV = NewInst; @@ -590,7 +589,7 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() { uint64_t VarSize = CGM.getDataLayout().getTypeAllocSize(Var->getValueType()); if (Info.Flags.isManaged()) { - auto ManagedVar = new llvm::GlobalVariable( + auto *ManagedVar = new llvm::GlobalVariable( CGM.getModule(), Var->getType(), /*isConstant=*/false, Var->getLinkage(), /*Init=*/Var->isDeclaration() @@ -823,7 +822,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { GpuBinaryHandle, CharUnits::fromQuantity(GpuBinaryHandle->getAlignment())); { - auto HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr); + auto *HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr); llvm::Constant *Zero = llvm::Constant::getNullValue(HandleValue->getType()); llvm::Value *EQZero = CtorBuilder.CreateICmpEQ(HandleValue, Zero); @@ -842,7 +841,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleCtorFunction() { CtorBuilder.SetInsertPoint(ExitBlock); // Call __hip_register_globals(GpuBinaryHandle); if (RegisterGlobalsFunc) { - auto HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr); + auto *HandleValue = CtorBuilder.CreateLoad(GpuBinaryAddr); CtorBuilder.CreateCall(RegisterGlobalsFunc, HandleValue); } } @@ -958,7 +957,7 @@ llvm::Function *CGNVCUDARuntime::makeModuleDtorFunction() { Address GpuBinaryAddr(GpuBinaryHandle, CharUnits::fromQuantity( GpuBinaryHandle->getAlignment())); - auto HandleValue = DtorBuilder.CreateLoad(GpuBinaryAddr); + auto *HandleValue = DtorBuilder.CreateLoad(GpuBinaryAddr); // There is only one HIP fat binary per linked module, however there are // multiple destructor functions. Make sure the fat binary is unregistered // only once. @@ -1071,7 +1070,7 @@ void CGNVCUDARuntime::transformManagedVars() { llvm::GlobalVariable *Var = Info.Var; if (Info.Flags.getKind() == DeviceVarFlags::Variable && Info.Flags.isManaged()) { - auto ManagedVar = new llvm::GlobalVariable( + auto *ManagedVar = new llvm::GlobalVariable( CGM.getModule(), Var->getType(), /*isConstant=*/false, Var->getLinkage(), /*Init=*/Var->isDeclaration() @@ -1148,6 +1147,7 @@ llvm::GlobalValue *CGNVCUDARuntime::getKernelHandle(llvm::Function *F, Var->setAlignment(CGM.getPointerAlign().getAsAlign()); Var->setDSOLocal(F->isDSOLocal()); Var->setVisibility(F->getVisibility()); + CGM.maybeSetTrivialComdat(*GD.getDecl(), *Var); KernelHandles[F] = Var; KernelStubs[Var] = F; return Var; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 47a4ed35be8..d830a7e0170 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1271,12 +1271,26 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty, // perform the conversion. if (auto *ScalableDst = dyn_cast(Ty)) { if (auto *FixedSrc = dyn_cast(SrcTy)) { + // If we are casting a fixed i8 vector to a scalable 16 x i1 predicate + // vector, use a vector insert and bitcast the result. + bool NeedsBitcast = false; + auto PredType = + llvm::ScalableVectorType::get(CGF.Builder.getInt1Ty(), 16); + llvm::Type *OrigType = Ty; + if (ScalableDst == PredType && + FixedSrc->getElementType() == CGF.Builder.getInt8Ty()) { + ScalableDst = llvm::ScalableVectorType::get(CGF.Builder.getInt8Ty(), 2); + NeedsBitcast = true; + } if (ScalableDst->getElementType() == FixedSrc->getElementType()) { auto *Load = CGF.Builder.CreateLoad(Src); auto *UndefVec = llvm::UndefValue::get(ScalableDst); auto *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty); - return CGF.Builder.CreateInsertVector(ScalableDst, UndefVec, Load, Zero, - "castScalableSve"); + llvm::Value *Result = CGF.Builder.CreateInsertVector( + ScalableDst, UndefVec, Load, Zero, "castScalableSve"); + if (NeedsBitcast) + Result = CGF.Builder.CreateBitCast(Result, OrigType); + return Result; } } } @@ -1550,11 +1564,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) { default: return false; case BuiltinType::Float: - return getTarget().useObjCFPRetForRealType(TargetInfo::Float); + return getTarget().useObjCFPRetForRealType(FloatModeKind::Float); case BuiltinType::Double: - return getTarget().useObjCFPRetForRealType(TargetInfo::Double); + return getTarget().useObjCFPRetForRealType(FloatModeKind::Double); case BuiltinType::LongDouble: - return getTarget().useObjCFPRetForRealType(TargetInfo::LongDouble); + return getTarget().useObjCFPRetForRealType(FloatModeKind::LongDouble); } } @@ -1733,6 +1747,21 @@ static void AddAttributesFromFunctionProtoType(ASTContext &Ctx, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } +static void AddAttributesFromAssumes(llvm::AttrBuilder &FuncAttrs, + const Decl *Callee) { + if (!Callee) + return; + + SmallVector Attrs; + + for (const AssumptionAttr *AA : Callee->specific_attrs()) + AA->getAssumption().split(Attrs, ","); + + if (!Attrs.empty()) + FuncAttrs.addAttribute(llvm::AssumptionAttrKey, + llvm::join(Attrs.begin(), Attrs.end(), ",")); +} + bool CodeGenModule::MayDropFunctionReturn(const ASTContext &Context, QualType ReturnType) { // We can't just discard the return value for a record type with a @@ -1814,6 +1843,8 @@ void CodeGenModule::getDefaultFunctionAttributes(StringRef Name, FuncAttrs.addAttribute("no-infs-fp-math", "true"); if (LangOpts.NoHonorNaNs) FuncAttrs.addAttribute("no-nans-fp-math", "true"); + if (LangOpts.ApproxFunc) + FuncAttrs.addAttribute("approx-func-fp-math", "true"); if (LangOpts.UnsafeFPMath) FuncAttrs.addAttribute("unsafe-fp-math", "true"); if (CodeGenOpts.SoftFloat) @@ -1871,7 +1902,7 @@ void CodeGenModule::addDefaultFunctionDefinitionAttributes(llvm::Function &F) { getDefaultFunctionAttributes(F.getName(), F.hasOptNone(), /* AttrOnCallSite = */ false, FuncAttrs); // TODO: call GetCPUAndFeaturesAttributes? - F.addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); + F.addFnAttrs(FuncAttrs); } void CodeGenModule::addDefaultFunctionDefinitionAttributes( @@ -2006,6 +2037,10 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, const Decl *TargetDecl = CalleeInfo.getCalleeDecl().getDecl(); + // Attach assumption attributes to the declaration. If this is a call + // site, attach assumptions from the caller to the call as well. + AddAttributesFromAssumes(FuncAttrs, TargetDecl); + bool HasOptnone = false; // The NoBuiltinAttr attached to the target FunctionDecl. const NoBuiltinAttr *NBA = nullptr; @@ -2052,24 +2087,6 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, // allows it to work on indirect virtual function calls. if (AttrOnCallSite && TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoMerge); - - // Add known guaranteed alignment for allocation functions. - if (unsigned BuiltinID = Fn->getBuiltinID()) { - switch (BuiltinID) { - case Builtin::BIaligned_alloc: - case Builtin::BIcalloc: - case Builtin::BImalloc: - case Builtin::BImemalign: - case Builtin::BIrealloc: - case Builtin::BIstrdup: - case Builtin::BIstrndup: - RetAttrs.addAlignmentAttr(Context.getTargetInfo().getNewAlign() / - Context.getTargetInfo().getCharWidth()); - break; - default: - break; - } - } } // 'const', 'pure' and 'noalias' attributed functions are also nounwind. @@ -2123,18 +2140,6 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, llvm::toStringRef(CodeGenOpts.UniformWGSize)); } } - - std::string AssumptionValueStr; - for (AssumptionAttr *AssumptionA : - TargetDecl->specific_attrs()) { - std::string AS = AssumptionA->getAssumption().str(); - if (!AS.empty() && !AssumptionValueStr.empty()) - AssumptionValueStr += ","; - AssumptionValueStr += AS; - } - - if (!AssumptionValueStr.empty()) - FuncAttrs.addAttribute(llvm::AssumptionAttrKey, AssumptionValueStr); } // Attach "no-builtins" attributes to: @@ -2227,7 +2232,7 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, // C++ explicitly makes returning undefined values UB. C's rule only applies // to used values, so we never mark them noundef for now. bool HasStrictReturn = getLangOpts().CPlusPlus; - if (TargetDecl) { + if (TargetDecl && HasStrictReturn) { if (const FunctionDecl *FDecl = dyn_cast(TargetDecl)) HasStrictReturn &= !FDecl->isExternC(); else if (const VarDecl *VDecl = dyn_cast(TargetDecl)) @@ -2790,7 +2795,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // so the UBSAN check could function. llvm::ConstantInt *AlignmentCI = cast(EmitScalarExpr(AVAttr->getAlignment())); - unsigned AlignmentInt = + uint64_t AlignmentInt = AlignmentCI->getLimitedValue(llvm::Value::MaximumAlignment); if (AI->getParamAlign().valueOrOne() < AlignmentInt) { AI->removeAttr(llvm::Attribute::AttrKind::Alignment); @@ -2857,9 +2862,18 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // llvm.experimental.vector.extract to convert back to the original // VLST. if (auto *VecTyTo = dyn_cast(ConvertType(Ty))) { - auto *Coerced = Fn->getArg(FirstIRArg); + llvm::Value *Coerced = Fn->getArg(FirstIRArg); if (auto *VecTyFrom = dyn_cast(Coerced->getType())) { + // If we are casting a scalable 16 x i1 predicate vector to a fixed i8 + // vector, bitcast the source and use a vector extract. + auto PredType = + llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16); + if (VecTyFrom == PredType && + VecTyTo->getElementType() == Builder.getInt8Ty()) { + VecTyFrom = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2); + Coerced = Builder.CreateBitCast(Coerced, VecTyFrom); + } if (VecTyFrom->getElementType() == VecTyTo->getElementType()) { llvm::Value *Zero = llvm::Constant::getNullValue(CGM.Int64Ty); @@ -4503,10 +4517,8 @@ maybeRaiseRetAlignmentAttribute(llvm::LLVMContext &Ctx, if (CurAlign >= NewAlign) return Attrs; llvm::Attribute AlignAttr = llvm::Attribute::getWithAlignment(Ctx, NewAlign); - return Attrs - .removeAttribute(Ctx, llvm::AttributeList::ReturnIndex, - llvm::Attribute::AttrKind::Alignment) - .addAttribute(Ctx, llvm::AttributeList::ReturnIndex, AlignAttr); + return Attrs.removeRetAttribute(Ctx, llvm::Attribute::AttrKind::Alignment) + .addRetAttribute(Ctx, AlignAttr); } template class AbstractAssumeAlignedAttrEmitter { @@ -5005,12 +5017,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, auto scalarAlign = CGM.getDataLayout().getPrefTypeAlignment(scalarType); // Materialize to a temporary. - addr = CreateTempAlloca( - RV.getScalarVal()->getType(), - CharUnits::fromQuantity(std::max( - (unsigned)layout->getAlignment().value(), scalarAlign)), - "tmp", - /*ArraySize=*/nullptr, &AllocaAddr); + addr = + CreateTempAlloca(RV.getScalarVal()->getType(), + CharUnits::fromQuantity(std::max( + layout->getAlignment().value(), scalarAlign)), + "tmp", + /*ArraySize=*/nullptr, &AllocaAddr); tempSize = EmitLifetimeStart(scalarSize, AllocaAddr.getPointer()); Builder.CreateStore(RV.getScalarVal(), addr); @@ -5167,15 +5179,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp - Attrs = - Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::StrictFP); + Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::StrictFP); // Add call-site nomerge attribute if exists. if (InNoMergeAttributedStmt) - Attrs = - Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoMerge); + Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoMerge); // Apply some call-site-specific attributes. // TODO: work this into building the attribute set. @@ -5185,15 +5193,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (CurCodeDecl && CurCodeDecl->hasAttr() && !(TargetDecl && TargetDecl->hasAttr())) { Attrs = - Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::AlwaysInline); + Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline); } // Disable inlining inside SEH __try blocks. if (isSEHTryScope()) { - Attrs = - Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoInline); + Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline); } // Decide whether to use a call or an invoke. @@ -5209,7 +5214,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, CannotThrow = true; } else { // Otherwise, nounwind call sites will never throw. - CannotThrow = Attrs.hasFnAttribute(llvm::Attribute::NoUnwind); + CannotThrow = Attrs.hasFnAttr(llvm::Attribute::NoUnwind); if (auto *FPtr = dyn_cast(CalleePtr)) if (FPtr->hasFnAttribute(llvm::Attribute::NoUnwind)) @@ -5232,9 +5237,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp - Attrs = - Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, - llvm::Attribute::StrictFP); + Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::StrictFP); AssumeAlignedAttrEmitter AssumeAlignedAttrEmitter(*this, TargetDecl); Attrs = AssumeAlignedAttrEmitter.TryEmitAsCallSiteAttribute(Attrs); @@ -5261,8 +5264,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (const auto *FD = dyn_cast_or_null(CurFuncDecl)) { if (const auto *A = FD->getAttr()) { if (A->getGuard() == CFGuardAttr::GuardArg::nocf && !CI->getCalledFunction()) - Attrs = Attrs.addAttribute( - getLLVMContext(), llvm::AttributeList::FunctionIndex, "guard_nocf"); + Attrs = Attrs.addFnAttribute(getLLVMContext(), "guard_nocf"); } } @@ -5306,6 +5308,15 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, TargetDecl->hasAttr()) getDebugInfo()->addHeapAllocSiteMetadata(CI, RetTy->getPointeeType(), Loc); + // Add metadata if calling an __attribute__((error(""))) or warning fn. + if (TargetDecl && TargetDecl->hasAttr()) { + llvm::ConstantInt *Line = + llvm::ConstantInt::get(Int32Ty, Loc.getRawEncoding()); + llvm::ConstantAsMetadata *MD = llvm::ConstantAsMetadata::get(Line); + llvm::MDTuple *MDT = llvm::MDNode::get(getLLVMContext(), {MD}); + CI->setMetadata("srcloc", MDT); + } + // 4. Finish the call. // If the call doesn't return, finish the basic block and clear the @@ -5321,8 +5332,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // attributes of the called function. if (auto *F = CI->getCalledFunction()) F->removeFnAttr(llvm::Attribute::NoReturn); - CI->removeAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoReturn); + CI->removeFnAttr(llvm::Attribute::NoReturn); // Avoid incompatibility with ASan which relies on the `noreturn` // attribute to insert handler calls. diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 9895a23b709..0df64d4d5d2 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1424,6 +1424,11 @@ static bool CanSkipVTablePointerInitialization(CodeGenFunction &CGF, if (!ClassDecl->isDynamicClass()) return true; + // For a final class, the vtable pointer is known to already point to the + // class's vtable. + if (ClassDecl->isEffectivelyFinal()) + return true; + if (!Dtor->hasTrivialBody()) return false; @@ -2502,6 +2507,8 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) { // Apply the offsets. Address VTableField = LoadCXXThisAddress(); + unsigned ThisAddrSpace = + VTableField.getPointer()->getType()->getPointerAddressSpace(); if (!NonVirtualOffset.isZero() || VirtualOffset) VTableField = ApplyNonVirtualAndVirtualOffset( @@ -2516,12 +2523,11 @@ void CodeGenFunction::InitializeVTablePointer(const VPtr &Vptr) { llvm::FunctionType::get(CGM.Int32Ty, /*isVarArg=*/true) ->getPointerTo(ProgAS) ->getPointerTo(GlobalsAS); - // vtable field is is derived from `this` pointer, therefore it should be in - // default address space. - VTableField = Builder.CreatePointerBitCastOrAddrSpaceCast( - VTableField, VTablePtrTy->getPointerTo()); - VTableAddressPoint = Builder.CreatePointerBitCastOrAddrSpaceCast( - VTableAddressPoint, VTablePtrTy); + // vtable field is is derived from `this` pointer, therefore they should be in + // the same addr space. Note that this might not be LLVM address space 0. + VTableField = Builder.CreateBitCast(VTableField, + VTablePtrTy->getPointerTo(ThisAddrSpace)); + VTableAddressPoint = Builder.CreateBitCast(VTableAddressPoint, VTablePtrTy); llvm::StoreInst *Store = Builder.CreateStore(VTableAddressPoint, VTableField); TBAAAccessInfo TBAAInfo = CGM.getTBAAVTablePtrAccessInfo(VTablePtrTy); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 81c910f40bf..af651e6f44b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -25,6 +25,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" @@ -52,7 +53,7 @@ using namespace clang::CodeGen; static uint32_t getTypeAlignIfRequired(const Type *Ty, const ASTContext &Ctx) { auto TI = Ctx.getTypeInfo(Ty); - return TI.AlignIsRequired ? TI.Align : 0; + return TI.isAlignRequired() ? TI.Align : 0; } static uint32_t getTypeAlignIfRequired(QualType Ty, const ASTContext &Ctx) { @@ -243,6 +244,11 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.SplitTemplateClosers = true; } + PP.SuppressInlineNamespace = false; + PP.PrintCanonicalTypes = true; + PP.UsePreferredNames = false; + PP.AlwaysIncludeTypeForTemplateArgument = true; + // Apply -fdebug-prefix-map. PP.Callbacks = &PrintCB; return PP; @@ -385,7 +391,7 @@ llvm::DIFile *CGDebugInfo::getOrCreateFile(SourceLocation Loc) { } else { PresumedLoc PLoc = SM.getPresumedLoc(Loc); FileName = PLoc.getFilename(); - + if (FileName.empty()) { FileName = TheCU->getFile()->getFilename(); } else { @@ -830,11 +836,12 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::BFloat16: case BuiltinType::Float128: case BuiltinType::Double: - // FIXME: For targets where long double and __float128 have the same size, - // they are currently indistinguishable in the debugger without some - // special treatment. However, there is currently no consensus on encoding - // and this should be updated once a DWARF encoding exists for distinct - // floating point types of the same size. + case BuiltinType::Ibm128: + // FIXME: For targets where long double, __ibm128 and __float128 have the + // same size, they are currently indistinguishable in the debugger without + // some special treatment. However, there is currently no consensus on + // encoding and this should be updated once a DWARF encoding exists for + // distinct floating point types of the same size. Encoding = llvm::dwarf::DW_ATE_float; break; case BuiltinType::ShortAccum: @@ -867,23 +874,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { break; } - switch (BT->getKind()) { - case BuiltinType::Long: - BTName = "long int"; - break; - case BuiltinType::LongLong: - BTName = "long long int"; - break; - case BuiltinType::ULong: - BTName = "long unsigned int"; - break; - case BuiltinType::ULongLong: - BTName = "long long unsigned int"; - break; - default: - BTName = BT->getName(CGM.getLangOpts()); - break; - } + BTName = BT->getName(CGM.getLangOpts()); // Bit size and offset of the type. uint64_t Size = CGM.getContext().getTypeSize(BT); return DBuilder.createBasicType(BTName, Size, Encoding); @@ -914,34 +905,98 @@ llvm::DIType *CGDebugInfo::CreateType(const ComplexType *Ty) { return DBuilder.createBasicType("complex", Size, Encoding); } -llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, - llvm::DIFile *Unit) { +static void stripUnusedQualifiers(Qualifiers &Q) { + // Ignore these qualifiers for now. + Q.removeObjCGCAttr(); + Q.removeAddressSpace(); + Q.removeObjCLifetime(); + Q.removeUnaligned(); +} + +static llvm::dwarf::Tag getNextQualifier(Qualifiers &Q) { + if (Q.hasConst()) { + Q.removeConst(); + return llvm::dwarf::DW_TAG_const_type; + } + if (Q.hasVolatile()) { + Q.removeVolatile(); + return llvm::dwarf::DW_TAG_volatile_type; + } + if (Q.hasRestrict()) { + Q.removeRestrict(); + return llvm::dwarf::DW_TAG_restrict_type; + } + return (llvm::dwarf::Tag)0; +} + +// Strip MacroQualifiedTypeLoc and AttributedTypeLoc +// as their corresponding types will be ignored +// during code generation. Stripping them allows +// to maintain proper TypeLoc for a given type +// during code generation. +static TypeLoc StripMacroAttributed(TypeLoc TL) { + if (!TL) + return TL; + + while (true) { + if (auto MTL = TL.getAs()) + TL = MTL.getInnerLoc(); + else if (auto ATL = TL.getAs()) + TL = ATL.getModifiedLoc(); + else + break; + } + return TL; +} + +llvm::DIType *CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { QualifierCollector Qc; const Type *T = Qc.strip(Ty); - // Ignore these qualifiers for now. - Qc.removeObjCGCAttr(); - Qc.removeAddressSpace(); - Qc.removeObjCLifetime(); + stripUnusedQualifiers(Qc); // We will create one Derived type for one qualifier and recurse to handle any // additional ones. - llvm::dwarf::Tag Tag; - if (Qc.hasConst()) { - Tag = llvm::dwarf::DW_TAG_const_type; - Qc.removeConst(); - } else if (Qc.hasVolatile()) { - Tag = llvm::dwarf::DW_TAG_volatile_type; - Qc.removeVolatile(); - } else if (Qc.hasRestrict()) { - Tag = llvm::dwarf::DW_TAG_restrict_type; - Qc.removeRestrict(); - } else { + llvm::dwarf::Tag Tag = getNextQualifier(Qc); + if (!Tag) { assert(Qc.empty() && "Unknown type qualifier for debug info"); return getOrCreateType(QualType(T, 0), Unit); } - auto *FromTy = getOrCreateType(Qc.apply(CGM.getContext(), T), Unit); + QualType NextTy = Qc.apply(CGM.getContext(), T); + TypeLoc NextTL; + if (NextTy.hasQualifiers()) + NextTL = TL; + else if (TL) { + if (auto QTL = TL.getAs()) + NextTL = StripMacroAttributed(QTL.getNextTypeLoc()); + } + auto *FromTy = getOrCreateType(NextTy, Unit, NextTL); + + // No need to fill in the Name, Line, Size, Alignment, Offset in case of + // CVR derived types. + return DBuilder.createQualifiedType(Tag, FromTy); +} + +llvm::DIType *CGDebugInfo::CreateQualifiedType(const FunctionProtoType *F, + llvm::DIFile *Unit) { + FunctionProtoType::ExtProtoInfo EPI = F->getExtProtoInfo(); + Qualifiers &Q = EPI.TypeQuals; + stripUnusedQualifiers(Q); + + // We will create one Derived type for one qualifier and recurse to handle any + // additional ones. + llvm::dwarf::Tag Tag = getNextQualifier(Q); + if (!Tag) { + assert(Q.empty() && "Unknown type qualifier for debug info"); + return nullptr; + } + + auto *FromTy = + getOrCreateType(CGM.getContext().getFunctionType(F->getReturnType(), + F->getParamTypes(), EPI), + Unit); // No need to fill in the Name, Line, Size, Alignment, Offset in case of // CVR derived types. @@ -961,10 +1016,10 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty, Ty->getPointeeType(), Unit); } -llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, - llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::CreateType(const PointerType *Ty, llvm::DIFile *Unit, + TypeLoc TL) { return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty, - Ty->getPointeeType(), Unit); + Ty->getPointeeType(), Unit, TL); } /// \return whether a C++ mangling exists for the type defined by TD. @@ -1105,7 +1160,8 @@ CGDebugInfo::getOrCreateRecordFwdDecl(const RecordType *Ty, llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, QualType PointeeTy, - llvm::DIFile *Unit) { + llvm::DIFile *Unit, + TypeLoc TL) { // Bit size, align and offset of the type. // Size is always the size of a pointer. We can't use getTypeSize here // because that does not return the correct value for references. @@ -1115,13 +1171,52 @@ llvm::DIType *CGDebugInfo::CreatePointerLikeType(llvm::dwarf::Tag Tag, Optional DWARFAddressSpace = CGM.getTarget().getDWARFAddressSpace(AddressSpace); + llvm::DINodeArray Annotations = nullptr; + TypeLoc NextTL; + if (TL) { + SmallVector Annots; + NextTL = TL.getNextTypeLoc(); + if (NextTL) { + // Traverse all MacroQualifiedTypeLoc, QualifiedTypeLoc and + // AttributedTypeLoc type locations so we can collect + // BTFTypeTag attributes for this pointer. + while (true) { + if (auto MTL = NextTL.getAs()) { + NextTL = MTL.getInnerLoc(); + } else if (auto QTL = NextTL.getAs()) { + NextTL = QTL.getNextTypeLoc(); + } else if (auto ATL = NextTL.getAs()) { + if (const auto *A = ATL.getAttrAs()) { + StringRef BTFTypeTag = A->getBTFTypeTag(); + if (!BTFTypeTag.empty()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), + StringRef("btf_type_tag")), + llvm::MDString::get(CGM.getLLVMContext(), BTFTypeTag)}; + Annots.insert(Annots.begin(), + llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + } + NextTL = ATL.getModifiedLoc(); + } else { + break; + } + } + } + + NextTL = StripMacroAttributed(TL.getNextTypeLoc()); + if (Annots.size() > 0) + Annotations = DBuilder.getOrCreateArray(Annots); + } + if (Tag == llvm::dwarf::DW_TAG_reference_type || Tag == llvm::dwarf::DW_TAG_rvalue_reference_type) return DBuilder.createReferenceType(Tag, getOrCreateType(PointeeTy, Unit), Size, Align, DWARFAddressSpace); else - return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit), Size, - Align, DWARFAddressSpace); + return DBuilder.createPointerType(getOrCreateType(PointeeTy, Unit, NextTL), + Size, Align, DWARFAddressSpace, + StringRef(), Annotations); } llvm::DIType *CGDebugInfo::getOrCreateStructPtrType(StringRef Name, @@ -1226,7 +1321,8 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, SmallString<128> NS; llvm::raw_svector_ostream OS(NS); - Ty->getTemplateName().print(OS, getPrintingPolicy(), /*qualified*/ false); + Ty->getTemplateName().print(OS, getPrintingPolicy(), + TemplateName::Qualified::None); printTemplateArgumentList(OS, Ty->template_arguments(), getPrintingPolicy()); SourceLocation Loc = AliasDecl->getLocation(); @@ -1237,8 +1333,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, llvm::DIFile *Unit) { + TypeLoc TL; + if (const TypeSourceInfo *TSI = Ty->getDecl()->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); llvm::DIType *Underlying = - getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit); + getOrCreateType(Ty->getDecl()->getUnderlyingType(), Unit, TL); if (Ty->getDecl()->hasAttr()) return Underlying; @@ -1249,9 +1348,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); // Typedefs are derived from some other type. + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(Ty->getDecl()); return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), - getDeclContextDescriptor(Ty->getDecl()), Align); + getDeclContextDescriptor(Ty->getDecl()), Align, + Annotations); } static unsigned getDwarfCC(CallingConv CC) { @@ -1300,27 +1401,74 @@ static unsigned getDwarfCC(CallingConv CC) { return 0; } +static llvm::DINode::DIFlags getRefFlags(const FunctionProtoType *Func) { + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; + if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) + Flags |= llvm::DINode::FlagLValueReference; + if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) + Flags |= llvm::DINode::FlagRValueReference; + return Flags; +} + llvm::DIType *CGDebugInfo::CreateType(const FunctionType *Ty, - llvm::DIFile *Unit) { + llvm::DIFile *Unit, TypeLoc TL) { + const auto *FPT = dyn_cast(Ty); + if (FPT) { + if (llvm::DIType *QTy = CreateQualifiedType(FPT, Unit)) + return QTy; + } + + // Create the type without any qualifiers + SmallVector EltTys; // Add the result type at least. - EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit)); + TypeLoc RetTL; + if (TL) { + if (auto FTL = TL.getAs()) + RetTL = FTL.getReturnLoc(); + } + EltTys.push_back(getOrCreateType(Ty->getReturnType(), Unit, RetTL)); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; // Set up remainder of arguments if there is a prototype. // otherwise emit it as a variadic function. - if (isa(Ty)) + if (!FPT) { EltTys.push_back(DBuilder.createUnspecifiedParameter()); - else if (const auto *FPT = dyn_cast(Ty)) { - for (const QualType &ParamType : FPT->param_types()) - EltTys.push_back(getOrCreateType(ParamType, Unit)); + } else { + Flags = getRefFlags(FPT); + bool DoneWithTL = false; + if (TL) { + if (auto FTL = TL.getAs()) { + DoneWithTL = true; + unsigned Idx = 0; + unsigned FTL_NumParams = FTL.getNumParams(); + for (const QualType &ParamType : FPT->param_types()) { + TypeLoc ParamTL; + if (Idx < FTL_NumParams) { + if (ParmVarDecl *Param = FTL.getParam(Idx)) { + if (const TypeSourceInfo *TSI = Param->getTypeSourceInfo()) + ParamTL = TSI->getTypeLoc(); + } + } + EltTys.push_back(getOrCreateType(ParamType, Unit, ParamTL)); + Idx++; + } + } + } + + if (!DoneWithTL) { + for (const QualType &ParamType : FPT->param_types()) + EltTys.push_back(getOrCreateType(ParamType, Unit)); + } if (FPT->isVariadic()) EltTys.push_back(DBuilder.createUnspecifiedParameter()); } llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(EltTys); - return DBuilder.createSubroutineType(EltTypeArray, llvm::DINode::FlagZero, - getDwarfCC(Ty->getCallConv())); + llvm::DIType *F = DBuilder.createSubroutineType( + EltTypeArray, Flags, getDwarfCC(Ty->getCallConv())); + return F; } /// Convert an AccessSpecifier into the corresponding DINode flag. @@ -1377,17 +1525,19 @@ llvm::DIType *CGDebugInfo::createBitFieldType(const FieldDecl *BitFieldDecl, Offset = BitFieldInfo.StorageSize - BitFieldInfo.Size - Offset; uint64_t OffsetInBits = StorageOffsetInBits + Offset; llvm::DINode::DIFlags Flags = getAccessFlag(BitFieldDecl->getAccess(), RD); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(BitFieldDecl); return DBuilder.createBitFieldMemberType( RecordTy, Name, File, Line, SizeInBits, OffsetInBits, StorageOffsetInBits, - Flags, DebugType); + Flags, DebugType, Annotations); } llvm::DIType * CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, - llvm::DIScope *scope, const RecordDecl *RD) { - llvm::DIType *debugType = getOrCreateType(type, tunit); + llvm::DIScope *scope, const RecordDecl *RD, + llvm::DINodeArray Annotations, TypeLoc TL) { + llvm::DIType *debugType = getOrCreateType(type, tunit, TL); // Get the location for the field. llvm::DIFile *file = getOrCreateFile(loc); @@ -1404,7 +1554,7 @@ CGDebugInfo::createFieldType(StringRef name, QualType type, SourceLocation loc, llvm::DINode::DIFlags flags = getAccessFlag(AS, RD); return DBuilder.createMemberType(scope, name, file, line, SizeInBits, Align, - offsetInBits, flags, debugType); + offsetInBits, flags, debugType, Annotations); } void CGDebugInfo::CollectRecordLambdaFields( @@ -1494,9 +1644,13 @@ void CGDebugInfo::CollectRecordNormalField( FieldType = createBitFieldType(field, RecordTy, RD); } else { auto Align = getDeclAlignIfRequired(field, CGM.getContext()); - FieldType = - createFieldType(name, type, field->getLocation(), field->getAccess(), - OffsetInBits, Align, tunit, RecordTy, RD); + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(field); + TypeLoc TL; + if (const TypeSourceInfo *TSI = field->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + FieldType = createFieldType(name, type, field->getLocation(), + field->getAccess(), OffsetInBits, Align, tunit, + RecordTy, RD, Annotations, TL); } elements.push_back(FieldType); @@ -1584,10 +1738,25 @@ llvm::DISubroutineType * CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr, const FunctionProtoType *Func, llvm::DIFile *Unit, bool decl) { + FunctionProtoType::ExtProtoInfo EPI = Func->getExtProtoInfo(); + Qualifiers &Qc = EPI.TypeQuals; + Qc.removeConst(); + Qc.removeVolatile(); + Qc.removeRestrict(); + Qc.removeUnaligned(); + // Keep the removed qualifiers in sync with + // CreateQualifiedType(const FunctionPrototype*, DIFile *Unit) + // On a 'real' member function type, these qualifiers are carried on the type + // of the first parameter, not as separate DW_TAG_const_type (etc) decorator + // tags around them. (But, in the raw function types with qualifiers, they have + // to use wrapper types.) + // Add "this" pointer. - llvm::DITypeRefArray Args( - cast(getOrCreateType(QualType(Func, 0), Unit)) - ->getTypeArray()); + const auto *OriginalFunc = cast( + getOrCreateType(CGM.getContext().getFunctionType( + Func->getReturnType(), Func->getParamTypes(), EPI), + Unit)); + llvm::DITypeRefArray Args = OriginalFunc->getTypeArray(); assert(Args.size() && "Invalid number of arguments!"); SmallVector Elts; @@ -1629,13 +1798,7 @@ CGDebugInfo::getOrCreateInstanceMethodType(QualType ThisPtr, llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); - llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; - if (Func->getExtProtoInfo().RefQualifier == RQ_LValue) - Flags |= llvm::DINode::FlagLValueReference; - if (Func->getExtProtoInfo().RefQualifier == RQ_RValue) - Flags |= llvm::DINode::FlagRValueReference; - - return DBuilder.createSubroutineType(EltTypeArray, Flags, + return DBuilder.createSubroutineType(EltTypeArray, OriginalFunc->getFlags(), getDwarfCC(Func->getCallConv())); } @@ -1887,23 +2050,25 @@ void CGDebugInfo::CollectCXXBasesAux( } llvm::DINodeArray -CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, - ArrayRef TAList, +CGDebugInfo::CollectTemplateParams(Optional OArgs, llvm::DIFile *Unit) { + if (!OArgs) + return llvm::DINodeArray(); + TemplateArgs &Args = *OArgs; SmallVector TemplateParams; - for (unsigned i = 0, e = TAList.size(); i != e; ++i) { - const TemplateArgument &TA = TAList[i]; + for (unsigned i = 0, e = Args.Args.size(); i != e; ++i) { + const TemplateArgument &TA = Args.Args[i]; StringRef Name; bool defaultParameter = false; - if (TPList) - Name = TPList->getParam(i)->getName(); + if (Args.TList) + Name = Args.TList->getParam(i)->getName(); switch (TA.getKind()) { case TemplateArgument::Type: { llvm::DIType *TTy = getOrCreateType(TA.getAsType(), Unit); - if (TPList) + if (Args.TList) if (auto *templateType = - dyn_cast_or_null(TPList->getParam(i))) + dyn_cast_or_null(Args.TList->getParam(i))) if (templateType->hasDefaultArgument()) defaultParameter = templateType->getDefaultArgument() == TA.getAsType(); @@ -1914,9 +2079,9 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, } break; case TemplateArgument::Integral: { llvm::DIType *TTy = getOrCreateType(TA.getIntegralType(), Unit); - if (TPList && CGM.getCodeGenOpts().DwarfVersion >= 5) - if (auto *templateType = - dyn_cast_or_null(TPList->getParam(i))) + if (Args.TList && CGM.getCodeGenOpts().DwarfVersion >= 5) + if (auto *templateType = dyn_cast_or_null( + Args.TList->getParam(i))) if (templateType->hasDefaultArgument() && !templateType->getDefaultArgument()->isValueDependent()) defaultParameter = llvm::APSInt::isSameValue( @@ -1993,15 +2158,19 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, TemplateParams.push_back(DBuilder.createTemplateValueParameter( TheCU, Name, TTy, defaultParameter, V)); } break; - case TemplateArgument::Template: + case TemplateArgument::Template: { + std::string QualName; + llvm::raw_string_ostream OS(QualName); + TA.getAsTemplate().getAsTemplateDecl()->printQualifiedName( + OS, getPrintingPolicy()); TemplateParams.push_back(DBuilder.createTemplateTemplateParameter( - TheCU, Name, nullptr, - TA.getAsTemplate().getAsTemplateDecl()->getQualifiedNameAsString())); + TheCU, Name, nullptr, OS.str())); break; + } case TemplateArgument::Pack: TemplateParams.push_back(DBuilder.createTemplateParameterPack( TheCU, Name, nullptr, - CollectTemplateParams(nullptr, TA.getPackAsArray(), Unit))); + CollectTemplateParams({{nullptr, TA.getPackAsArray()}}, Unit))); break; case TemplateArgument::Expression: { const Expr *E = TA.getAsExpr(); @@ -2024,43 +2193,72 @@ CGDebugInfo::CollectTemplateParams(const TemplateParameterList *TPList, return DBuilder.getOrCreateArray(TemplateParams); } -llvm::DINodeArray -CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, - llvm::DIFile *Unit) { +Optional +CGDebugInfo::GetTemplateArgs(const FunctionDecl *FD) const { if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization) { const TemplateParameterList *TList = FD->getTemplateSpecializationInfo() ->getTemplate() ->getTemplateParameters(); - return CollectTemplateParams( - TList, FD->getTemplateSpecializationArgs()->asArray(), Unit); + return {{TList, FD->getTemplateSpecializationArgs()->asArray()}}; } - return llvm::DINodeArray(); + return None; +} +Optional +CGDebugInfo::GetTemplateArgs(const VarDecl *VD) const { + // Always get the full list of parameters, not just the ones from the + // specialization. A partial specialization may have fewer parameters than + // there are arguments. + auto *TS = dyn_cast(VD); + if (!TS) + return None; + VarTemplateDecl *T = TS->getSpecializedTemplate(); + const TemplateParameterList *TList = T->getTemplateParameters(); + auto TA = TS->getTemplateArgs().asArray(); + return {{TList, TA}}; +} +Optional +CGDebugInfo::GetTemplateArgs(const RecordDecl *RD) const { + if (auto *TSpecial = dyn_cast(RD)) { + // Always get the full list of parameters, not just the ones from the + // specialization. A partial specialization may have fewer parameters than + // there are arguments. + TemplateParameterList *TPList = + TSpecial->getSpecializedTemplate()->getTemplateParameters(); + const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); + return {{TPList, TAList.asArray()}}; + } + return None; +} + +llvm::DINodeArray +CGDebugInfo::CollectFunctionTemplateParams(const FunctionDecl *FD, + llvm::DIFile *Unit) { + return CollectTemplateParams(GetTemplateArgs(FD), Unit); } llvm::DINodeArray CGDebugInfo::CollectVarTemplateParams(const VarDecl *VL, llvm::DIFile *Unit) { - // Always get the full list of parameters, not just the ones from the - // specialization. A partial specialization may have fewer parameters than - // there are arguments. - auto *TS = dyn_cast(VL); - if (!TS) - return llvm::DINodeArray(); - VarTemplateDecl *T = TS->getSpecializedTemplate(); - const TemplateParameterList *TList = T->getTemplateParameters(); - auto TA = TS->getTemplateArgs().asArray(); - return CollectTemplateParams(TList, TA, Unit); + return CollectTemplateParams(GetTemplateArgs(VL), Unit); } -llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams( - const ClassTemplateSpecializationDecl *TSpecial, llvm::DIFile *Unit) { - // Always get the full list of parameters, not just the ones from the - // specialization. A partial specialization may have fewer parameters than - // there are arguments. - TemplateParameterList *TPList = - TSpecial->getSpecializedTemplate()->getTemplateParameters(); - const TemplateArgumentList &TAList = TSpecial->getTemplateArgs(); - return CollectTemplateParams(TPList, TAList.asArray(), Unit); +llvm::DINodeArray CGDebugInfo::CollectCXXTemplateParams(const RecordDecl *RD, + llvm::DIFile *Unit) { + return CollectTemplateParams(GetTemplateArgs(RD), Unit); +} + +llvm::DINodeArray CGDebugInfo::CollectBTFDeclTagAnnotations(const Decl *D) { + if (!D->hasAttr()) + return nullptr; + + SmallVector Annotations; + for (const auto *I : D->specific_attrs()) { + llvm::Metadata *Ops[2] = { + llvm::MDString::get(CGM.getLLVMContext(), StringRef("btf_decl_tag")), + llvm::MDString::get(CGM.getLLVMContext(), I->getBTFDeclTag())}; + Annotations.push_back(llvm::MDNode::get(CGM.getLLVMContext(), Ops)); + } + return DBuilder.getOrCreateArray(Annotations); } llvm::DIType *CGDebugInfo::getOrCreateVTablePtrType(llvm::DIFile *Unit) { @@ -3210,7 +3408,8 @@ void CGDebugInfo::completeUnusedClass(const CXXRecordDecl &D) { RetainedTypes.push_back(CGM.getContext().getRecordType(&D).getAsOpaquePtr()); } -llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { if (Ty.isNull()) return nullptr; @@ -3227,7 +3426,7 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (auto *T = getTypeOrNull(Ty)) return T; - llvm::DIType *Res = CreateTypeNode(Ty, Unit); + llvm::DIType *Res = CreateTypeNode(Ty, Unit, TL); void *TyPtr = Ty.getAsOpaquePtr(); // And update the type cache. @@ -3271,10 +3470,11 @@ llvm::DIModule *CGDebugInfo::getParentModuleOrNull(const Decl *D) { return nullptr; } -llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { +llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit, + TypeLoc TL) { // Handle qualifiers, which recursively handles what they refer to. if (Ty.hasLocalQualifiers()) - return CreateQualifiedType(Ty, Unit); + return CreateQualifiedType(Ty, Unit, TL); // Work out details of type. switch (Ty->getTypeClass()) { @@ -3303,7 +3503,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::Complex: return CreateType(cast(Ty)); case Type::Pointer: - return CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit, TL); case Type::BlockPointer: return CreateType(cast(Ty), Unit); case Type::Typedef: @@ -3314,7 +3514,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { return CreateEnumType(cast(Ty)); case Type::FunctionProto: case Type::FunctionNoProto: - return CreateType(cast(Ty), Unit); + return CreateType(cast(Ty), Unit, TL); case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: @@ -3435,9 +3635,10 @@ llvm::DICompositeType *CGDebugInfo::CreateLimitedType(const RecordType *Ty) { Flags |= llvm::DINode::FlagExportSymbols; } + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); llvm::DICompositeType *RealDecl = DBuilder.createReplaceableCompositeType( getTagForRecord(RD), RDName, RDContext, DefUnit, Line, 0, Size, Align, - Flags, Identifier); + Flags, Identifier, Annotations); // Elements of composite types usually have back to the type, creating // uniquing cycles. Distinct nodes are more efficient. @@ -3858,7 +4059,26 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, getDwarfCC(CC)); } - return cast(getOrCreateType(FnType, F)); + TypeLoc TL; + if (const auto *FD = dyn_cast(D)) { + if (const TypeSourceInfo *TSI = FD->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + } + return cast(getOrCreateType(FnType, F, TL)); +} + +QualType +CGDebugInfo::getFunctionType(const FunctionDecl *FD, QualType RetTy, + const SmallVectorImpl &Args) { + CallingConv CC = CallingConv::CC_C; + if (FD) + if (const auto *SrcFnTy = FD->getType()->getAs()) + CC = SrcFnTy->getCallConv(); + SmallVector ArgTypes; + for (const VarDecl *VD : Args) + ArgTypes.push_back(VD->getType()); + return CGM.getContext().getFunctionType(RetTy, ArgTypes, + FunctionProtoType::ExtProtoInfo(CC)); } void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, @@ -3935,10 +4155,13 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, unsigned ScopeLine = getLineNumber(ScopeLoc); llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit); llvm::DISubprogram *Decl = nullptr; - if (D) + llvm::DINodeArray Annotations = nullptr; + if (D) { Decl = isa(D) ? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags) : getFunctionDeclaration(D); + Annotations = CollectBTFDeclTagAnnotations(D); + } // FIXME: The function declaration we're constructing here is mostly reusing // declarations from CXXMethodDecl and not constructing new ones for arbitrary @@ -3947,7 +4170,8 @@ void CGDebugInfo::emitFunctionStart(GlobalDecl GD, SourceLocation Loc, // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine, - FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl); + FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl, nullptr, + Annotations); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating // code for the initialization of globals. Do not record these decls @@ -4006,10 +4230,11 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); llvm::DISubprogram *SP = DBuilder.createFunction( FDContext, Name, LinkageName, Unit, LineNo, getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, - TParamsArray.get(), getFunctionDeclaration(D)); + TParamsArray.get(), getFunctionDeclaration(D), nullptr, Annotations); if (IsDeclForCallSite) Fn->setSubprogram(SP); @@ -4241,8 +4466,12 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, uint64_t XOffset = 0; if (VD->hasAttr()) Ty = EmitTypeForVarWithBlocksAttr(VD, &XOffset).WrappedType; - else - Ty = getOrCreateType(VD->getType(), Unit); + else { + TypeLoc TL; + if (const TypeSourceInfo *TSI = VD->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + Ty = getOrCreateType(VD->getType(), Unit, TL); + } // If there is no debug info for this type then do not emit debug info // for this variable. @@ -4337,8 +4566,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, // Use DW_OP_deref to tell the debugger to load the pointer and treat it as // the address of the variable. if (UsePointerValue) { - assert(std::find(Expr.begin(), Expr.end(), llvm::dwarf::DW_OP_deref) == - Expr.end() && + assert(!llvm::is_contained(Expr, llvm::dwarf::DW_OP_deref) && "Debug info already contains DW_OP_deref."); Expr.push_back(llvm::dwarf::DW_OP_deref); } @@ -4346,8 +4574,10 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, // Create the descriptor for the variable. llvm::DILocalVariable *D = nullptr; if (ArgNo) { + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(VD); D = DBuilder.createParameterVariable(Scope, Name, *ArgNo, Unit, Line, Ty, - CGM.getLangOpts().Optimize, Flags); + CGM.getLangOpts().Optimize, Flags, + Annotations); } else { // For normal local variable, we will try to find out whether 'VD' is the // copy parameter of coroutine. @@ -4653,7 +4883,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::DIType *fieldType; if (capture->isByRef()) { TypeInfo PtrInfo = C.getTypeInfo(C.VoidPtrTy); - auto Align = PtrInfo.AlignIsRequired ? PtrInfo.Align : 0; + auto Align = PtrInfo.isAlignRequired() ? PtrInfo.Align : 0; // FIXME: This recomputes the layout of the BlockByRefWrapper. uint64_t xoffset; fieldType = @@ -4740,14 +4970,172 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( return GVE; } +namespace { +struct ReconstitutableType : public RecursiveASTVisitor { + bool Reconstitutable = true; + bool VisitVectorType(VectorType *FT) { + Reconstitutable = false; + return false; + } + bool VisitAtomicType(AtomicType *FT) { + Reconstitutable = false; + return false; + } + bool TraverseEnumType(EnumType *ET) { + // Unnamed enums can't be reconstituted due to a lack of column info we + // produce in the DWARF, so we can't get Clang's full name back. + if (const auto *ED = dyn_cast(ET->getDecl())) { + if (!ED->getIdentifier()) { + Reconstitutable = false; + return false; + } + } + return true; + } + bool VisitFunctionProtoType(FunctionProtoType *FT) { + // noexcept is not encoded in DWARF, so the reversi + Reconstitutable &= !isNoexceptExceptionSpec(FT->getExceptionSpecType()); + return Reconstitutable; + } + bool TraverseRecordType(RecordType *RT) { + // Unnamed classes/lambdas can't be reconstituted due to a lack of column + // info we produce in the DWARF, so we can't get Clang's full name back. + // But so long as it's not one of those, it doesn't matter if some sub-type + // of the record (a template parameter) can't be reconstituted - because the + // un-reconstitutable type itself will carry its own name. + const auto *RD = dyn_cast(RT->getDecl()); + if (!RD) + return true; + if (RD->isLambda() || !RD->getIdentifier()) { + Reconstitutable = false; + return false; + } + return true; + } +}; +} // anonymous namespace + +// Test whether a type name could be rebuilt from emitted debug info. +static bool IsReconstitutableType(QualType QT) { + ReconstitutableType T; + T.TraverseType(QT); + return T.Reconstitutable; +} + std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const { std::string Name; llvm::raw_string_ostream OS(Name); - if (const NamedDecl *ND = dyn_cast(D)) { - PrintingPolicy PP = getPrintingPolicy(); - PP.PrintCanonicalTypes = true; - PP.SuppressInlineNamespace = false; + const NamedDecl *ND = dyn_cast(D); + if (!ND) + return Name; + codegenoptions::DebugTemplateNamesKind TemplateNamesKind = + CGM.getCodeGenOpts().getDebugSimpleTemplateNames(); + Optional Args; + + bool IsOperatorOverload = false; // isa(ND); + if (auto *RD = dyn_cast(ND)) { + Args = GetTemplateArgs(RD); + } else if (auto *FD = dyn_cast(ND)) { + Args = GetTemplateArgs(FD); + auto NameKind = ND->getDeclName().getNameKind(); + IsOperatorOverload |= + NameKind == DeclarationName::CXXOperatorName || + NameKind == DeclarationName::CXXConversionFunctionName; + } else if (auto *VD = dyn_cast(ND)) { + Args = GetTemplateArgs(VD); + } + std::function)> HasReconstitutableArgs = + [&](ArrayRef Args) { + return llvm::all_of(Args, [&](const TemplateArgument &TA) { + switch (TA.getKind()) { + case TemplateArgument::Template: + // Easy to reconstitute - the value of the parameter in the debug + // info is the string name of the template. (so the template name + // itself won't benefit from any name rebuilding, but that's a + // representational limitation - maybe DWARF could be + // changed/improved to use some more structural representation) + return true; + case TemplateArgument::Declaration: + // Reference and pointer non-type template parameters point to + // variables, functions, etc and their value is, at best (for + // variables) represented as an address - not a reference to the + // DWARF describing the variable/function/etc. This makes it hard, + // possibly impossible to rebuild the original name - looking up the + // address in the executable file's symbol table would be needed. + return false; + case TemplateArgument::NullPtr: + // These could be rebuilt, but figured they're close enough to the + // declaration case, and not worth rebuilding. + return false; + case TemplateArgument::Pack: + // A pack is invalid if any of the elements of the pack are invalid. + return HasReconstitutableArgs(TA.getPackAsArray()); + case TemplateArgument::Integral: + // Larger integers get encoded as DWARF blocks which are a bit + // harder to parse back into a large integer, etc - so punting on + // this for now. Re-parsing the integers back into APInt is probably + // feasible some day. + return TA.getAsIntegral().getBitWidth() <= 64; + case TemplateArgument::Type: + return IsReconstitutableType(TA.getAsType()); + default: + llvm_unreachable("Other, unresolved, template arguments should " + "not be seen here"); + } + }); + }; + // A conversion operator presents complications/ambiguity if there's a + // conversion to class template that is itself a template, eg: + // template + // operator ns::t1(); + // This should be named, eg: "operator ns::t1" + // (ignoring clang bug that means this is currently "operator t1") + // but if the arguments were stripped, the consumer couldn't differentiate + // whether the template argument list for the conversion type was the + // function's argument list (& no reconstitution was needed) or not. + // This could be handled if reconstitutable names had a separate attribute + // annotating them as such - this would remove the ambiguity. + // + // Alternatively the template argument list could be parsed enough to check + // whether there's one list or two, then compare that with the DWARF + // description of the return type and the template argument lists to determine + // how many lists there should be and if one is missing it could be assumed(?) + // to be the function's template argument list & then be rebuilt. + // + // Other operator overloads that aren't conversion operators could be + // reconstituted but would require a bit more nuance about detecting the + // difference between these different operators during that rebuilding. + bool Reconstitutable = + Args && HasReconstitutableArgs(Args->Args) && !IsOperatorOverload; + + PrintingPolicy PP = getPrintingPolicy(); + + if (TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Full || + !Reconstitutable) { ND->getNameForDiagnostic(OS, PP, Qualified); + } else { + bool Mangled = + TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Mangled; + // check if it's a template + if (Mangled) + OS << "_STN"; + + OS << ND->getDeclName(); + std::string EncodedOriginalName; + llvm::raw_string_ostream EncodedOriginalNameOS(EncodedOriginalName); + EncodedOriginalNameOS << ND->getDeclName(); + + if (Mangled) { + OS << "|"; + printTemplateArgumentList(OS, Args->Args, PP); + printTemplateArgumentList(EncodedOriginalNameOS, Args->Args, PP); +#ifndef NDEBUG + std::string CanonicalOriginalName; + llvm::raw_string_ostream OriginalOS(CanonicalOriginalName); + ND->getNameForDiagnostic(OriginalOS, PP, Qualified); + assert(EncodedOriginalNameOS.str() == OriginalOS.str()); +#endif + } } return Name; } @@ -4807,12 +5195,17 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } AppendAddressSpaceXDeref(AddressSpace, Expr); + TypeLoc TL; + if (const TypeSourceInfo *TSI = D->getTypeSourceInfo()) + TL = TSI->getTypeLoc(); + + llvm::DINodeArray Annotations = CollectBTFDeclTagAnnotations(D); GVE = DBuilder.createGlobalVariableExpression( - DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasLocalLinkage(), true, + DContext, DeclName, LinkageName, Unit, LineNo, + getOrCreateType(T, Unit, TL), Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, - Align); + Align, Annotations); Var->addDebugInfo(GVE); } DeclCache[D->getCanonicalDecl()].reset(GVE); diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index b01165f85a6..a7b72fa5f5a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -178,14 +178,19 @@ class CGDebugInfo { llvm::DIType *CreateType(const ComplexType *Ty); llvm::DIType *CreateType(const AutoType *Ty); llvm::DIType *CreateType(const ExtIntType *Ty); - llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *CreateQualifiedType(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); + llvm::DIType *CreateQualifiedType(const FunctionProtoType *Ty, + llvm::DIFile *Fg); llvm::DIType *CreateType(const TypedefType *Ty, llvm::DIFile *Fg); llvm::DIType *CreateType(const TemplateSpecializationType *Ty, llvm::DIFile *Fg); llvm::DIType *CreateType(const ObjCObjectPointerType *Ty, llvm::DIFile *F); - llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const PointerType *Ty, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); llvm::DIType *CreateType(const BlockPointerType *Ty, llvm::DIFile *F); - llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F); + llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); /// Get structure or union type. llvm::DIType *CreateType(const RecordType *Tyg); llvm::DIType *CreateTypeDefinition(const RecordType *Ty); @@ -240,7 +245,8 @@ class CGDebugInfo { /// \return namespace descriptor for the given namespace decl. llvm::DINamespace *getOrCreateNamespace(const NamespaceDecl *N); llvm::DIType *CreatePointerLikeType(llvm::dwarf::Tag Tag, const Type *Ty, - QualType PointeeTy, llvm::DIFile *F); + QualType PointeeTy, llvm::DIFile *F, + TypeLoc TL = TypeLoc()); llvm::DIType *getOrCreateStructPtrType(StringRef Name, llvm::DIType *&Cache); /// A helper function to create a subprogram for a single member @@ -272,9 +278,12 @@ class CGDebugInfo { llvm::DenseSet> &SeenTypes, llvm::DINode::DIFlags StartingFlags); + struct TemplateArgs { + const TemplateParameterList *TList; + llvm::ArrayRef Args; + }; /// A helper function to collect template parameters. - llvm::DINodeArray CollectTemplateParams(const TemplateParameterList *TPList, - ArrayRef TAList, + llvm::DINodeArray CollectTemplateParams(Optional Args, llvm::DIFile *Unit); /// A helper function to collect debug info for function template /// parameters. @@ -286,17 +295,25 @@ class CGDebugInfo { llvm::DINodeArray CollectVarTemplateParams(const VarDecl *VD, llvm::DIFile *Unit); + Optional GetTemplateArgs(const VarDecl *) const; + Optional GetTemplateArgs(const RecordDecl *) const; + Optional GetTemplateArgs(const FunctionDecl *) const; + /// A helper function to collect debug info for template /// parameters. - llvm::DINodeArray - CollectCXXTemplateParams(const ClassTemplateSpecializationDecl *TS, - llvm::DIFile *F); + llvm::DINodeArray CollectCXXTemplateParams(const RecordDecl *TS, + llvm::DIFile *F); + + /// A helper function to collect debug info for btf_decl_tag annotations. + llvm::DINodeArray CollectBTFDeclTagAnnotations(const Decl *D); llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, uint64_t offsetInBits, uint32_t AlignInBits, llvm::DIFile *tunit, llvm::DIScope *scope, - const RecordDecl *RD = nullptr); + const RecordDecl *RD = nullptr, + llvm::DINodeArray Annotations = nullptr, + TypeLoc TL = TypeLoc()); llvm::DIType *createFieldType(StringRef name, QualType type, SourceLocation loc, AccessSpecifier AS, @@ -417,6 +434,9 @@ public: /// location will be reused. void EmitLocation(CGBuilderTy &Builder, SourceLocation Loc); + QualType getFunctionType(const FunctionDecl *FD, QualType RetTy, + const SmallVectorImpl &Args); + /// Emit a call to llvm.dbg.function.start to indicate /// start of a new function. /// \param Loc The location of the function header. @@ -613,7 +633,8 @@ private: Optional Source); /// Get the type from the cache or create a new type if necessary. - llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *getOrCreateType(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); /// Get a reference to a clang module. If \p CreateSkeletonCU is true, /// this also creates a split dwarf skeleton compile unit. @@ -628,7 +649,8 @@ private: llvm::DICompositeType *getOrCreateLimitedType(const RecordType *Ty); /// Create type metadata for a source language type. - llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg); + llvm::DIType *CreateTypeNode(QualType Ty, llvm::DIFile *Fg, + TypeLoc TL = TypeLoc()); /// Create new member and increase Offset by FType's size. llvm::DIType *CreateMemberType(llvm::DIFile *Unit, QualType FType, diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 5b3d39f20b4..941671c6148 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -1142,7 +1142,7 @@ Address CodeGenModule::createUnnamedGlobalFrom(const VarDecl &D, GV->setAlignment(Align.getAsAlign()); GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); CacheEntry = GV; - } else if (CacheEntry->getAlignment() < Align.getQuantity()) { + } else if (CacheEntry->getAlignment() < uint64_t(Align.getQuantity())) { CacheEntry->setAlignment(Align.getAsAlign()); } @@ -1447,6 +1447,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { if (getLangOpts().OpenMP && OpenMPLocalAddr.isValid()) { address = OpenMPLocalAddr; + AllocaAddr = OpenMPLocalAddr; } else if (Ty->isConstantSizeType()) { // If this value is an array or struct with a statically determinable // constant initializer, there are optimizations we can do. @@ -1492,6 +1493,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // return slot, so that we can elide the copy when returning this // variable (C++0x [class.copy]p34). address = ReturnValue; + AllocaAddr = ReturnValue; if (const RecordType *RecordTy = Ty->getAs()) { const auto *RD = RecordTy->getDecl(); @@ -1503,7 +1505,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // applied. llvm::Value *Zero = Builder.getFalse(); Address NRVOFlag = - CreateTempAlloca(Zero->getType(), CharUnits::One(), "nrvo"); + CreateTempAlloca(Zero->getType(), CharUnits::One(), "nrvo", + /*ArraySize=*/nullptr, &AllocaAddr); EnsureInsertPoint(); Builder.CreateStore(Zero, NRVOFlag); @@ -1605,10 +1608,11 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { DI->setLocation(D.getLocation()); // If NRVO, use a pointer to the return address. - if (UsePointerValue) + if (UsePointerValue) { DebugAddr = ReturnValuePointer; - - (void)DI->EmitDeclareOfAutoVariable(&D, DebugAddr.getPointer(), Builder, + AllocaAddr = ReturnValuePointer; + } + (void)DI->EmitDeclareOfAutoVariable(&D, AllocaAddr.getPointer(), Builder, UsePointerValue); } @@ -2450,6 +2454,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, } Address DeclPtr = Address::invalid(); + Address AllocaPtr = Address::invalid(); bool DoStore = false; bool IsScalar = hasScalarEvaluationKind(Ty); // If we already have a pointer to the argument, reuse the input pointer. @@ -2464,6 +2469,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // from the default address space. auto AllocaAS = CGM.getASTAllocaAddressSpace(); auto *V = DeclPtr.getPointer(); + AllocaPtr = DeclPtr; auto SrcLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : AllocaAS; auto DestLangAS = getLangOpts().OpenCL ? LangAS::opencl_private : LangAS::Default; @@ -2500,10 +2506,11 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, : Address::invalid(); if (getLangOpts().OpenMP && OpenMPLocalAddr.isValid()) { DeclPtr = OpenMPLocalAddr; + AllocaPtr = DeclPtr; } else { // Otherwise, create a temporary to hold the value. DeclPtr = CreateMemTemp(Ty, getContext().getDeclAlign(&D), - D.getName() + ".addr"); + D.getName() + ".addr", &AllocaPtr); } DoStore = true; } @@ -2579,7 +2586,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk) { llvm::DILocalVariable *DILocalVar = DI->EmitDeclareOfArgVariable( - &D, DeclPtr.getPointer(), ArgNo, Builder); + &D, AllocaPtr.getPointer(), ArgNo, Builder); if (const auto *Var = dyn_cast_or_null(&D)) DI->getParamDbgMappings().insert({Var, DILocalVar}); } diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index d43fb99550a..d22f9dc3b68 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -555,7 +555,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); } else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) || - getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR) { + getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR || + D->hasAttr()) { // C++ [basic.start.init]p2: // Definitions of explicitly specialized class template static data // members have ordered initialization. Other class template static data @@ -568,17 +569,28 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, // group with the global being initialized. On most platforms, this is a // minor startup time optimization. In the MS C++ ABI, there are no guard // variables, so this COMDAT key is required for correctness. - AddGlobalCtor(Fn, 65535, COMDATKey); - if (getTarget().getCXXABI().isMicrosoft() && COMDATKey) { - // In The MS C++, MS add template static data member in the linker - // drective. - addUsedGlobal(COMDATKey); - } - } else if (D->hasAttr()) { + // // SelectAny globals will be comdat-folded. Put the initializer into a // COMDAT group associated with the global, so the initializers get folded // too. + AddGlobalCtor(Fn, 65535, COMDATKey); + if (COMDATKey && (getTriple().isOSBinFormatELF() || + getTarget().getCXXABI().isMicrosoft())) { + // When COMDAT is used on ELF or in the MS C++ ABI, the key must be in + // llvm.used to prevent linker GC. + addUsedGlobal(COMDATKey); + } + + // If we used a COMDAT key for the global ctor, the init function can be + // discarded if the global ctor entry is discarded. + // FIXME: Do we need to restrict this to ELF and Wasm? + llvm::Comdat *C = Addr->getComdat(); + if (COMDATKey && C && + (getTarget().getTriple().isOSBinFormatELF() || + getTarget().getTriple().isOSBinFormatWasm())) { + Fn->setComdat(C); + } } else { I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash. if (I == DelayedCXXInitPosition.end()) { diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 9f65e9eb120..aff9c77d53c 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -477,11 +477,11 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) { - // noexcept functions are simple terminate scopes. - if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur - EHStack.pushTerminate(); - } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + // In C++17 and later, 'throw()' aka EST_DynamicNone is treated the same way + // as noexcept. In earlier standards, it is handled in this block, along with + // 'throw(X...)'. + if (EST == EST_Dynamic || + (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { // TODO: Revisit exception specifications for the MS ABI. There is a way to // encode these in an object file but MSVC doesn't do anything with it. if (getTarget().getCXXABI().isMicrosoft()) @@ -521,6 +521,10 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { /*ForEH=*/true); Filter->setFilter(I, EHType); } + } else if (Proto->canThrow() == CT_Cannot) { + // noexcept functions are simple terminate scopes. + if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur + EHStack.pushTerminate(); } } @@ -580,10 +584,8 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { return; ExceptionSpecificationType EST = Proto->getExceptionSpecType(); - if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot && - !EHStack.empty() /* possible empty when under async exceptions */) { - EHStack.popTerminate(); - } else if (EST == EST_Dynamic || EST == EST_DynamicNone) { + if (EST == EST_Dynamic || + (EST == EST_DynamicNone && !getLangOpts().CPlusPlus17)) { // TODO: Revisit exception specifications for the MS ABI. There is a way to // encode these in an object file but MSVC doesn't do anything with it. if (getTarget().getCXXABI().isMicrosoft()) @@ -599,6 +601,10 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { EHFilterScope &filterScope = cast(*EHStack.begin()); emitFilterDispatchBlock(*this, filterScope); EHStack.popFilter(); + } else if (Proto->canThrow() == CT_Cannot && + /* possible empty when under async exceptions */ + !EHStack.empty()) { + EHStack.popTerminate(); } } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index bf514aab885..4332e74dbb2 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -35,6 +35,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/MatrixBuilder.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" @@ -94,7 +95,7 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, // otherwise alloca is inserted at the current insertion point of the // builder. if (!ArraySize) - Builder.SetInsertPoint(AllocaInsertPt); + Builder.SetInsertPoint(getPostAllocaInsertPoint()); V = getTargetHooks().performAddrSpaceCast( *this, V, getASTAllocaAddressSpace(), LangAS::Default, Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); @@ -122,23 +123,10 @@ llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, const Twine &Name) { CharUnits Align = - CharUnits::fromQuantity(CGM.getDataLayout().getABITypeAlignment(Ty)); + CharUnits::fromQuantity(CGM.getDataLayout().getPrefTypeAlignment(Ty)); return CreateTempAlloca(Ty, Align, Name); } -void CodeGenFunction::InitTempAlloca(Address Var, llvm::Value *Init) { - auto *Alloca = Var.getPointer(); - assert(isa(Alloca) || - (isa(Alloca) && - isa( - cast(Alloca)->getPointerOperand()))); - - auto *Store = new llvm::StoreInst(Init, Alloca, /*volatile*/ false, - Var.getAlignment().getAsAlign()); - llvm::BasicBlock *Block = AllocaInsertPt->getParent(); - Block->getInstList().insertAfter(AllocaInsertPt->getIterator(), Store); -} - Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { CharUnits Align = getContext().getTypeAlignInChars(Ty); return CreateTempAlloca(ConvertType(Ty), Align, Name); @@ -580,8 +568,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // Perform derived-to-base casts and/or field accesses, to get from the // temporary object we created (and, potentially, for which we extended // the lifetime) to the subobject we're binding the reference to. - for (unsigned I = Adjustments.size(); I != 0; --I) { - SubobjectAdjustment &Adjustment = Adjustments[I-1]; + for (SubobjectAdjustment &Adjustment : llvm::reverse(Adjustments)) { switch (Adjustment.Kind) { case SubobjectAdjustment::DerivedToBaseAdjustment: Object = @@ -667,9 +654,9 @@ bool CodeGenFunction::isVptrCheckRequired(TypeCheckKind TCK, QualType Ty) { } bool CodeGenFunction::sanitizePerformTypeCheck() const { - return SanOpts.has(SanitizerKind::Null) | - SanOpts.has(SanitizerKind::Alignment) | - SanOpts.has(SanitizerKind::ObjectSize) | + return SanOpts.has(SanitizerKind::Null) || + SanOpts.has(SanitizerKind::Alignment) || + SanOpts.has(SanitizerKind::ObjectSize) || SanOpts.has(SanitizerKind::Vptr); } @@ -1642,7 +1629,7 @@ static bool getRangeForType(CodeGenFunction &CGF, QualType Ty, } else { assert(NumPositiveBits <= Bitwidth); End = llvm::APInt(Bitwidth, 1) << NumPositiveBits; - Min = llvm::APInt(Bitwidth, 0); + Min = llvm::APInt::getZero(Bitwidth); } } return true; @@ -1939,10 +1926,15 @@ RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { return EmitLoadOfGlobalRegLValue(LV); if (LV.isMatrixElt()) { + llvm::Value *Idx = LV.getMatrixIdx(); + if (CGM.getCodeGenOpts().OptimizationLevel > 0) { + const auto *const MatTy = LV.getType()->getAs(); + llvm::MatrixBuilder MB(Builder); + MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened()); + } llvm::LoadInst *Load = Builder.CreateLoad(LV.getMatrixAddress(), LV.isVolatileQualified()); - return RValue::get( - Builder.CreateExtractElement(Load, LV.getMatrixIdx(), "matrixext")); + return RValue::get(Builder.CreateExtractElement(Load, Idx, "matrixext")); } assert(LV.isBitField() && "Unknown LValue type!"); @@ -2080,9 +2072,15 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, return EmitStoreThroughGlobalRegLValue(Src, Dst); if (Dst.isMatrixElt()) { - llvm::Value *Vec = Builder.CreateLoad(Dst.getMatrixAddress()); - Vec = Builder.CreateInsertElement(Vec, Src.getScalarVal(), - Dst.getMatrixIdx(), "matins"); + llvm::Value *Idx = Dst.getMatrixIdx(); + if (CGM.getCodeGenOpts().OptimizationLevel > 0) { + const auto *const MatTy = Dst.getType()->getAs(); + llvm::MatrixBuilder MB(Builder); + MB.CreateIndexAssumption(Idx, MatTy->getNumElementsFlattened()); + } + llvm::Instruction *Load = Builder.CreateLoad(Dst.getMatrixAddress()); + llvm::Value *Vec = + Builder.CreateInsertElement(Load, Src.getScalarVal(), Idx, "matins"); Builder.CreateStore(Vec, Dst.getMatrixAddress(), Dst.isVolatileQualified()); return; @@ -3498,7 +3496,7 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked, if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", CGM.getCodeGenOpts().TrapFuncName); - TrapCall->addAttribute(llvm::AttributeList::FunctionIndex, A); + TrapCall->addFnAttr(A); } TrapCall->setDoesNotReturn(); TrapCall->setDoesNotThrow(); @@ -3522,7 +3520,7 @@ llvm::CallInst *CodeGenFunction::EmitTrapCall(llvm::Intrinsic::ID IntrID) { if (!CGM.getCodeGenOpts().TrapFuncName.empty()) { auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name", CGM.getCodeGenOpts().TrapFuncName); - TrapCall->addAttribute(llvm::AttributeList::FunctionIndex, A); + TrapCall->addFnAttr(A); } return TrapCall; @@ -4684,10 +4682,28 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_UserDefinedConversion: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: - case CK_NoOp: case CK_LValueToRValue: return EmitLValue(E->getSubExpr()); + case CK_NoOp: { + // CK_NoOp can model a qualification conversion, which can remove an array + // bound and change the IR type. + // FIXME: Once pointee types are removed from IR, remove this. + LValue LV = EmitLValue(E->getSubExpr()); + if (LV.isSimple()) { + Address V = LV.getAddress(*this); + if (V.isValid()) { + llvm::Type *T = + ConvertTypeForMem(E->getType()) + ->getPointerTo( + cast(V.getType())->getAddressSpace()); + if (V.getType() != T) + LV.setAddress(Builder.CreateBitCast(V, T)); + } + } + return LV; + } + case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { const auto *DerivedClassTy = @@ -4879,12 +4895,28 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) { const FunctionDecl *FD = cast(GD.getDecl()); if (auto builtinID = FD->getBuiltinID()) { - // Replaceable builtin provide their own implementation of a builtin. Unless - // we are in the builtin implementation itself, don't call the actual - // builtin. If we are in the builtin implementation, avoid trivial infinite + std::string FDInlineName = (FD->getName() + ".inline").str(); + // When directing calling an inline builtin, call it through it's mangled + // name to make it clear it's not the actual builtin. + if (FD->isInlineBuiltinDeclaration() && + CGF.CurFn->getName() != FDInlineName) { + llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD); + llvm::Function *Fn = llvm::cast(CalleePtr); + llvm::Module *M = Fn->getParent(); + llvm::Function *Clone = M->getFunction(FDInlineName); + if (!Clone) { + Clone = llvm::Function::Create(Fn->getFunctionType(), + llvm::GlobalValue::InternalLinkage, + Fn->getAddressSpace(), FDInlineName, M); + Clone->addFnAttr(llvm::Attribute::AlwaysInline); + } + return CGCallee::forDirect(Clone, GD); + } + + // Replaceable builtins provide their own implementation of a builtin. If we + // are in an inline builtin implementation, avoid trivial infinite // recursion. - if (!FD->isInlineBuiltinDeclaration() || - CGF.CurFn->getName() == FD->getName()) + else return CGCallee::forBuiltin(builtinID, FD); } @@ -4893,6 +4925,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) { FD->hasAttr()) CalleePtr = CGF.CGM.getCUDARuntime().getKernelStub( cast(CalleePtr->stripPointerCasts())); + return CGCallee::forDirect(CalleePtr, GD); } @@ -5306,9 +5339,13 @@ RValue CodeGenFunction::EmitCall(QualType CalleeType, const CGCallee &OrigCallee // Generate function declaration DISuprogram in order to be used // in debug info about call sites. if (CGDebugInfo *DI = getDebugInfo()) { - if (auto *CalleeDecl = dyn_cast_or_null(TargetDecl)) - DI->EmitFuncDeclForCallSite(CallOrInvoke, QualType(FnType, 0), + if (auto *CalleeDecl = dyn_cast_or_null(TargetDecl)) { + FunctionArgList Args; + QualType ResTy = BuildFunctionArgList(CalleeDecl, Args); + DI->EmitFuncDeclForCallSite(CallOrInvoke, + DI->getFunctionType(CalleeDecl, ResTy, Args), CalleeDecl); + } } return Call; diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 1e81ad9f2dc..5b56a587fa5 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -127,6 +127,8 @@ public: } void VisitConstantExpr(ConstantExpr *E) { + EnsureDest(E->getType()); + if (llvm::Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) { CGF.EmitAggregateStore(Result, Dest.getAddress(), E->getType().isVolatileQualified()); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 96cf977ca29..cc838bf38c6 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -609,15 +609,18 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, return; // Elide the constructor if we're constructing from a temporary. - // The temporary check is required because Sema sets this on NRVO - // returns. if (getLangOpts().ElideConstructors && E->isElidable()) { - assert(getContext().hasSameUnqualifiedType(E->getType(), - E->getArg(0)->getType())); - if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) { - EmitAggExpr(E->getArg(0), Dest); - return; - } + // FIXME: This only handles the simplest case, where the source object + // is passed directly as the first argument to the constructor. + // This should also handle stepping though implicit casts and + // conversion sequences which involve two steps, with a + // conversion operator followed by a converting constructor. + const Expr *SrcObj = E->getArg(0); + assert(SrcObj->isTemporaryObject(getContext(), CD->getParent())); + assert( + getContext().hasSameUnqualifiedType(E->getType(), SrcObj->getType())); + EmitAggExpr(SrcObj, Dest); + return; } if (const ArrayType *arrayType @@ -1323,8 +1326,7 @@ static RValue EmitNewDeleteCall(CodeGenFunction &CGF, llvm::Function *Fn = dyn_cast(CalleePtr); if (CalleeDecl->isReplaceableGlobalAllocationFunction() && Fn && Fn->hasFnAttribute(llvm::Attribute::NoBuiltin)) { - CallOrInvoke->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::Builtin); + CallOrInvoke->addFnAttr(llvm::Attribute::Builtin); } return RV; diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 734024149bb..ff900ed077e 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -1369,7 +1369,7 @@ llvm::Constant *ConstantEmitter::tryEmitConstantExpr(const ConstantExpr *CE) { const Expr *Inner = CE->getSubExpr()->IgnoreImplicit(); QualType RetType; if (auto *Call = dyn_cast(Inner)) - RetType = Call->getCallReturnType(CGF->getContext()); + RetType = Call->getCallReturnType(CGM.getContext()); else if (auto *Ctor = dyn_cast(Inner)) RetType = Ctor->getType(); llvm::Constant *Res = @@ -1714,6 +1714,8 @@ llvm::Constant *ConstantEmitter::emitForMemory(CodeGenModule &CGM, llvm::Constant *ConstantEmitter::tryEmitPrivate(const Expr *E, QualType destType) { + assert(!destType->isVoidType() && "can't emit a void constant"); + Expr::EvalResult Result; bool Success = false; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 418f23bd1a9..ae9434f9652 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -419,6 +419,11 @@ public: Value *VisitExpr(Expr *S); Value *VisitConstantExpr(ConstantExpr *E) { + // A constant expression of type 'void' generates no code and produces no + // value. + if (E->getType()->isVoidType()) + return nullptr; + if (Value *Result = ConstantEmitter(CGF).tryEmitConstantExpr(E)) { if (E->isGLValue()) return CGF.Builder.CreateLoad(Address( @@ -1647,7 +1652,7 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { for (unsigned i = 2; i < E->getNumSubExprs(); ++i) { llvm::APSInt Idx = E->getShuffleMaskIdx(CGF.getContext(), i-2); // Check for -1 and output it as undef in the IR. - if (Idx.isSigned() && Idx.isAllOnesValue()) + if (Idx.isSigned() && Idx.isAllOnes()) Indices.push_back(-1); else Indices.push_back(Idx.getZExtValue()); @@ -1775,13 +1780,18 @@ Value *ScalarExprEmitter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *E) { // integer value. Value *RowIdx = Visit(E->getRowIdx()); Value *ColumnIdx = Visit(E->getColumnIdx()); + + const auto *MatrixTy = E->getBase()->getType()->castAs(); + unsigned NumRows = MatrixTy->getNumRows(); + llvm::MatrixBuilder MB(Builder); + Value *Idx = MB.CreateIndex(RowIdx, ColumnIdx, NumRows); + if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0) + MB.CreateIndexAssumption(Idx, MatrixTy->getNumElementsFlattened()); + Value *Matrix = Visit(E->getBase()); // TODO: Should we emit bounds checks with SanitizerKind::ArrayBounds? - llvm::MatrixBuilder MB(Builder); - return MB.CreateExtractElement( - Matrix, RowIdx, ColumnIdx, - E->getBase()->getType()->castAs()->getNumRows()); + return Builder.CreateExtractElement(Matrix, Idx, "matrixext"); } static int getMaskElt(llvm::ShuffleVectorInst *SVI, unsigned Idx, @@ -2063,11 +2073,25 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // perform the bitcast. if (const auto *FixedSrc = dyn_cast(SrcTy)) { if (const auto *ScalableDst = dyn_cast(DstTy)) { + // If we are casting a fixed i8 vector to a scalable 16 x i1 predicate + // vector, use a vector insert and bitcast the result. + bool NeedsBitCast = false; + auto PredType = llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16); + llvm::Type *OrigType = DstTy; + if (ScalableDst == PredType && + FixedSrc->getElementType() == Builder.getInt8Ty()) { + DstTy = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2); + ScalableDst = dyn_cast(DstTy); + NeedsBitCast = true; + } if (FixedSrc->getElementType() == ScalableDst->getElementType()) { llvm::Value *UndefVec = llvm::UndefValue::get(DstTy); llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty); - return Builder.CreateInsertVector(DstTy, UndefVec, Src, Zero, - "castScalableSve"); + llvm::Value *Result = Builder.CreateInsertVector( + DstTy, UndefVec, Src, Zero, "castScalableSve"); + if (NeedsBitCast) + Result = Builder.CreateBitCast(Result, OrigType); + return Result; } } } @@ -2077,6 +2101,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // perform the bitcast. if (const auto *ScalableSrc = dyn_cast(SrcTy)) { if (const auto *FixedDst = dyn_cast(DstTy)) { + // If we are casting a scalable 16 x i1 predicate vector to a fixed i8 + // vector, bitcast the source and use a vector extract. + auto PredType = llvm::ScalableVectorType::get(Builder.getInt1Ty(), 16); + if (ScalableSrc == PredType && + FixedDst->getElementType() == Builder.getInt8Ty()) { + SrcTy = llvm::ScalableVectorType::get(Builder.getInt8Ty(), 2); + ScalableSrc = dyn_cast(SrcTy); + Src = Builder.CreateBitCast(Src, SrcTy); + } if (ScalableSrc->getElementType() == FixedDst->getElementType()) { llvm::Value *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty); return Builder.CreateExtractVector(DstTy, Src, Zero, "castFixedSve"); @@ -2087,10 +2120,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // Perform VLAT <-> VLST bitcast through memory. // TODO: since the llvm.experimental.vector.{insert,extract} intrinsics // require the element types of the vectors to be the same, we - // need to keep this around for casting between predicates, or more - // generally for bitcasts between VLAT <-> VLST where the element - // types of the vectors are not the same, until we figure out a better - // way of doing these casts. + // need to keep this around for bitcasts between VLAT <-> VLST where + // the element types of the vectors are not the same, until we figure + // out a better way of doing these casts. if ((isa(SrcTy) && isa(DstTy)) || (isa(SrcTy) && @@ -2127,10 +2159,22 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } case CK_AtomicToNonAtomic: case CK_NonAtomicToAtomic: - case CK_NoOp: case CK_UserDefinedConversion: return Visit(const_cast(E)); + case CK_NoOp: { + llvm::Value *V = Visit(const_cast(E)); + if (V) { + // CK_NoOp can model a pointer qualification conversion, which can remove + // an array bound and change the IR type. + // FIXME: Once pointee types are removed from IR, remove this. + llvm::Type *T = ConvertType(DestTy); + if (T != V->getType()) + V = Builder.CreateBitCast(V, T); + } + return V; + } + case CK_BaseToDerived: { const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl(); assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!"); @@ -2658,7 +2702,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, amt = llvm::ConstantFP::get(VMContext, llvm::APFloat(static_cast(amount))); else { - // Remaining types are Half, LongDouble or __float128. Convert from float. + // Remaining types are Half, LongDouble, __ibm128 or __float128. Convert + // from float. llvm::APFloat F(static_cast(amount)); bool ignored; const llvm::fltSemantics *FS; @@ -2668,6 +2713,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, FS = &CGF.getTarget().getFloat128Format(); else if (value->getType()->isHalfTy()) FS = &CGF.getTarget().getHalfFormat(); + else if (value->getType()->isPPC_FP128Ty()) + FS = &CGF.getTarget().getIbm128Format(); else FS = &CGF.getTarget().getLongDoubleFormat(); F.convert(*FS, llvm::APFloat::rmTowardZero, &ignored); @@ -4763,11 +4810,8 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { // vector to get a vec4, then a bitcast if the target type is different. if (NumElementsSrc == 3 && NumElementsDst != 3) { Src = ConvertVec3AndVec4(Builder, CGF, Src, 4); - - if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) { - Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, - DstTy); - } + Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, + DstTy); Src->setName("astype"); return Src; @@ -4777,12 +4821,10 @@ Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { // to vec4 if the original type is not vec4, then a shuffle vector to // get a vec3. if (NumElementsSrc != 3 && NumElementsDst == 3) { - if (!CGF.CGM.getCodeGenOpts().PreserveVec3Type) { - auto *Vec4Ty = llvm::FixedVectorType::get( - cast(DstTy)->getElementType(), 4); - Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, - Vec4Ty); - } + auto *Vec4Ty = llvm::FixedVectorType::get( + cast(DstTy)->getElementType(), 4); + Src = createCastsForTypeOfSameSize(Builder, CGF.CGM.getDataLayout(), Src, + Vec4Ty); Src = ConvertVec3AndVec4(Builder, CGF, Src, 3); Src->setName("astype"); @@ -4942,7 +4984,7 @@ static GEPOffsetAndOverflow EmitGEPOffsetInBytes(Value *BasePtr, Value *GEPVal, auto *GEP = cast(GEPVal); assert(GEP->getPointerOperand() == BasePtr && - "BasePtr must be the the base of the GEP."); + "BasePtr must be the base of the GEP."); assert(GEP->isInBounds() && "Expected inbounds GEP"); auto *IntPtrTy = DL.getIntPtrType(GEP->getPointerOperandType()); diff --git a/clang/lib/CodeGen/CGGPUBuiltin.cpp b/clang/lib/CodeGen/CGGPUBuiltin.cpp index f860623e2bc..fdd2fa18bb4 100644 --- a/clang/lib/CodeGen/CGGPUBuiltin.cpp +++ b/clang/lib/CodeGen/CGGPUBuiltin.cpp @@ -21,13 +21,14 @@ using namespace clang; using namespace CodeGen; -static llvm::Function *GetVprintfDeclaration(llvm::Module &M) { +namespace { +llvm::Function *GetVprintfDeclaration(llvm::Module &M) { llvm::Type *ArgTypes[] = {llvm::Type::getInt8PtrTy(M.getContext()), llvm::Type::getInt8PtrTy(M.getContext())}; llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get( llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false); - if (auto* F = M.getFunction("vprintf")) { + if (auto *F = M.getFunction("vprintf")) { // Our CUDA system header declares vprintf with the right signature, so // nobody else should have been able to declare vprintf with a bogus // signature. @@ -41,6 +42,28 @@ static llvm::Function *GetVprintfDeclaration(llvm::Module &M) { VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M); } +llvm::Function *GetOpenMPVprintfDeclaration(CodeGenModule &CGM) { + const char *Name = "__llvm_omp_vprintf"; + llvm::Module &M = CGM.getModule(); + llvm::Type *ArgTypes[] = {llvm::Type::getInt8PtrTy(M.getContext()), + llvm::Type::getInt8PtrTy(M.getContext()), + llvm::Type::getInt32Ty(M.getContext())}; + llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get( + llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false); + + if (auto *F = M.getFunction(Name)) { + if (F->getFunctionType() != VprintfFuncType) { + CGM.Error(SourceLocation(), + "Invalid type declaration for __llvm_omp_vprintf"); + return nullptr; + } + return F; + } + + return llvm::Function::Create( + VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, Name, &M); +} + // Transforms a call to printf into a call to the NVPTX vprintf syscall (which // isn't particularly special; it's invoked just like a regular function). // vprintf takes two args: A format string, and a pointer to a buffer containing @@ -66,39 +89,22 @@ static llvm::Function *GetVprintfDeclaration(llvm::Module &M) { // // Note that by the time this function runs, E's args have already undergone the // standard C vararg promotion (short -> int, float -> double, etc.). -RValue -CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue) { - assert(getTarget().getTriple().isNVPTX()); - assert(E->getBuiltinCallee() == Builtin::BIprintf); - assert(E->getNumArgs() >= 1); // printf always has at least one arg. - const llvm::DataLayout &DL = CGM.getDataLayout(); - llvm::LLVMContext &Ctx = CGM.getLLVMContext(); - - CallArgList Args; - EmitCallArgs(Args, - E->getDirectCallee()->getType()->getAs(), - E->arguments(), E->getDirectCallee(), - /* ParamsToSkip = */ 0); - - // We don't know how to emit non-scalar varargs. - if (std::any_of(Args.begin() + 1, Args.end(), [&](const CallArg &A) { - return !A.getRValue(*this).isScalar(); - })) { - CGM.ErrorUnsupported(E, "non-scalar arg to printf"); - return RValue::get(llvm::ConstantInt::get(IntTy, 0)); - } +std::pair +packArgsIntoNVPTXFormatBuffer(CodeGenFunction *CGF, const CallArgList &Args) { + const llvm::DataLayout &DL = CGF->CGM.getDataLayout(); + llvm::LLVMContext &Ctx = CGF->CGM.getLLVMContext(); + CGBuilderTy &Builder = CGF->Builder; // Construct and fill the args buffer that we'll pass to vprintf. - llvm::Value *BufferPtr; if (Args.size() <= 1) { - // If there are no args, pass a null pointer to vprintf. - BufferPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(Ctx)); + // If there are no args, pass a null pointer and size 0 + llvm::Value * BufferPtr = llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(Ctx)); + return {BufferPtr, llvm::TypeSize::Fixed(0)}; } else { llvm::SmallVector ArgTypes; for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) - ArgTypes.push_back(Args[I].getRValue(*this).getScalarVal()->getType()); + ArgTypes.push_back(Args[I].getRValue(*CGF).getScalarVal()->getType()); // Using llvm::StructType is correct only because printf doesn't accept // aggregates. If we had to handle aggregates here, we'd have to manually @@ -106,25 +112,71 @@ CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E, // that the alignment of the llvm type was the same as the alignment of the // clang type. llvm::Type *AllocaTy = llvm::StructType::create(ArgTypes, "printf_args"); - llvm::Value *Alloca = CreateTempAlloca(AllocaTy); + llvm::Value *Alloca = CGF->CreateTempAlloca(AllocaTy); for (unsigned I = 1, NumArgs = Args.size(); I < NumArgs; ++I) { llvm::Value *P = Builder.CreateStructGEP(AllocaTy, Alloca, I - 1); - llvm::Value *Arg = Args[I].getRValue(*this).getScalarVal(); + llvm::Value *Arg = Args[I].getRValue(*CGF).getScalarVal(); Builder.CreateAlignedStore(Arg, P, DL.getPrefTypeAlign(Arg->getType())); } - BufferPtr = Builder.CreatePointerCast(Alloca, llvm::Type::getInt8PtrTy(Ctx)); + llvm::Value *BufferPtr = + Builder.CreatePointerCast(Alloca, llvm::Type::getInt8PtrTy(Ctx)); + return {BufferPtr, DL.getTypeAllocSize(AllocaTy)}; } - - // Invoke vprintf and return. - llvm::Function* VprintfFunc = GetVprintfDeclaration(CGM.getModule()); - return RValue::get(Builder.CreateCall( - VprintfFunc, {Args[0].getRValue(*this).getScalarVal(), BufferPtr})); } -RValue -CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue) { +bool containsNonScalarVarargs(CodeGenFunction *CGF, CallArgList Args) { + return llvm::any_of(llvm::drop_begin(Args), [&](const CallArg &A) { + return !A.getRValue(*CGF).isScalar(); + }); +} + +RValue EmitDevicePrintfCallExpr(const CallExpr *E, CodeGenFunction *CGF, + llvm::Function *Decl, bool WithSizeArg) { + CodeGenModule &CGM = CGF->CGM; + CGBuilderTy &Builder = CGF->Builder; + assert(E->getBuiltinCallee() == Builtin::BIprintf); + assert(E->getNumArgs() >= 1); // printf always has at least one arg. + + // Uses the same format as nvptx for the argument packing, but also passes + // an i32 for the total size of the passed pointer + CallArgList Args; + CGF->EmitCallArgs(Args, + E->getDirectCallee()->getType()->getAs(), + E->arguments(), E->getDirectCallee(), + /* ParamsToSkip = */ 0); + + // We don't know how to emit non-scalar varargs. + if (containsNonScalarVarargs(CGF, Args)) { + CGM.ErrorUnsupported(E, "non-scalar arg to printf"); + return RValue::get(llvm::ConstantInt::get(CGF->IntTy, 0)); + } + + auto r = packArgsIntoNVPTXFormatBuffer(CGF, Args); + llvm::Value *BufferPtr = r.first; + + llvm::SmallVector Vec = { + Args[0].getRValue(*CGF).getScalarVal(), BufferPtr}; + if (WithSizeArg) { + // Passing > 32bit of data as a local alloca doesn't work for nvptx or + // amdgpu + llvm::Constant *Size = + llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGM.getLLVMContext()), + static_cast(r.second.getFixedSize())); + + Vec.push_back(Size); + } + return RValue::get(Builder.CreateCall(Decl, Vec)); +} +} // namespace + +RValue CodeGenFunction::EmitNVPTXDevicePrintfCallExpr(const CallExpr *E) { + assert(getTarget().getTriple().isNVPTX()); + return EmitDevicePrintfCallExpr( + E, this, GetVprintfDeclaration(CGM.getModule()), false); +} + +RValue CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E) { assert(getTarget().getTriple().getArch() == llvm::Triple::amdgcn); assert(E->getBuiltinCallee() == Builtin::BIprintf || E->getBuiltinCallee() == Builtin::BI__builtin_printf); @@ -154,3 +206,10 @@ CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E, Builder.SetInsertPoint(IRB.GetInsertBlock(), IRB.GetInsertPoint()); return RValue::get(Printf); } + +RValue CodeGenFunction::EmitOpenMPDevicePrintfCallExpr(const CallExpr *E) { + assert(getTarget().getTriple().isNVPTX() || + getTarget().getTriple().isAMDGCN()); + return EmitDevicePrintfCallExpr(E, this, GetOpenMPVprintfDeclaration(CGM), + true); +} diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 937a0e8a3b6..ac26f0d4232 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1555,6 +1555,12 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, argCK = CK_AnyPointerToBlockPointerCast; } else if (ivarRef.getType()->isPointerType()) { argCK = CK_BitCast; + } else if (argLoad.getType()->isAtomicType() && + !ivarRef.getType()->isAtomicType()) { + argCK = CK_AtomicToNonAtomic; + } else if (!argLoad.getType()->isAtomicType() && + ivarRef.getType()->isAtomicType()) { + argCK = CK_NonAtomicToAtomic; } ImplicitCastExpr argCast(ImplicitCastExpr::OnStack, ivarRef.getType(), argCK, &argLoad, VK_PRValue, FPOptionsOverride()); @@ -2108,6 +2114,13 @@ static void setARCRuntimeFunctionLinkage(CodeGenModule &CGM, setARCRuntimeFunctionLinkage(CGM, RTF.getCallee()); } +static llvm::Function *getARCIntrinsic(llvm::Intrinsic::ID IntID, + CodeGenModule &CGM) { + llvm::Function *fn = CGM.getIntrinsic(IntID); + setARCRuntimeFunctionLinkage(CGM, fn); + return fn; +} + /// Perform an operation having the signature /// i8* (i8*) /// where a null input causes a no-op and returns null. @@ -2118,10 +2131,8 @@ static llvm::Value *emitARCValueOperation( if (isa(value)) return value; - if (!fn) { - fn = CGF.CGM.getIntrinsic(IntID); - setARCRuntimeFunctionLinkage(CGF.CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(IntID, CGF.CGM); // Cast the argument to 'id'. llvm::Type *origType = returnType ? returnType : value->getType(); @@ -2140,10 +2151,8 @@ static llvm::Value *emitARCValueOperation( static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, Address addr, llvm::Function *&fn, llvm::Intrinsic::ID IntID) { - if (!fn) { - fn = CGF.CGM.getIntrinsic(IntID); - setARCRuntimeFunctionLinkage(CGF.CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(IntID, CGF.CGM); // Cast the argument to 'id*'. llvm::Type *origType = addr.getElementType(); @@ -2168,10 +2177,8 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, Address addr, bool ignored) { assert(addr.getElementType() == value->getType()); - if (!fn) { - fn = CGF.CGM.getIntrinsic(IntID); - setARCRuntimeFunctionLinkage(CGF.CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(IntID, CGF.CGM); llvm::Type *origType = value->getType(); @@ -2193,10 +2200,8 @@ static void emitARCCopyOperation(CodeGenFunction &CGF, Address dst, Address src, llvm::Intrinsic::ID IntID) { assert(dst.getType() == src.getType()); - if (!fn) { - fn = CGF.CGM.getIntrinsic(IntID); - setARCRuntimeFunctionLinkage(CGF.CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(IntID, CGF.CGM); llvm::Value *args[] = { CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy), @@ -2340,13 +2345,22 @@ static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value, // retainRV or claimRV calls in the IR. We currently do this only when the // optimization level isn't -O0 since global-isel, which is currently run at // -O0, doesn't know about the operand bundle. + ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints(); + llvm::Function *&EP = IsRetainRV + ? EPs.objc_retainAutoreleasedReturnValue + : EPs.objc_unsafeClaimAutoreleasedReturnValue; + llvm::Intrinsic::ID IID = + IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue + : llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue; + EP = getARCIntrinsic(IID, CGF.CGM); - // FIXME: Do this when the target isn't aarch64. + llvm::Triple::ArchType Arch = CGF.CGM.getTriple().getArch(); + + // FIXME: Do this on all targets and at -O0 too. This can be enabled only if + // the target backend knows how to handle the operand bundle. if (CGF.CGM.getCodeGenOpts().OptimizationLevel > 0 && - CGF.CGM.getTarget().getTriple().isAArch64()) { - llvm::Value *bundleArgs[] = {llvm::ConstantInt::get( - CGF.Int64Ty, - llvm::objcarc::getAttachedCallOperandBundleEnum(IsRetainRV))}; + (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::x86_64)) { + llvm::Value *bundleArgs[] = {EP}; llvm::OperandBundleDef OB("clang.arc.attachedcall", bundleArgs); auto *oldCall = cast(value); llvm::CallBase *newCall = llvm::CallBase::addOperandBundle( @@ -2362,13 +2376,6 @@ static llvm::Value *emitOptimizedARCReturnCall(llvm::Value *value, CGF.CGM.getTargetCodeGenInfo().markARCOptimizedReturnCallsAsNoTail(); llvm::CallInst::TailCallKind tailKind = isNoTail ? llvm::CallInst::TCK_NoTail : llvm::CallInst::TCK_None; - ObjCEntrypoints &EPs = CGF.CGM.getObjCEntrypoints(); - llvm::Function *&EP = IsRetainRV - ? EPs.objc_retainAutoreleasedReturnValue - : EPs.objc_unsafeClaimAutoreleasedReturnValue; - llvm::Intrinsic::ID IID = - IsRetainRV ? llvm::Intrinsic::objc_retainAutoreleasedReturnValue - : llvm::Intrinsic::objc_unsafeClaimAutoreleasedReturnValue; return emitARCValueOperation(CGF, value, nullptr, EP, IID, tailKind); } @@ -2401,10 +2408,8 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, if (isa(value)) return; llvm::Function *&fn = CGM.getObjCEntrypoints().objc_release; - if (!fn) { - fn = CGM.getIntrinsic(llvm::Intrinsic::objc_release); - setARCRuntimeFunctionLinkage(CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(llvm::Intrinsic::objc_release, CGM); // Cast the argument to 'id'. value = Builder.CreateBitCast(value, Int8PtrTy); @@ -2447,10 +2452,8 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr, assert(addr.getElementType() == value->getType()); llvm::Function *&fn = CGM.getObjCEntrypoints().objc_storeStrong; - if (!fn) { - fn = CGM.getIntrinsic(llvm::Intrinsic::objc_storeStrong); - setARCRuntimeFunctionLinkage(CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(llvm::Intrinsic::objc_storeStrong, CGM); llvm::Value *args[] = { Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy), @@ -2603,10 +2606,8 @@ void CodeGenFunction::EmitARCInitWeak(Address addr, llvm::Value *value) { /// Essentially objc_storeWeak(addr, nil). void CodeGenFunction::EmitARCDestroyWeak(Address addr) { llvm::Function *&fn = CGM.getObjCEntrypoints().objc_destroyWeak; - if (!fn) { - fn = CGM.getIntrinsic(llvm::Intrinsic::objc_destroyWeak); - setARCRuntimeFunctionLinkage(CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(llvm::Intrinsic::objc_destroyWeak, CGM); // Cast the argument to 'id*'. addr = Builder.CreateBitCast(addr, Int8PtrPtrTy); @@ -2651,10 +2652,8 @@ void CodeGenFunction::emitARCMoveAssignWeak(QualType Ty, Address DstAddr, /// call i8* \@objc_autoreleasePoolPush(void) llvm::Value *CodeGenFunction::EmitObjCAutoreleasePoolPush() { llvm::Function *&fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPush; - if (!fn) { - fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush); - setARCRuntimeFunctionLinkage(CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPush, CGM); return EmitNounwindRuntimeCall(fn); } @@ -2679,10 +2678,8 @@ void CodeGenFunction::EmitObjCAutoreleasePoolPop(llvm::Value *value) { EmitRuntimeCallOrInvoke(fn, value); } else { llvm::FunctionCallee &fn = CGM.getObjCEntrypoints().objc_autoreleasePoolPop; - if (!fn) { - fn = CGM.getIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop); - setARCRuntimeFunctionLinkage(CGM, fn); - } + if (!fn) + fn = getARCIntrinsic(llvm::Intrinsic::objc_autoreleasePoolPop, CGM); EmitRuntimeCall(fn, value); } @@ -3344,7 +3341,8 @@ struct ARCRetainExprEmitter : TryEmitResult result = visitExpr(e); // Avoid the block-retain if this is a block literal that doesn't need to be // copied to the heap. - if (e->getBlockDecl()->canAvoidCopyToHeap()) + if (CGF.CGM.getCodeGenOpts().ObjCAvoidHeapifyLocalBlocks && + e->getBlockDecl()->canAvoidCopyToHeap()) result.setInt(true); return result; } @@ -3697,7 +3695,7 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( FunctionDecl *FD = FunctionDecl::Create( C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, - FunctionTy, nullptr, SC_Static, false, false); + FunctionTy, nullptr, SC_Static, false, false, false); FunctionArgList args; ParmVarDecl *Params[2]; @@ -3787,7 +3785,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( FunctionDecl *FD = FunctionDecl::Create( C, C.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, - FunctionTy, nullptr, SC_Static, false, false); + FunctionTy, nullptr, SC_Static, false, false, false); FunctionArgList args; ParmVarDecl *Params[2]; diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index 3f361f4e793..e016644150b 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -2651,35 +2651,6 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, } } - // If the return type is something that goes in an integer register, the - // runtime will handle 0 returns. For other cases, we fill in the 0 value - // ourselves. - // - // The language spec says the result of this kind of message send is - // undefined, but lots of people seem to have forgotten to read that - // paragraph and insist on sending messages to nil that have structure - // returns. With GCC, this generates a random return value (whatever happens - // to be on the stack / in those registers at the time) on most platforms, - // and generates an illegal instruction trap on SPARC. With LLVM it corrupts - // the stack. - bool isPointerSizedReturn = (ResultType->isAnyPointerType() || - ResultType->isIntegralOrEnumerationType() || ResultType->isVoidType()); - - llvm::BasicBlock *startBB = nullptr; - llvm::BasicBlock *messageBB = nullptr; - llvm::BasicBlock *continueBB = nullptr; - - if (!isPointerSizedReturn) { - startBB = Builder.GetInsertBlock(); - messageBB = CGF.createBasicBlock("msgSend"); - continueBB = CGF.createBasicBlock("continue"); - - llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, - llvm::Constant::getNullValue(Receiver->getType())); - Builder.CreateCondBr(isNil, continueBB, messageBB); - CGF.EmitBlock(messageBB); - } - IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); llvm::Value *cmd; if (Method) @@ -2703,6 +2674,96 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, MessageSendInfo MSI = getMessageSendInfo(Method, ResultType, ActualArgs); + // Message sends are expected to return a zero value when the + // receiver is nil. At one point, this was only guaranteed for + // simple integer and pointer types, but expectations have grown + // over time. + // + // Given a nil receiver, the GNU runtime's message lookup will + // return a stub function that simply sets various return-value + // registers to zero and then returns. That's good enough for us + // if and only if (1) the calling conventions of that stub are + // compatible with the signature we're using and (2) the registers + // it sets are sufficient to produce a zero value of the return type. + // Rather than doing a whole target-specific analysis, we assume it + // only works for void, integer, and pointer types, and in all + // other cases we do an explicit nil check is emitted code. In + // addition to ensuring we produe a zero value for other types, this + // sidesteps the few outright CC incompatibilities we know about that + // could otherwise lead to crashes, like when a method is expected to + // return on the x87 floating point stack or adjust the stack pointer + // because of an indirect return. + bool hasParamDestroyedInCallee = false; + bool requiresExplicitZeroResult = false; + bool requiresNilReceiverCheck = [&] { + // We never need a check if we statically know the receiver isn't nil. + if (!canMessageReceiverBeNull(CGF, Method, /*IsSuper*/ false, + Class, Receiver)) + return false; + + // If there's a consumed argument, we need a nil check. + if (Method && Method->hasParamDestroyedInCallee()) { + hasParamDestroyedInCallee = true; + } + + // If the return value isn't flagged as unused, and the result + // type isn't in our narrow set where we assume compatibility, + // we need a nil check to ensure a nil value. + if (!Return.isUnused()) { + if (ResultType->isVoidType()) { + // void results are definitely okay. + } else if (ResultType->hasPointerRepresentation() && + CGM.getTypes().isZeroInitializable(ResultType)) { + // Pointer types should be fine as long as they have + // bitwise-zero null pointers. But do we need to worry + // about unusual address spaces? + } else if (ResultType->isIntegralOrEnumerationType()) { + // Bitwise zero should always be zero for integral types. + // FIXME: we probably need a size limit here, but we've + // never imposed one before + } else { + // Otherwise, use an explicit check just to be sure. + requiresExplicitZeroResult = true; + } + } + + return hasParamDestroyedInCallee || requiresExplicitZeroResult; + }(); + + // We will need to explicitly zero-initialize an aggregate result slot + // if we generally require explicit zeroing and we have an aggregate + // result. + bool requiresExplicitAggZeroing = + requiresExplicitZeroResult && CGF.hasAggregateEvaluationKind(ResultType); + + // The block we're going to end up in after any message send or nil path. + llvm::BasicBlock *continueBB = nullptr; + // The block that eventually branched to continueBB along the nil path. + llvm::BasicBlock *nilPathBB = nullptr; + // The block to do explicit work in along the nil path, if necessary. + llvm::BasicBlock *nilCleanupBB = nullptr; + + // Emit the nil-receiver check. + if (requiresNilReceiverCheck) { + llvm::BasicBlock *messageBB = CGF.createBasicBlock("msgSend"); + continueBB = CGF.createBasicBlock("continue"); + + // If we need to zero-initialize an aggregate result or destroy + // consumed arguments, we'll need a separate cleanup block. + // Otherwise we can just branch directly to the continuation block. + if (requiresExplicitAggZeroing || hasParamDestroyedInCallee) { + nilCleanupBB = CGF.createBasicBlock("nilReceiverCleanup"); + } else { + nilPathBB = Builder.GetInsertBlock(); + } + + llvm::Value *isNil = Builder.CreateICmpEQ(Receiver, + llvm::Constant::getNullValue(Receiver->getType())); + Builder.CreateCondBr(isNil, nilCleanupBB ? nilCleanupBB : continueBB, + messageBB); + CGF.EmitBlock(messageBB); + } + // Get the IMP to call llvm::Value *imp; @@ -2744,36 +2805,48 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF, RValue msgRet = CGF.EmitCall(MSI.CallInfo, callee, Return, ActualArgs, &call); call->setMetadata(msgSendMDKind, node); - - if (!isPointerSizedReturn) { - messageBB = CGF.Builder.GetInsertBlock(); + if (requiresNilReceiverCheck) { + llvm::BasicBlock *nonNilPathBB = CGF.Builder.GetInsertBlock(); CGF.Builder.CreateBr(continueBB); + + // Emit the nil path if we decided it was necessary above. + if (nilCleanupBB) { + CGF.EmitBlock(nilCleanupBB); + + if (hasParamDestroyedInCallee) { + destroyCalleeDestroyedArguments(CGF, Method, CallArgs); + } + + if (requiresExplicitAggZeroing) { + assert(msgRet.isAggregate()); + Address addr = msgRet.getAggregateAddress(); + CGF.EmitNullInitialization(addr, ResultType); + } + + nilPathBB = CGF.Builder.GetInsertBlock(); + CGF.Builder.CreateBr(continueBB); + } + + // Enter the continuation block and emit a phi if required. CGF.EmitBlock(continueBB); if (msgRet.isScalar()) { llvm::Value *v = msgRet.getScalarVal(); llvm::PHINode *phi = Builder.CreatePHI(v->getType(), 2); - phi->addIncoming(v, messageBB); - phi->addIncoming(llvm::Constant::getNullValue(v->getType()), startBB); + phi->addIncoming(v, nonNilPathBB); + phi->addIncoming(CGM.EmitNullConstant(ResultType), nilPathBB); msgRet = RValue::get(phi); } else if (msgRet.isAggregate()) { - Address v = msgRet.getAggregateAddress(); - llvm::PHINode *phi = Builder.CreatePHI(v.getType(), 2); - llvm::Type *RetTy = v.getElementType(); - Address NullVal = CGF.CreateTempAlloca(RetTy, v.getAlignment(), "null"); - CGF.InitTempAlloca(NullVal, llvm::Constant::getNullValue(RetTy)); - phi->addIncoming(v.getPointer(), messageBB); - phi->addIncoming(NullVal.getPointer(), startBB); - msgRet = RValue::getAggregate(Address(phi, v.getAlignment())); + // Aggregate zeroing is handled in nilCleanupBB when it's required. } else /* isComplex() */ { std::pair v = msgRet.getComplexVal(); llvm::PHINode *phi = Builder.CreatePHI(v.first->getType(), 2); - phi->addIncoming(v.first, messageBB); + phi->addIncoming(v.first, nonNilPathBB); phi->addIncoming(llvm::Constant::getNullValue(v.first->getType()), - startBB); + nilPathBB); llvm::PHINode *phi2 = Builder.CreatePHI(v.second->getType(), 2); - phi2->addIncoming(v.second, messageBB); + phi2->addIncoming(v.second, nonNilPathBB); phi2->addIncoming(llvm::Constant::getNullValue(v.second->getType()), - startBB); + nilPathBB); msgRet = RValue::getComplex(phi, phi2); } } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 3de67bb4bbc..5b925359ac2 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1754,37 +1754,9 @@ struct NullReturnState { // Okay, start emitting the null-receiver block. CGF.EmitBlock(NullBB); - // Release any consumed arguments we've got. + // Destroy any consumed arguments we've got. if (Method) { - CallArgList::const_iterator I = CallArgs.begin(); - for (ObjCMethodDecl::param_const_iterator i = Method->param_begin(), - e = Method->param_end(); i != e; ++i, ++I) { - const ParmVarDecl *ParamDecl = (*i); - if (ParamDecl->hasAttr()) { - RValue RV = I->getRValue(CGF); - assert(RV.isScalar() && - "NullReturnState::complete - arg not on object"); - CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime); - } else { - QualType QT = ParamDecl->getType(); - auto *RT = QT->getAs(); - if (RT && RT->getDecl()->isParamDestroyedInCallee()) { - RValue RV = I->getRValue(CGF); - QualType::DestructionKind DtorKind = QT.isDestructedType(); - switch (DtorKind) { - case QualType::DK_cxx_destructor: - CGF.destroyCXXObject(CGF, RV.getAggregateAddress(), QT); - break; - case QualType::DK_nontrivial_c_struct: - CGF.destroyNonTrivialCStruct(CGF, RV.getAggregateAddress(), QT); - break; - default: - llvm_unreachable("unexpected dtor kind"); - break; - } - } - } - } + CGObjCRuntime::destroyCalleeDestroyedArguments(CGF, Method, CallArgs); } // The phi code below assumes that we haven't needed any control flow yet. @@ -2151,15 +2123,6 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, Method, Class, ObjCTypes); } -static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) { - do { - if (ID->isWeakImported()) - return true; - } while ((ID = ID->getSuperClass())); - - return false; -} - CodeGen::RValue CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, @@ -2200,32 +2163,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, CGM.getContext().getCanonicalType(ResultType) && "Result type mismatch!"); - bool ReceiverCanBeNull = true; - - // Super dispatch assumes that self is non-null; even the messenger - // doesn't have a null check internally. - if (IsSuper) { - ReceiverCanBeNull = false; - - // If this is a direct dispatch of a class method, check whether the class, - // or anything in its hierarchy, was weak-linked. - } else if (ClassReceiver && Method && Method->isClassMethod()) { - ReceiverCanBeNull = isWeakLinkedClass(ClassReceiver); - - // If we're emitting a method, and self is const (meaning just ARC, for now), - // and the receiver is a load of self, then self is a valid object. - } else if (auto CurMethod = - dyn_cast_or_null(CGF.CurCodeDecl)) { - auto Self = CurMethod->getSelfDecl(); - if (Self->getType().isConstQualified()) { - if (auto LI = dyn_cast(Arg0->stripPointerCasts())) { - llvm::Value *SelfAddr = CGF.GetAddrOfLocalVar(Self).getPointer(); - if (SelfAddr == LI->getPointerOperand()) { - ReceiverCanBeNull = false; - } - } - } - } + bool ReceiverCanBeNull = + canMessageReceiverBeNull(CGF, Method, IsSuper, ClassReceiver, Arg0); bool RequiresNullCheck = false; @@ -2261,14 +2200,8 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, RequiresNullCheck = false; // Emit a null-check if there's a consumed argument other than the receiver. - if (!RequiresNullCheck && CGM.getLangOpts().ObjCAutoRefCount && Method) { - for (const auto *ParamDecl : Method->parameters()) { - if (ParamDecl->isDestroyedInCallee()) { - RequiresNullCheck = true; - break; - } - } - } + if (!RequiresNullCheck && Method && Method->hasParamDestroyedInCallee()) + RequiresNullCheck = true; NullReturnState nullReturn; if (RequiresNullCheck) { @@ -4788,9 +4721,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // matched and avoid generating code for falling off the end if // so. bool AllMatched = false; - for (unsigned I = 0, N = AtTryStmt->getNumCatchStmts(); I != N; ++I) { - const ObjCAtCatchStmt *CatchStmt = AtTryStmt->getCatchStmt(I); - + for (const ObjCAtCatchStmt *CatchStmt : AtTryStmt->catch_stmts()) { const VarDecl *CatchParam = CatchStmt->getCatchParamDecl(); const ObjCObjectPointerType *OPT = nullptr; @@ -6741,33 +6672,53 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { } } - values.add(emitMethodList(listName, MethodListType::CategoryInstanceMethods, - instanceMethods)); - values.add(emitMethodList(listName, MethodListType::CategoryClassMethods, - classMethods)); + auto instanceMethodList = emitMethodList( + listName, MethodListType::CategoryInstanceMethods, instanceMethods); + auto classMethodList = emitMethodList( + listName, MethodListType::CategoryClassMethods, classMethods); + values.add(instanceMethodList); + values.add(classMethodList); + // Keep track of whether we have actual metadata to emit. + bool isEmptyCategory = + instanceMethodList->isNullValue() && classMethodList->isNullValue(); const ObjCCategoryDecl *Category = - Interface->FindCategoryDeclaration(OCD->getIdentifier()); + Interface->FindCategoryDeclaration(OCD->getIdentifier()); if (Category) { SmallString<256> ExtName; - llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_" - << OCD->getName(); - values.add(EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" - + Interface->getObjCRuntimeNameAsString() + "_$_" - + Category->getName(), - Category->protocol_begin(), - Category->protocol_end())); - values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, false)); - values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), - OCD, Category, ObjCTypes, true)); + llvm::raw_svector_ostream(ExtName) + << Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName(); + auto protocolList = + EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" + + Interface->getObjCRuntimeNameAsString() + "_$_" + + Category->getName(), + Category->protocol_begin(), Category->protocol_end()); + auto propertyList = EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(), + OCD, Category, ObjCTypes, false); + auto classPropertyList = + EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), OCD, + Category, ObjCTypes, true); + values.add(protocolList); + values.add(propertyList); + values.add(classPropertyList); + isEmptyCategory &= protocolList->isNullValue() && + propertyList->isNullValue() && + classPropertyList->isNullValue(); } else { values.addNullPointer(ObjCTypes.ProtocolListnfABIPtrTy); values.addNullPointer(ObjCTypes.PropertyListPtrTy); values.addNullPointer(ObjCTypes.PropertyListPtrTy); } - unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy); + if (isEmptyCategory) { + // Empty category, don't emit any metadata. + values.abandon(); + MethodDefinitions.clear(); + return; + } + + unsigned Size = + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategorynfABITy); values.addInt(ObjCTypes.IntTy, Size); llvm::GlobalVariable *GCATV = diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 108f6fc7ba6..33ae3c7c2b2 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -163,8 +163,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, // Enter the catch, if there is one. if (S.getNumCatchStmts()) { - for (unsigned I = 0, N = S.getNumCatchStmts(); I != N; ++I) { - const ObjCAtCatchStmt *CatchStmt = S.getCatchStmt(I); + for (const ObjCAtCatchStmt *CatchStmt : S.catch_stmts()) { const VarDecl *CatchDecl = CatchStmt->getCatchParamDecl(); Handlers.push_back(CatchHandler()); @@ -385,6 +384,83 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, return MessageSendInfo(argsInfo, signatureType); } +bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, + const ObjCMethodDecl *method, + bool isSuper, + const ObjCInterfaceDecl *classReceiver, + llvm::Value *receiver) { + // Super dispatch assumes that self is non-null; even the messenger + // doesn't have a null check internally. + if (isSuper) + return false; + + // If this is a direct dispatch of a class method, check whether the class, + // or anything in its hierarchy, was weak-linked. + if (classReceiver && method && method->isClassMethod()) + return isWeakLinkedClass(classReceiver); + + // If we're emitting a method, and self is const (meaning just ARC, for now), + // and the receiver is a load of self, then self is a valid object. + if (auto curMethod = + dyn_cast_or_null(CGF.CurCodeDecl)) { + auto self = curMethod->getSelfDecl(); + if (self->getType().isConstQualified()) { + if (auto LI = dyn_cast(receiver->stripPointerCasts())) { + llvm::Value *selfAddr = CGF.GetAddrOfLocalVar(self).getPointer(); + if (selfAddr == LI->getPointerOperand()) { + return false; + } + } + } + } + + // Otherwise, assume it can be null. + return true; +} + +bool CGObjCRuntime::isWeakLinkedClass(const ObjCInterfaceDecl *ID) { + do { + if (ID->isWeakImported()) + return true; + } while ((ID = ID->getSuperClass())); + + return false; +} + +void CGObjCRuntime::destroyCalleeDestroyedArguments(CodeGenFunction &CGF, + const ObjCMethodDecl *method, + const CallArgList &callArgs) { + CallArgList::const_iterator I = callArgs.begin(); + for (auto i = method->param_begin(), e = method->param_end(); + i != e; ++i, ++I) { + const ParmVarDecl *param = (*i); + if (param->hasAttr()) { + RValue RV = I->getRValue(CGF); + assert(RV.isScalar() && + "NullReturnState::complete - arg not on object"); + CGF.EmitARCRelease(RV.getScalarVal(), ARCImpreciseLifetime); + } else { + QualType QT = param->getType(); + auto *RT = QT->getAs(); + if (RT && RT->getDecl()->isParamDestroyedInCallee()) { + RValue RV = I->getRValue(CGF); + QualType::DestructionKind DtorKind = QT.isDestructedType(); + switch (DtorKind) { + case QualType::DK_cxx_destructor: + CGF.destroyCXXObject(CGF, RV.getAggregateAddress(), QT); + break; + case QualType::DK_nontrivial_c_struct: + CGF.destroyNonTrivialCStruct(CGF, RV.getAggregateAddress(), QT); + break; + default: + llvm_unreachable("unexpected dtor kind"); + break; + } + } + } + } +} + llvm::Constant * clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM, const ObjCProtocolDecl *protocol) { diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index f56101df77b..bb27c38db20 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -337,6 +337,23 @@ public: MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method, QualType resultType, CallArgList &callArgs); + bool canMessageReceiverBeNull(CodeGenFunction &CGF, + const ObjCMethodDecl *method, + bool isSuper, + const ObjCInterfaceDecl *classReceiver, + llvm::Value *receiver); + static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls); + + /// Destroy the callee-destroyed arguments of the given method, + /// if it has any. Used for nil-receiver paths in message sends. + /// Never does anything if the method does not satisfy + /// hasParamDestroyedInCallee(). + /// + /// \param callArgs - just the formal arguments, not including implicit + /// arguments such as self and cmd + static void destroyCalleeDestroyedArguments(CodeGenFunction &CGF, + const ObjCMethodDecl *method, + const CallArgList &callArgs); // FIXME: This probably shouldn't be here, but the code to compute // it is here. diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index c09797e91b9..75709b3c7e7 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1448,8 +1448,8 @@ llvm::Value *CGOpenMPRuntime::emitUpdateLocation(CodeGenFunction &CGF, const char *FileName = PLoc.getFilename(); unsigned Line = PLoc.getLine(); unsigned Column = PLoc.getColumn(); - SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FunctionName.c_str(), FileName, - Line, Column); + SrcLocStr = + OMPBuilder.getOrCreateSrcLocStr(FunctionName, FileName, Line, Column); } unsigned Reserved2Flags = getDefaultLocationReserved2Flags(); return OMPBuilder.getOrCreateIdent(SrcLocStr, llvm::omp::IdentFlag(Flags), @@ -1560,13 +1560,22 @@ llvm::Type *CGOpenMPRuntime::getKmpc_MicroPointerTy() { } llvm::FunctionCallee -CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize, bool IVSigned) { +CGOpenMPRuntime::createForStaticInitFunction(unsigned IVSize, bool IVSigned, + bool IsGPUDistribute) { assert((IVSize == 32 || IVSize == 64) && "IV size is not compatible with the omp runtime"); - StringRef Name = IVSize == 32 ? (IVSigned ? "__kmpc_for_static_init_4" - : "__kmpc_for_static_init_4u") - : (IVSigned ? "__kmpc_for_static_init_8" - : "__kmpc_for_static_init_8u"); + StringRef Name; + if (IsGPUDistribute) + Name = IVSize == 32 ? (IVSigned ? "__kmpc_distribute_static_init_4" + : "__kmpc_distribute_static_init_4u") + : (IVSigned ? "__kmpc_distribute_static_init_8" + : "__kmpc_distribute_static_init_8u"); + else + Name = IVSize == 32 ? (IVSigned ? "__kmpc_for_static_init_4" + : "__kmpc_for_static_init_4u") + : (IVSigned ? "__kmpc_for_static_init_8" + : "__kmpc_for_static_init_8u"); + llvm::Type *ITy = IVSize == 32 ? CGM.Int32Ty : CGM.Int64Ty; auto *PtrTy = llvm::PointerType::getUnqual(ITy); llvm::Type *TypeParams[] = { @@ -2112,7 +2121,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, Address ZeroAddrBound = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".bound.zero.addr"); - CGF.InitTempAlloca(ZeroAddrBound, CGF.Builder.getInt32(/*C*/ 0)); + CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound); llvm::SmallVector OutlinedFnArgs; // ThreadId for serialized parallels is 0. OutlinedFnArgs.push_back(ThreadIDAddr.getPointer()); @@ -2120,11 +2129,12 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); // Ensure we do not inline the function. This is trivially true for the ones - // passed to __kmpc_fork_call but the ones calles in serialized regions + // passed to __kmpc_fork_call but the ones called in serialized regions // could be inlined. This is not a perfect but it is closer to the invariant // we want, namely, every data environment starts with a new function. // TODO: We should pass the if condition to the runtime function and do the // handling there. Much cleaner code. + OutlinedFn->removeFnAttr(llvm::Attribute::AlwaysInline); OutlinedFn->addFnAttr(llvm::Attribute::NoInline); RT.emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); @@ -2825,7 +2835,7 @@ void CGOpenMPRuntime::emitForStaticInit(CodeGenFunction &CGF, : OMP_IDENT_WORK_SECTIONS); llvm::Value *ThreadId = getThreadID(CGF, Loc); llvm::FunctionCallee StaticInitFunction = - createForStaticInitFunction(Values.IVSize, Values.IVSigned); + createForStaticInitFunction(Values.IVSize, Values.IVSigned, false); auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc); emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction, ScheduleNum, ScheduleKind.M1, ScheduleKind.M2, Values); @@ -2840,8 +2850,13 @@ void CGOpenMPRuntime::emitDistributeStaticInit( llvm::Value *UpdatedLocation = emitUpdateLocation(CGF, Loc, OMP_IDENT_WORK_DISTRIBUTE); llvm::Value *ThreadId = getThreadID(CGF, Loc); - llvm::FunctionCallee StaticInitFunction = - createForStaticInitFunction(Values.IVSize, Values.IVSigned); + llvm::FunctionCallee StaticInitFunction; + bool isGPUDistribute = + CGM.getLangOpts().OpenMPIsDevice && + (CGM.getTriple().isAMDGCN() || CGM.getTriple().isNVPTX()); + StaticInitFunction = createForStaticInitFunction( + Values.IVSize, Values.IVSigned, isGPUDistribute); + emitForStaticInitCall(CGF, UpdatedLocation, ThreadId, StaticInitFunction, ScheduleNum, OMPC_SCHEDULE_MODIFIER_unknown, OMPC_SCHEDULE_MODIFIER_unknown, Values); @@ -2862,9 +2877,16 @@ void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF, : OMP_IDENT_WORK_SECTIONS), getThreadID(CGF, Loc)}; auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc); - CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_for_static_fini), - Args); + if (isOpenMPDistributeDirective(DKind) && CGM.getLangOpts().OpenMPIsDevice && + (CGM.getTriple().isAMDGCN() || CGM.getTriple().isNVPTX())) + CGF.EmitRuntimeCall( + OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_distribute_static_fini), + Args); + else + CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_for_static_fini), + Args); } void CGOpenMPRuntime::emitForOrderedIterationEnd(CodeGenFunction &CGF, @@ -3891,7 +3913,7 @@ static void emitPrivatesInit(CodeGenFunction &CGF, SharedRefLValue.getTBAAInfo()); } else if (CGF.LambdaCaptureFields.count( Pair.second.Original->getCanonicalDecl()) > 0 || - dyn_cast_or_null(CGF.CurCodeDecl)) { + isa_and_nonnull(CGF.CurCodeDecl)) { SharedRefLValue = CGF.EmitLValue(Pair.second.OriginalRef); } else { // Processing for implicitly captured variables. @@ -4400,14 +4422,14 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, if (NumOfElements) { NumOfElements = CGF.Builder.CreateNUWAdd( llvm::ConstantInt::get(CGF.SizeTy, NumAffinities), NumOfElements); - OpaqueValueExpr OVE( + auto *OVE = new (C) OpaqueValueExpr( Loc, C.getIntTypeForBitwidth(C.getTypeSize(C.getSizeType()), /*Signed=*/0), VK_PRValue); - CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, + CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE, RValue::get(NumOfElements)); KmpTaskAffinityInfoArrayTy = - C.getVariableArrayType(KmpTaskAffinityInfoTy, &OVE, ArrayType::Normal, + C.getVariableArrayType(KmpTaskAffinityInfoTy, OVE, ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange(Loc, Loc)); // Properly emit variable-sized array. auto *PD = ImplicitParamDecl::Create(C, KmpTaskAffinityInfoArrayTy, @@ -4758,8 +4780,8 @@ emitDepobjElementsSizes(CodeGenFunction &CGF, QualType &KmpDependInfoTy, LValue NumLVal = CGF.MakeAddrLValue( CGF.CreateMemTemp(C.getUIntPtrType(), "depobj.size.addr"), C.getUIntPtrType()); - CGF.InitTempAlloca(NumLVal.getAddress(CGF), - llvm::ConstantInt::get(CGF.IntPtrTy, 0)); + CGF.Builder.CreateStore(llvm::ConstantInt::get(CGF.IntPtrTy, 0), + NumLVal.getAddress(CGF)); llvm::Value *PrevVal = CGF.EmitLoadOfScalar(NumLVal, E->getExprLoc()); llvm::Value *Add = CGF.Builder.CreateNUWAdd(PrevVal, NumDeps); CGF.EmitStoreOfScalar(Add, NumLVal); @@ -4860,7 +4882,7 @@ std::pair CGOpenMPRuntime::emitDependClause( bool HasRegularWithIterators = false; llvm::Value *NumOfDepobjElements = llvm::ConstantInt::get(CGF.IntPtrTy, 0); llvm::Value *NumOfRegularWithIterators = - llvm::ConstantInt::get(CGF.IntPtrTy, 1); + llvm::ConstantInt::get(CGF.IntPtrTy, 0); // Calculate number of depobj dependecies and regular deps with the iterators. for (const OMPTaskDataTy::DependData &D : Dependencies) { if (D.DepKind == OMPC_DEPEND_depobj) { @@ -4874,12 +4896,15 @@ std::pair CGOpenMPRuntime::emitDependClause( continue; } // Include number of iterations, if any. + if (const auto *IE = cast_or_null(D.IteratorExpr)) { for (unsigned I = 0, E = IE->numOfIterators(); I < E; ++I) { llvm::Value *Sz = CGF.EmitScalarExpr(IE->getHelper(I).Upper); Sz = CGF.Builder.CreateIntCast(Sz, CGF.IntPtrTy, /*isSigned=*/false); + llvm::Value *NumClauseDeps = CGF.Builder.CreateNUWMul( + Sz, llvm::ConstantInt::get(CGF.IntPtrTy, D.DepExprs.size())); NumOfRegularWithIterators = - CGF.Builder.CreateNUWMul(NumOfRegularWithIterators, Sz); + CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumClauseDeps); } HasRegularWithIterators = true; continue; @@ -4898,13 +4923,13 @@ std::pair CGOpenMPRuntime::emitDependClause( NumOfElements = CGF.Builder.CreateNUWAdd(NumOfRegularWithIterators, NumOfElements); } - OpaqueValueExpr OVE(Loc, - C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0), - VK_PRValue); - CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, + auto *OVE = new (C) OpaqueValueExpr( + Loc, C.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0), + VK_PRValue); + CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, OVE, RValue::get(NumOfElements)); KmpDependInfoArrayTy = - C.getVariableArrayType(KmpDependInfoTy, &OVE, ArrayType::Normal, + C.getVariableArrayType(KmpDependInfoTy, OVE, ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange(Loc, Loc)); // CGF.EmitVariablyModifiedType(KmpDependInfoArrayTy); // Properly emit variable-sized array. @@ -6239,21 +6264,51 @@ Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF, SharedLVal.getAlignment()); } -void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, - SourceLocation Loc) { +void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, + const OMPTaskDataTy &Data) { if (!CGF.HaveInsertPoint()) return; - if (CGF.CGM.getLangOpts().OpenMPIRBuilder) { + if (CGF.CGM.getLangOpts().OpenMPIRBuilder && Data.Dependences.empty()) { + // TODO: Need to support taskwait with dependences in the OpenMPIRBuilder. OMPBuilder.createTaskwait(CGF.Builder); } else { - // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32 - // global_tid); - llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc)}; - // Ignore return result until untied tasks are supported. - CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( - CGM.getModule(), OMPRTL___kmpc_omp_taskwait), - Args); + llvm::Value *ThreadID = getThreadID(CGF, Loc); + llvm::Value *UpLoc = emitUpdateLocation(CGF, Loc); + auto &M = CGM.getModule(); + Address DependenciesArray = Address::invalid(); + llvm::Value *NumOfElements; + std::tie(NumOfElements, DependenciesArray) = + emitDependClause(CGF, Data.Dependences, Loc); + llvm::Value *DepWaitTaskArgs[6]; + if (!Data.Dependences.empty()) { + DepWaitTaskArgs[0] = UpLoc; + DepWaitTaskArgs[1] = ThreadID; + DepWaitTaskArgs[2] = NumOfElements; + DepWaitTaskArgs[3] = DependenciesArray.getPointer(); + DepWaitTaskArgs[4] = CGF.Builder.getInt32(0); + DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); + + CodeGenFunction::RunCleanupsScope LocalScope(CGF); + + // Build void __kmpc_omp_wait_deps(ident_t *, kmp_int32 gtid, + // kmp_int32 ndeps, kmp_depend_info_t *dep_list, kmp_int32 + // ndeps_noalias, kmp_depend_info_t *noalias_dep_list); if dependence info + // is specified. + CGF.EmitRuntimeCall( + OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_wait_deps), + DepWaitTaskArgs); + + } else { + + // Build call kmp_int32 __kmpc_omp_taskwait(ident_t *loc, kmp_int32 + // global_tid); + llvm::Value *Args[] = {UpLoc, ThreadID}; + // Ignore return result until untied tasks are supported. + CGF.EmitRuntimeCall( + OMPBuilder.getOrCreateRuntimeFunction(M, OMPRTL___kmpc_omp_taskwait), + Args); + } } if (auto *Region = dyn_cast_or_null(CGF.CapturedStmtInfo)) @@ -6739,6 +6794,7 @@ const Expr *CGOpenMPRuntime::getNumTeamsExprForTargetDirective( case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_requires: + case OMPD_metadirective: case OMPD_unknown: break; default: @@ -7213,6 +7269,7 @@ llvm::Value *CGOpenMPRuntime::emitNumThreadsForTargetDirective( case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_requires: + case OMPD_metadirective: case OMPD_unknown: break; default: @@ -7268,6 +7325,14 @@ public: /// 0x800 is reserved for compatibility with XLC. /// Produce a runtime error if the data is not already allocated. OMP_MAP_PRESENT = 0x1000, + // Increment and decrement a separate reference counter so that the data + // cannot be unmapped within the associated region. Thus, this flag is + // intended to be used on 'target' and 'target data' directives because they + // are inherently structured. It is not intended to be used on 'target + // enter data' and 'target exit data' directives because they are inherently + // dynamic. + // This is an OpenMP extension for the sake of OpenACC support. + OMP_MAP_OMPX_HOLD = 0x2000, /// Signal that the runtime library should use args as an array of /// descriptor_dim pointers and use args_size as dims. Used when we have /// non-contiguous list items in target update directive @@ -7446,6 +7511,9 @@ private: SmallVector> DevPointersMap; + /// Map between lambda declarations and their map type. + llvm::DenseMap LambdasMap; + llvm::Value *getExprTypeSize(const Expr *E) const { QualType ExprTy = E->getType().getCanonicalType(); @@ -7558,17 +7626,15 @@ private: Bits |= OMP_MAP_PTR_AND_OBJ; if (AddIsTargetParamFlag) Bits |= OMP_MAP_TARGET_PARAM; - if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_always) - != MapModifiers.end()) + if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_always)) Bits |= OMP_MAP_ALWAYS; - if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_close) - != MapModifiers.end()) + if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_close)) Bits |= OMP_MAP_CLOSE; - if (llvm::find(MapModifiers, OMPC_MAP_MODIFIER_present) != - MapModifiers.end() || - llvm::find(MotionModifiers, OMPC_MOTION_MODIFIER_present) != - MotionModifiers.end()) + if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_present) || + llvm::is_contained(MotionModifiers, OMPC_MOTION_MODIFIER_present)) Bits |= OMP_MAP_PRESENT; + if (llvm::is_contained(MapModifiers, OMPC_MAP_MODIFIER_ompx_hold)) + Bits |= OMP_MAP_OMPX_HOLD; if (IsNonContiguous) Bits |= OMP_MAP_NON_CONTIG; return Bits; @@ -8404,6 +8470,15 @@ private: return MappableExprsHandler::OMP_MAP_PRIVATE | MappableExprsHandler::OMP_MAP_TO; } + auto I = LambdasMap.find(Cap.getCapturedVar()->getCanonicalDecl()); + if (I != LambdasMap.end()) + // for map(to: lambda): using user specified map type. + return getMapTypeBits( + I->getSecond()->getMapType(), I->getSecond()->getMapTypeModifiers(), + /*MotionModifiers=*/llvm::None, I->getSecond()->isImplicit(), + /*AddPtrFlag=*/false, + /*AddIsTargetParamFlag=*/false, + /*isNonContiguous=*/false); return MappableExprsHandler::OMP_MAP_TO | MappableExprsHandler::OMP_MAP_FROM; } @@ -8535,10 +8610,8 @@ private: if (!C) continue; MapKind Kind = Other; - if (!C->getMapTypeModifiers().empty() && - llvm::any_of(C->getMapTypeModifiers(), [](OpenMPMapModifierKind K) { - return K == OMPC_MAP_MODIFIER_present; - })) + if (llvm::is_contained(C->getMapTypeModifiers(), + OMPC_MAP_MODIFIER_present)) Kind = Present; else if (C->getMapType() == OMPC_MAP_alloc) Kind = Allocs; @@ -8557,10 +8630,8 @@ private: if (!C) continue; MapKind Kind = Other; - if (!C->getMotionModifiers().empty() && - llvm::any_of(C->getMotionModifiers(), [](OpenMPMotionModifierKind K) { - return K == OMPC_MOTION_MODIFIER_present; - })) + if (llvm::is_contained(C->getMotionModifiers(), + OMPC_MOTION_MODIFIER_present)) Kind = Present; const auto *EI = C->getVarRefs().begin(); for (const auto L : C->component_lists()) { @@ -8575,10 +8646,8 @@ private: if (!C) continue; MapKind Kind = Other; - if (!C->getMotionModifiers().empty() && - llvm::any_of(C->getMotionModifiers(), [](OpenMPMotionModifierKind K) { - return K == OMPC_MOTION_MODIFIER_present; - })) + if (llvm::is_contained(C->getMotionModifiers(), + OMPC_MOTION_MODIFIER_present)) Kind = Present; const auto *EI = C->getVarRefs().begin(); for (const auto L : C->component_lists()) { @@ -8868,6 +8937,21 @@ public: for (const auto *C : Dir.getClausesOfKind()) for (auto L : C->component_lists()) DevPointersMap[std::get<0>(L)].push_back(std::get<1>(L)); + // Extract map information. + for (const auto *C : Dir.getClausesOfKind()) { + if (C->getMapType() != OMPC_MAP_to) + continue; + for (auto L : C->component_lists()) { + const ValueDecl *VD = std::get<0>(L); + const auto *RD = VD ? VD->getType() + .getCanonicalType() + .getNonReferenceType() + ->getAsCXXRecordDecl() + : nullptr; + if (RD && RD->isLambda()) + LambdasMap.try_emplace(std::get<0>(L), C); + } + } } /// Constructor for the declare mapper directive. @@ -8922,6 +9006,20 @@ public: CombinedInfo.Types.back() |= OMP_MAP_PRESENT; // Remove TARGET_PARAM flag from the first element (*CurTypes.begin()) &= ~OMP_MAP_TARGET_PARAM; + // If any element has the ompx_hold modifier, then make sure the runtime + // uses the hold reference count for the struct as a whole so that it won't + // be unmapped by an extra dynamic reference count decrement. Add it to all + // elements as well so the runtime knows which reference count to check + // when determining whether it's time for device-to-host transfers of + // individual elements. + if (CurTypes.end() != + llvm::find_if(CurTypes, [](OpenMPOffloadMappingFlags Type) { + return Type & OMP_MAP_OMPX_HOLD; + })) { + CombinedInfo.Types.back() |= OMP_MAP_OMPX_HOLD; + for (auto &M : CurTypes) + M |= OMP_MAP_OMPX_HOLD; + } // All other current entries will be MEMBER_OF the combined entry // (except for PTR_AND_OBJ entries which do not have a placeholder value @@ -9066,6 +9164,11 @@ public: ? nullptr : Cap->getCapturedVar()->getCanonicalDecl(); + // for map(to: lambda): skip here, processing it in + // generateDefaultMapInfo + if (LambdasMap.count(VD)) + return; + // If this declaration appears in a is_device_ptr clause we just have to // pass the pointer by value. If it is a reference to a declaration, we just // pass its value. @@ -9112,18 +9215,13 @@ public: const MapData &RHS) { ArrayRef MapModifiers = std::get<2>(LHS); OpenMPMapClauseKind MapType = std::get<1>(RHS); - bool HasPresent = !MapModifiers.empty() && - llvm::any_of(MapModifiers, [](OpenMPMapModifierKind K) { - return K == clang::OMPC_MAP_MODIFIER_present; - }); + bool HasPresent = + llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present); bool HasAllocs = MapType == OMPC_MAP_alloc; MapModifiers = std::get<2>(RHS); MapType = std::get<1>(LHS); bool HasPresentR = - !MapModifiers.empty() && - llvm::any_of(MapModifiers, [](OpenMPMapModifierKind K) { - return K == clang::OMPC_MAP_MODIFIER_present; - }); + llvm::is_contained(MapModifiers, clang::OMPC_MAP_MODIFIER_present); bool HasAllocsR = MapType == OMPC_MAP_alloc; return (HasPresent && !HasPresentR) || (HasAllocs && !HasAllocsR); }); @@ -9434,34 +9532,50 @@ static void emitNonContiguousDescriptor( } } +// Try to extract the base declaration from a `this->x` expression if possible. +static ValueDecl *getDeclFromThisExpr(const Expr *E) { + if (!E) + return nullptr; + + if (const auto *OASE = dyn_cast(E->IgnoreParenCasts())) + if (const MemberExpr *ME = + dyn_cast(OASE->getBase()->IgnoreParenImpCasts())) + return ME->getMemberDecl(); + return nullptr; +} + /// Emit a string constant containing the names of the values mapped to the /// offloading runtime library. llvm::Constant * emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, MappableExprsHandler::MappingExprInfo &MapExprs) { - llvm::Constant *SrcLocStr; - if (!MapExprs.getMapDecl()) { - SrcLocStr = OMPBuilder.getOrCreateDefaultSrcLocStr(); - } else { - std::string ExprName = ""; - if (MapExprs.getMapExpr()) { - PrintingPolicy P(CGF.getContext().getLangOpts()); - llvm::raw_string_ostream OS(ExprName); - MapExprs.getMapExpr()->printPretty(OS, nullptr, P); - OS.flush(); - } else { - ExprName = MapExprs.getMapDecl()->getNameAsString(); - } - SourceLocation Loc = MapExprs.getMapDecl()->getLocation(); - PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); - const char *FileName = PLoc.getFilename(); - unsigned Line = PLoc.getLine(); - unsigned Column = PLoc.getColumn(); - SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(FileName, ExprName.c_str(), - Line, Column); + if (!MapExprs.getMapDecl() && !MapExprs.getMapExpr()) + return OMPBuilder.getOrCreateDefaultSrcLocStr(); + + SourceLocation Loc; + if (!MapExprs.getMapDecl() && MapExprs.getMapExpr()) { + if (const ValueDecl *VD = getDeclFromThisExpr(MapExprs.getMapExpr())) + Loc = VD->getLocation(); + else + Loc = MapExprs.getMapExpr()->getExprLoc(); + } else { + Loc = MapExprs.getMapDecl()->getLocation(); } - return SrcLocStr; + + std::string ExprName = ""; + if (MapExprs.getMapExpr()) { + PrintingPolicy P(CGF.getContext().getLangOpts()); + llvm::raw_string_ostream OS(ExprName); + MapExprs.getMapExpr()->printPretty(OS, nullptr, P); + OS.flush(); + } else { + ExprName = MapExprs.getMapDecl()->getNameAsString(); + } + + PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); + return OMPBuilder.getOrCreateSrcLocStr(PLoc.getFilename(), ExprName.c_str(), + PLoc.getLine(), PLoc.getColumn()); } /// Emit the arrays used to pass the captures and map information to the @@ -9809,6 +9923,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_requires: + case OMPD_metadirective: case OMPD_unknown: default: llvm_unreachable("Unexpected directive."); @@ -10659,6 +10774,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, case OMPD_parallel_master_taskloop: case OMPD_parallel_master_taskloop_simd: case OMPD_requires: + case OMPD_metadirective: case OMPD_unknown: default: llvm_unreachable("Unknown target directive for OpenMP device codegen."); @@ -11340,6 +11456,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( case OMPD_target_parallel_for: case OMPD_target_parallel_for_simd: case OMPD_requires: + case OMPD_metadirective: case OMPD_unknown: default: llvm_unreachable("Unexpected standalone target data directive."); @@ -11626,11 +11743,11 @@ getNDSWDS(const FunctionDecl *FD, ArrayRef ParamAttrs) { assert(!Sizes.empty() && "Unable to determine NDS and WDS."); // The LS of a function parameter / return value can only be a power // of 2, starting from 8 bits, up to 128. - assert(std::all_of(Sizes.begin(), Sizes.end(), - [](unsigned Size) { - return Size == 8 || Size == 16 || Size == 32 || - Size == 64 || Size == 128; - }) && + assert(llvm::all_of(Sizes, + [](unsigned Size) { + return Size == 8 || Size == 16 || Size == 32 || + Size == 64 || Size == 128; + }) && "Invalid size"); return std::make_tuple(*std::min_element(std::begin(Sizes), std::end(Sizes)), @@ -12286,7 +12403,7 @@ bool CGOpenMPRuntime::isNontemporalDecl(const ValueDecl *VD) const { return llvm::any_of( CGM.getOpenMPRuntime().NontemporalDeclsStack, - [VD](const NontemporalDeclsSet &Set) { return Set.count(VD) > 0; }); + [VD](const NontemporalDeclsSet &Set) { return Set.contains(VD); }); } void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( @@ -12957,7 +13074,8 @@ Address CGOpenMPSIMDRuntime::getTaskReductionItem(CodeGenFunction &CGF, } void CGOpenMPSIMDRuntime::emitTaskwaitCall(CodeGenFunction &CGF, - SourceLocation Loc) { + SourceLocation Loc, + const OMPTaskDataTy &Data) { llvm_unreachable("Not supported in SIMD-only mode"); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index c24648aae7e..527a23a8af6 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -795,9 +795,11 @@ private: llvm::Type *getKmpc_MicroPointerTy(); /// Returns __kmpc_for_static_init_* runtime function for the specified - /// size \a IVSize and sign \a IVSigned. + /// size \a IVSize and sign \a IVSigned. Will create a distribute call + /// __kmpc_distribute_static_init* if \a IsGPUDistribute is set. llvm::FunctionCallee createForStaticInitFunction(unsigned IVSize, - bool IVSigned); + bool IVSigned, + bool IsGPUDistribute); /// Returns __kmpc_dispatch_init_* runtime function for the specified /// size \a IVSize and sign \a IVSigned. @@ -1545,7 +1547,8 @@ public: LValue SharedLVal); /// Emit code for 'taskwait' directive. - virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc); + virtual void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, + const OMPTaskDataTy &Data); /// Emit code for 'cancellation point' construct. /// \param CancelRegion Region kind for which the cancellation point must be @@ -2383,7 +2386,8 @@ public: LValue SharedLVal) override; /// Emit code for 'taskwait' directive. - void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc) override; + void emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, + const OMPTaskDataTy &Data) override; /// Emit code for 'cancellation point' construct. /// \param CancelRegion Region kind for which the cancellation point must be diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp deleted file mode 100644 index 33d4ab838af..00000000000 --- a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===-- CGOpenMPRuntimeAMDGCN.cpp - Interface to OpenMP AMDGCN Runtimes --===// -// -// 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 provides a class for OpenMP runtime code generation specialized to -// AMDGCN targets from generalized CGOpenMPRuntimeGPU class. -// -//===----------------------------------------------------------------------===// - -#include "CGOpenMPRuntimeAMDGCN.h" -#include "CGOpenMPRuntimeGPU.h" -#include "CodeGenFunction.h" -#include "clang/AST/Attr.h" -#include "clang/AST/DeclOpenMP.h" -#include "clang/AST/StmtOpenMP.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/Cuda.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/IR/IntrinsicsAMDGPU.h" - -using namespace clang; -using namespace CodeGen; -using namespace llvm::omp; - -CGOpenMPRuntimeAMDGCN::CGOpenMPRuntimeAMDGCN(CodeGenModule &CGM) - : CGOpenMPRuntimeGPU(CGM) { - if (!CGM.getLangOpts().OpenMPIsDevice) - llvm_unreachable("OpenMP AMDGCN can only handle device code."); -} - -llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUWarpSize(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - // return constant compile-time target-specific warp size - unsigned WarpSize = CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size); - return Bld.getInt32(WarpSize); -} - -llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUThreadID(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - llvm::Function *F = - CGF.CGM.getIntrinsic(llvm::Intrinsic::amdgcn_workitem_id_x); - return Bld.CreateCall(F, llvm::None, "nvptx_tid"); -} - -llvm::Value *CGOpenMPRuntimeAMDGCN::getGPUNumThreads(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - llvm::Module *M = &CGF.CGM.getModule(); - const char *LocSize = "__kmpc_amdgcn_gpu_num_threads"; - llvm::Function *F = M->getFunction(LocSize); - if (!F) { - F = llvm::Function::Create( - llvm::FunctionType::get(CGF.Int32Ty, llvm::None, false), - llvm::GlobalVariable::ExternalLinkage, LocSize, &CGF.CGM.getModule()); - } - return Bld.CreateCall(F, llvm::None, "nvptx_num_threads"); -} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h b/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h deleted file mode 100644 index c1421261bfc..00000000000 --- a/clang/lib/CodeGen/CGOpenMPRuntimeAMDGCN.h +++ /dev/null @@ -1,43 +0,0 @@ -//===--- CGOpenMPRuntimeAMDGCN.h - Interface to OpenMP AMDGCN Runtimes ---===// -// -// 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 provides a class for OpenMP runtime code generation specialized to -// AMDGCN targets from generalized CGOpenMPRuntimeGPU class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H -#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H - -#include "CGOpenMPRuntime.h" -#include "CGOpenMPRuntimeGPU.h" -#include "CodeGenFunction.h" -#include "clang/AST/StmtOpenMP.h" - -namespace clang { -namespace CodeGen { - -class CGOpenMPRuntimeAMDGCN final : public CGOpenMPRuntimeGPU { - -public: - explicit CGOpenMPRuntimeAMDGCN(CodeGenModule &CGM); - - /// Get the GPU warp size. - llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) override; - - /// Get the id of the current thread on the GPU. - llvm::Value *getGPUThreadID(CodeGenFunction &CGF) override; - - /// Get the maximum number of threads in a block of the GPU. - llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) override; -}; - -} // namespace CodeGen -} // namespace clang - -#endif // LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMEAMDGCN_H diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 63fecedc6fb..dcb224f3315 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "CGOpenMPRuntimeGPU.h" -#include "CGOpenMPRuntimeNVPTX.h" #include "CodeGenFunction.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclOpenMP.h" @@ -21,7 +20,7 @@ #include "clang/Basic/Cuda.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Frontend/OpenMP/OMPGridValues.h" -#include "llvm/IR/IntrinsicsNVPTX.h" +#include "llvm/Support/MathExtras.h" using namespace clang; using namespace CodeGen; @@ -106,8 +105,7 @@ public: /// is the same for all known NVPTX architectures. enum MachineConfiguration : unsigned { /// See "llvm/Frontend/OpenMP/OMPGridValues.h" for various related target - /// specific Grid Values like GV_Warp_Size, GV_Warp_Size_Log2, - /// and GV_Warp_Size_Log2_Mask. + /// specific Grid Values like GV_Warp_Size, GV_Slot_Size /// Global memory alignment for performance. GlobalMemoryAlignment = 128, @@ -339,7 +337,7 @@ class CheckVarsEscapingDeclContext final assert(!GlobalizedRD && "Record for globalized variables is built already."); ArrayRef EscapedDeclsForParallel, EscapedDeclsForTeams; - unsigned WarpSize = CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size); + unsigned WarpSize = CGF.getTarget().getGridValue().GV_Warp_Size; if (IsInTTDRegion) EscapedDeclsForTeams = EscapedDecls.getArrayRef(); else @@ -536,7 +534,7 @@ public: static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) { CGBuilderTy &Bld = CGF.Builder; unsigned LaneIDBits = - CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size_Log2); + llvm::Log2_32(CGF.getTarget().getGridValue().GV_Warp_Size); auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); return Bld.CreateAShr(RT.getGPUThreadID(CGF), LaneIDBits, "nvptx_warp_id"); } @@ -546,8 +544,9 @@ static llvm::Value *getNVPTXWarpID(CodeGenFunction &CGF) { /// on the NVPTX device, to generate more efficient code. static llvm::Value *getNVPTXLaneID(CodeGenFunction &CGF) { CGBuilderTy &Bld = CGF.Builder; - unsigned LaneIDMask = CGF.getContext().getTargetInfo().getGridValue( - llvm::omp::GV_Warp_Size_Log2_Mask); + unsigned LaneIDBits = + llvm::Log2_32(CGF.getTarget().getGridValue().GV_Warp_Size); + unsigned LaneIDMask = ~0u >> (32u - LaneIDBits); auto &RT = static_cast(CGF.CGM.getOpenMPRuntime()); return Bld.CreateAnd(RT.getGPUThreadID(CGF), Bld.getInt32(LaneIDMask), "nvptx_lane_id"); @@ -1111,11 +1110,12 @@ void CGOpenMPRuntimeGPU::emitSPMDKernel(const OMPExecutableDirective &D, // warps participate in parallel work. static void setPropertyExecutionMode(CodeGenModule &CGM, StringRef Name, bool Mode) { - auto *GVMode = - new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true, - llvm::GlobalValue::WeakAnyLinkage, - llvm::ConstantInt::get(CGM.Int8Ty, Mode ? 0 : 1), - Twine(Name, "_exec_mode")); + auto *GVMode = new llvm::GlobalVariable( + CGM.getModule(), CGM.Int8Ty, /*isConstant=*/true, + llvm::GlobalValue::WeakAnyLinkage, + llvm::ConstantInt::get(CGM.Int8Ty, Mode ? OMP_TGT_EXEC_MODE_SPMD + : OMP_TGT_EXEC_MODE_GENERIC), + Twine(Name, "_exec_mode")); CGM.addCompilerUsedGlobal(GVMode); } @@ -1195,7 +1195,17 @@ unsigned CGOpenMPRuntimeGPU::getDefaultLocationReserved2Flags() const { CGOpenMPRuntimeGPU::CGOpenMPRuntimeGPU(CodeGenModule &CGM) : CGOpenMPRuntime(CGM, "_", "$") { if (!CGM.getLangOpts().OpenMPIsDevice) - llvm_unreachable("OpenMP NVPTX can only handle device code."); + llvm_unreachable("OpenMP can only handle device code."); + + llvm::OpenMPIRBuilder &OMPBuilder = getOMPBuilder(); + if (CGM.getLangOpts().OpenMPTargetNewRuntime) { + OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPTargetDebug, + "__omp_rtl_debug_kind"); + OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPTeamSubscription, + "__omp_rtl_assume_teams_oversubscription"); + OMPBuilder.createGlobalFlag(CGM.getLangOpts().OpenMPThreadSubscription, + "__omp_rtl_assume_threads_oversubscription"); + } } void CGOpenMPRuntimeGPU::emitProcBindClause(CodeGenFunction &CGF, @@ -1308,7 +1318,7 @@ llvm::Function *CGOpenMPRuntimeGPU::emitTeamsOutlinedFunction( const RecordDecl *GlobalizedRD = nullptr; llvm::SmallVector LastPrivatesReductions; llvm::SmallDenseMap MappedDeclsFields; - unsigned WarpSize = CGM.getTarget().getGridValue(llvm::omp::GV_Warp_Size); + unsigned WarpSize = CGM.getTarget().getGridValue().GV_Warp_Size; // Globalize team reductions variable unconditionally in all modes. if (getExecutionMode() != CGOpenMPRuntimeGPU::EM_SPMD) getTeamsReductionVars(CGM.getContext(), D, LastPrivatesReductions); @@ -1488,7 +1498,7 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".zero.addr"); - CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0)); + CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr); llvm::SmallVector OutlinedFnArgs; OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer()); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); @@ -2089,7 +2099,7 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, "__openmp_nvptx_data_transfer_temporary_storage"; llvm::GlobalVariable *TransferMedium = M.getGlobalVariable(TransferMediumName); - unsigned WarpSize = CGF.getTarget().getGridValue(llvm::omp::GV_Warp_Size); + unsigned WarpSize = CGF.getTarget().getGridValue().GV_Warp_Size; if (!TransferMedium) { auto *Ty = llvm::ArrayType::get(CGM.Int32Ty, WarpSize); unsigned SharedAddressSpace = C.getTargetAddressSpace(LangAS::cuda_shared); @@ -3476,7 +3486,7 @@ llvm::Function *CGOpenMPRuntimeGPU::createParallelDataSharingWrapper( Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".zero.addr"); - CGF.InitTempAlloca(ZeroAddr, CGF.Builder.getInt32(/*C*/ 0)); + CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr); // Get the array of arguments. SmallVector Args; @@ -3935,3 +3945,31 @@ void CGOpenMPRuntimeGPU::clear() { } CGOpenMPRuntime::clear(); } + +llvm::Value *CGOpenMPRuntimeGPU::getGPUNumThreads(CodeGenFunction &CGF) { + CGBuilderTy &Bld = CGF.Builder; + llvm::Module *M = &CGF.CGM.getModule(); + const char *LocSize = "__kmpc_get_hardware_num_threads_in_block"; + llvm::Function *F = M->getFunction(LocSize); + if (!F) { + F = llvm::Function::Create( + llvm::FunctionType::get(CGF.Int32Ty, llvm::None, false), + llvm::GlobalVariable::ExternalLinkage, LocSize, &CGF.CGM.getModule()); + } + return Bld.CreateCall(F, llvm::None, "nvptx_num_threads"); +} + +llvm::Value *CGOpenMPRuntimeGPU::getGPUThreadID(CodeGenFunction &CGF) { + ArrayRef Args{}; + return CGF.EmitRuntimeCall( + OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_get_hardware_thread_id_in_block), + Args); +} + +llvm::Value *CGOpenMPRuntimeGPU::getGPUWarpSize(CodeGenFunction &CGF) { + ArrayRef Args{}; + return CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( + CGM.getModule(), OMPRTL___kmpc_get_warp_size), + Args); +} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h index b5f1b843c46..ac51264d768 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.h @@ -17,7 +17,6 @@ #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "clang/AST/StmtOpenMP.h" -#include "llvm/Frontend/OpenMP/OMPGridValues.h" namespace clang { namespace CodeGen { @@ -177,13 +176,13 @@ public: /// and NVPTX. /// Get the GPU warp size. - virtual llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) = 0; + llvm::Value *getGPUWarpSize(CodeGenFunction &CGF); /// Get the id of the current thread on the GPU. - virtual llvm::Value *getGPUThreadID(CodeGenFunction &CGF) = 0; + llvm::Value *getGPUThreadID(CodeGenFunction &CGF); /// Get the maximum number of threads in a block of the GPU. - virtual llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) = 0; + llvm::Value *getGPUNumThreads(CodeGenFunction &CGF); /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 /// global_tid, int proc_bind) to generate code for 'proc_bind' clause. diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp deleted file mode 100644 index 1688d07b90b..00000000000 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===---- CGOpenMPRuntimeNVPTX.cpp - Interface to OpenMP NVPTX Runtimes ---===// -// -// 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 provides a class for OpenMP runtime code generation specialized to NVPTX -// targets from generalized CGOpenMPRuntimeGPU class. -// -//===----------------------------------------------------------------------===// - -#include "CGOpenMPRuntimeNVPTX.h" -#include "CGOpenMPRuntimeGPU.h" -#include "CodeGenFunction.h" -#include "clang/AST/Attr.h" -#include "clang/AST/DeclOpenMP.h" -#include "clang/AST/StmtOpenMP.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/Basic/Cuda.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/IR/IntrinsicsNVPTX.h" - -using namespace clang; -using namespace CodeGen; -using namespace llvm::omp; - -CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM) - : CGOpenMPRuntimeGPU(CGM) { - if (!CGM.getLangOpts().OpenMPIsDevice) - llvm_unreachable("OpenMP NVPTX can only handle device code."); -} - -llvm::Value *CGOpenMPRuntimeNVPTX::getGPUWarpSize(CodeGenFunction &CGF) { - return CGF.EmitRuntimeCall( - llvm::Intrinsic::getDeclaration( - &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_warpsize), - "nvptx_warp_size"); -} - -llvm::Value *CGOpenMPRuntimeNVPTX::getGPUThreadID(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - llvm::Function *F; - F = llvm::Intrinsic::getDeclaration( - &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_tid_x); - return Bld.CreateCall(F, llvm::None, "nvptx_tid"); -} - -llvm::Value *CGOpenMPRuntimeNVPTX::getGPUNumThreads(CodeGenFunction &CGF) { - CGBuilderTy &Bld = CGF.Builder; - llvm::Function *F; - F = llvm::Intrinsic::getDeclaration( - &CGF.CGM.getModule(), llvm::Intrinsic::nvvm_read_ptx_sreg_ntid_x); - return Bld.CreateCall(F, llvm::None, "nvptx_num_threads"); -} diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h deleted file mode 100644 index 5f160295926..00000000000 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ /dev/null @@ -1,43 +0,0 @@ -//===----- CGOpenMPRuntimeNVPTX.h - Interface to OpenMP NVPTX Runtimes ----===// -// -// 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 provides a class for OpenMP runtime code generation specialized to NVPTX -// targets from generalized CGOpenMPRuntimeGPU class. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H -#define LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H - -#include "CGOpenMPRuntime.h" -#include "CGOpenMPRuntimeGPU.h" -#include "CodeGenFunction.h" -#include "clang/AST/StmtOpenMP.h" - -namespace clang { -namespace CodeGen { - -class CGOpenMPRuntimeNVPTX final : public CGOpenMPRuntimeGPU { - -public: - explicit CGOpenMPRuntimeNVPTX(CodeGenModule &CGM); - - /// Get the GPU warp size. - llvm::Value *getGPUWarpSize(CodeGenFunction &CGF) override; - - /// Get the id of the current thread on the GPU. - llvm::Value *getGPUThreadID(CodeGenFunction &CGF) override; - - /// Get the maximum number of threads in a block of the GPU. - llvm::Value *getGPUNumThreads(CodeGenFunction &CGF) override; -}; - -} // CodeGen namespace. -} // clang namespace. - -#endif // LLVM_CLANG_LIB_CODEGEN_CGOPENMPRUNTIMENVPTX_H diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index aeb319ca158..d399ff919cc 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -26,6 +26,7 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/Assumptions.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" @@ -196,6 +197,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::SEHTryStmtClass: EmitSEHTryStmt(cast(*S)); break; + case Stmt::OMPMetaDirectiveClass: + EmitOMPMetaDirective(cast(*S)); + break; case Stmt::OMPCanonicalLoopClass: EmitOMPCanonicalLoop(cast(S)); break; @@ -389,6 +393,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef Attrs) { case Stmt::OMPMaskedDirectiveClass: EmitOMPMaskedDirective(cast(*S)); break; + case Stmt::OMPGenericLoopDirectiveClass: + EmitOMPGenericLoopDirective(cast(*S)); + break; } } @@ -709,6 +716,17 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) { } void CodeGenFunction::EmitIfStmt(const IfStmt &S) { + // The else branch of a consteval if statement is always the only branch that + // can be runtime evaluated. + if (S.isConsteval()) { + const Stmt *Executed = S.isNegatedConsteval() ? S.getThen() : S.getElse(); + if (Executed) { + RunCleanupsScope ExecutedScope(*this); + EmitStmt(Executed); + } + return; + } + // C99 6.8.4.1: The first substatement is executed if the expression compares // unequal to 0. The condition must be a scalar type. LexicalScope ConditionScope(*this, S.getCond()->getSourceRange()); @@ -1518,6 +1536,12 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S, NextCase = dyn_cast(CurCase->getSubStmt()); } + // Generate a stop point for debug info if the case statement is + // followed by a default statement. A fallthrough case before a + // default case gets its own branch target. + if (CurCase->getSubStmt()->getStmtClass() == Stmt::DefaultStmtClass) + EmitStopPoint(CurCase); + // Normal default recursion for non-cases. EmitStmt(CurCase->getSubStmt()); } @@ -2097,7 +2121,8 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, } else { llvm::Type *Ty = ConvertType(InputType); uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty); - if (Size <= 64 && llvm::isPowerOf2_64(Size)) { + if ((Size <= 64 && llvm::isPowerOf2_64(Size)) || + getTargetHooks().isScalarizableAsmOperand(*this, Ty)) { Ty = llvm::IntegerType::get(getLLVMContext(), Size); Ty = llvm::PointerType::getUnqual(Ty); @@ -2187,20 +2212,16 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect, CodeGenFunction &CGF, std::vector &RegResults) { if (!HasUnwindClobber) - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoUnwind); + Result.addFnAttr(llvm::Attribute::NoUnwind); if (NoMerge) - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoMerge); + Result.addFnAttr(llvm::Attribute::NoMerge); // Attach readnone and readonly attributes. if (!HasSideEffect) { if (ReadNone) - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::ReadNone); + Result.addFnAttr(llvm::Attribute::ReadNone); else if (ReadOnly) - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::ReadOnly); + Result.addFnAttr(llvm::Attribute::ReadOnly); } // Slap the source location of the inline asm into a !srcloc metadata on the @@ -2222,8 +2243,7 @@ static void UpdateAsmCallInst(llvm::CallBase &Result, bool HasSideEffect, // convergent (meaning, they may call an intrinsically convergent op, such // as bar.sync, and so can't have certain optimizations applied around // them). - Result.addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::Convergent); + Result.addFnAttr(llvm::Attribute::Convergent); // Extract all of the register value results from the asm. if (ResultRegTypes.size() == 1) { RegResults.push_back(&Result); @@ -2320,23 +2340,28 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // If this is a register output, then make the inline asm return it // by-value. If this is a memory result, return the value by-reference. - bool isScalarizableAggregate = - hasAggregateEvaluationKind(OutExpr->getType()); - if (!Info.allowsMemory() && (hasScalarEvaluationKind(OutExpr->getType()) || - isScalarizableAggregate)) { + QualType QTy = OutExpr->getType(); + const bool IsScalarOrAggregate = hasScalarEvaluationKind(QTy) || + hasAggregateEvaluationKind(QTy); + if (!Info.allowsMemory() && IsScalarOrAggregate) { + Constraints += "=" + OutputConstraint; - ResultRegQualTys.push_back(OutExpr->getType()); + ResultRegQualTys.push_back(QTy); ResultRegDests.push_back(Dest); - ResultTruncRegTypes.push_back(ConvertTypeForMem(OutExpr->getType())); - if (Info.allowsRegister() && isScalarizableAggregate) { - ResultTypeRequiresCast.push_back(true); - unsigned Size = getContext().getTypeSize(OutExpr->getType()); - llvm::Type *ConvTy = llvm::IntegerType::get(getLLVMContext(), Size); - ResultRegTypes.push_back(ConvTy); - } else { - ResultTypeRequiresCast.push_back(false); - ResultRegTypes.push_back(ResultTruncRegTypes.back()); + + llvm::Type *Ty = ConvertTypeForMem(QTy); + const bool RequiresCast = Info.allowsRegister() && + (getTargetHooks().isScalarizableAsmOperand(*this, Ty) || + Ty->isAggregateType()); + + ResultTruncRegTypes.push_back(Ty); + ResultTypeRequiresCast.push_back(RequiresCast); + + if (RequiresCast) { + unsigned Size = getContext().getTypeSize(QTy); + Ty = llvm::IntegerType::get(getLLVMContext(), Size); } + ResultRegTypes.push_back(Ty); // If this output is tied to an input, and if the input is larger, then // we need to set the actual result type of the inline asm node to be the // same as the input type. @@ -2604,8 +2629,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::FunctionType::get(ResultType, ArgTypes, false); bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0; + + llvm::InlineAsm::AsmDialect GnuAsmDialect = + CGM.getCodeGenOpts().getInlineAsmDialect() == CodeGenOptions::IAD_ATT + ? llvm::InlineAsm::AD_ATT + : llvm::InlineAsm::AD_Intel; llvm::InlineAsm::AsmDialect AsmDialect = isa(&S) ? - llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT; + llvm::InlineAsm::AD_Intel : GnuAsmDialect; + llvm::InlineAsm *IA = llvm::InlineAsm::get( FTy, AsmString, Constraints, HasSideEffect, /* IsAlignStack */ false, AsmDialect, HasUnwindClobber); @@ -2638,11 +2669,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { assert(ResultTypeRequiresCast.size() <= ResultRegDests.size()); for (unsigned i = 0, e = RegResults.size(); i != e; ++i) { llvm::Value *Tmp = RegResults[i]; + llvm::Type *TruncTy = ResultTruncRegTypes[i]; // If the result type of the LLVM IR asm doesn't match the result type of // the expression, do the conversion. if (ResultRegTypes[i] != ResultTruncRegTypes[i]) { - llvm::Type *TruncTy = ResultTruncRegTypes[i]; // Truncate the integer result to the right size, note that TruncTy can be // a pointer. @@ -2672,6 +2703,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]); Address A = Builder.CreateBitCast(Dest.getAddress(*this), ResultRegTypes[i]->getPointerTo()); + if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) { + Builder.CreateStore(Tmp, A); + continue; + } + QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false); if (Ty.isNull()) { const Expr *OutExpr = S.getOutputExpr(i); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index f6233b79118..4f14459e4d2 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -309,8 +309,8 @@ llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) { while (const VariableArrayType *VAT = C.getAsVariableArrayType(Ty)) { VlaSizePair VlaSize = getVLASize(VAT); Ty = VlaSize.Type; - Size = Size ? Builder.CreateNUWMul(Size, VlaSize.NumElts) - : VlaSize.NumElts; + Size = + Size ? Builder.CreateNUWMul(Size, VlaSize.NumElts) : VlaSize.NumElts; } SizeInChars = C.getTypeSizeInChars(Ty); if (SizeInChars.isZero()) @@ -450,7 +450,8 @@ static llvm::Function *emitOutlinedFunctionPrologue( Ctx, Ctx.getTranslationUnitDecl(), FO.S->getBeginLoc(), SourceLocation(), DeclarationName(), FunctionTy, Ctx.getTrivialTypeSourceInfo(FunctionTy), SC_Static, - /*isInlineSpecified=*/false, /*hasWrittenPrototype=*/false); + /*UsesFPIntrin=*/false, /*isInlineSpecified=*/false, + /*hasWrittenPrototype=*/false); } for (const FieldDecl *FD : RD->fields()) { QualType ArgType = FD->getType(); @@ -497,9 +498,8 @@ static llvm::Function *emitOutlinedFunctionPrologue( : CGM.getOpenMPRuntime().translateParameter(FD, Arg)); ++I; } - Args.append( - std::next(CD->param_begin(), CD->getContextParamPosition() + 1), - CD->param_end()); + Args.append(std::next(CD->param_begin(), CD->getContextParamPosition() + 1), + CD->param_end()); TargetArgs.append( std::next(CD->param_begin(), CD->getContextParamPosition() + 1), CD->param_end()); @@ -518,8 +518,10 @@ static llvm::Function *emitOutlinedFunctionPrologue( F->setDoesNotRecurse(); // Always inline the outlined function if optimizations are enabled. - if (CGM.getCodeGenOpts().OptimizationLevel != 0) + if (CGM.getCodeGenOpts().OptimizationLevel != 0) { + F->removeFnAttr(llvm::Attribute::NoInline); F->addFnAttr(llvm::Attribute::AlwaysInline); + } // Generate the function. CGF.StartFunction(CD, Ctx.VoidTy, F, FuncInfo, TargetArgs, @@ -671,9 +673,9 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S, if (EI != VLASizes.end()) { CallArg = EI->second.second; } else { - LValue LV = WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg), - Arg->getType(), - AlignmentSource::Decl); + LValue LV = + WrapperCGF.MakeAddrLValue(WrapperCGF.GetAddrOfLocalVar(Arg), + Arg->getType(), AlignmentSource::Decl); CallArg = WrapperCGF.EmitLoadOfScalar(LV, S.getBeginLoc()); } } @@ -718,29 +720,29 @@ void CodeGenFunction::EmitOMPAggregateAssign( CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy); llvm::PHINode *SrcElementPHI = - Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast"); + Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast"); SrcElementPHI->addIncoming(SrcBegin, EntryBB); Address SrcElementCurrent = Address(SrcElementPHI, SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize)); - llvm::PHINode *DestElementPHI = - Builder.CreatePHI(DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); + llvm::PHINode *DestElementPHI = Builder.CreatePHI( + DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); DestElementPHI->addIncoming(DestBegin, EntryBB); Address DestElementCurrent = - Address(DestElementPHI, - DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); + Address(DestElementPHI, + DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); // Emit copy. CopyGen(DestElementCurrent, SrcElementCurrent); // Shift the address forward by one element. - llvm::Value *DestElementNext = Builder.CreateConstGEP1_32( - DestAddr.getElementType(), DestElementPHI, /*Idx0=*/1, - "omp.arraycpy.dest.element"); - llvm::Value *SrcElementNext = Builder.CreateConstGEP1_32( - SrcAddr.getElementType(), SrcElementPHI, /*Idx0=*/1, - "omp.arraycpy.src.element"); + llvm::Value *DestElementNext = + Builder.CreateConstGEP1_32(DestAddr.getElementType(), DestElementPHI, + /*Idx0=*/1, "omp.arraycpy.dest.element"); + llvm::Value *SrcElementNext = + Builder.CreateConstGEP1_32(SrcAddr.getElementType(), SrcElementPHI, + /*Idx0=*/1, "omp.arraycpy.src.element"); // Check whether we've reached the end. llvm::Value *Done = Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done"); @@ -1003,9 +1005,9 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { LocalDeclMap.erase(VD); } else { MasterAddr = - Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) - : CGM.GetAddrOfGlobal(VD), - getContext().getDeclAlign(VD)); + Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) + : CGM.GetAddrOfGlobal(VD), + getContext().getDeclAlign(VD)); } // Get the address of the threadprivate variable. Address PrivateAddr = EmitLValue(*IRef).getAddress(*this); @@ -1076,7 +1078,7 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() { DeclRefExpr DRE(getContext(), const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/ - CapturedStmtInfo->lookup(OrigVD) != nullptr, + CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); return EmitLValue(&DRE).getAddress(*this); }); @@ -1085,19 +1087,19 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( // for 'firstprivate' clause. if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) { const auto *VD = cast(cast(IInit)->getDecl()); - bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, VD, C, - OrigVD]() { - if (C->getKind() == OMPC_LASTPRIVATE_conditional) { - Address VDAddr = - CGM.getOpenMPRuntime().emitLastprivateConditionalInit(*this, - OrigVD); - setAddrOfLocalVar(VD, VDAddr); - return VDAddr; - } - // Emit private VarDecl with copy init. - EmitDecl(*VD); - return GetAddrOfLocalVar(VD); - }); + bool IsRegistered = + PrivateScope.addPrivate(OrigVD, [this, VD, C, OrigVD]() { + if (C->getKind() == OMPC_LASTPRIVATE_conditional) { + Address VDAddr = + CGM.getOpenMPRuntime().emitLastprivateConditionalInit( + *this, OrigVD); + setAddrOfLocalVar(VD, VDAddr); + return VDAddr; + } + // Emit private VarDecl with copy init. + EmitDecl(*VD); + return GetAddrOfLocalVar(VD); + }); assert(IsRegistered && "lastprivate var already registered as private"); (void)IsRegistered; @@ -1292,14 +1294,12 @@ void CodeGenFunction::EmitOMPReductionClauseInit( OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin"); } PrivateScope.addPrivate(LHSVD, [OriginalAddr]() { return OriginalAddr; }); - PrivateScope.addPrivate( - RHSVD, [this, PrivateVD, RHSVD, IsArray]() { - return IsArray - ? Builder.CreateElementBitCast( + PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD, IsArray]() { + return IsArray ? Builder.CreateElementBitCast( GetAddrOfLocalVar(PrivateVD), ConvertTypeForMem(RHSVD->getType()), "rhs.begin") : GetAddrOfLocalVar(PrivateVD); - }); + }); } ++ILHS; ++IRHS; @@ -1786,6 +1786,10 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { checkForLastprivateConditionalUpdate(*this, S); } +void CodeGenFunction::EmitOMPMetaDirective(const OMPMetaDirective &S) { + EmitStmt(S.getIfStmt()); +} + namespace { /// RAII to handle scopes for loop transformation directives. class OMPTransformDirectiveScopeRAII { @@ -1827,9 +1831,7 @@ static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop, return; } if (SimplifiedS == NextLoop) { - if (auto *Dir = dyn_cast(SimplifiedS)) - SimplifiedS = Dir->getTransformedStmt(); - if (auto *Dir = dyn_cast(SimplifiedS)) + if (auto *Dir = dyn_cast(SimplifiedS)) SimplifiedS = Dir->getTransformedStmt(); if (const auto *CanonLoop = dyn_cast(SimplifiedS)) SimplifiedS = CanonLoop->getLoopStmt(); @@ -1953,11 +1955,27 @@ llvm::CanonicalLoopInfo * CodeGenFunction::EmitOMPCollapsedCanonicalLoopNest(const Stmt *S, int Depth) { assert(Depth == 1 && "Nested loops with OpenMPIRBuilder not yet implemented"); + // The caller is processing the loop-associated directive processing the \p + // Depth loops nested in \p S. Put the previous pending loop-associated + // directive to the stack. If the current loop-associated directive is a loop + // transformation directive, it will push its generated loops onto the stack + // such that together with the loops left here they form the combined loop + // nest for the parent loop-associated directive. + int ParentExpectedOMPLoopDepth = ExpectedOMPLoopDepth; + ExpectedOMPLoopDepth = Depth; + EmitStmt(S); assert(OMPLoopNestStack.size() >= (size_t)Depth && "Found too few loops"); // The last added loop is the outermost one. - return OMPLoopNestStack.back(); + llvm::CanonicalLoopInfo *Result = OMPLoopNestStack.back(); + + // Pop the \p Depth loops requested by the call from that stack and restore + // the previous context. + OMPLoopNestStack.set_size(OMPLoopNestStack.size() - Depth); + ExpectedOMPLoopDepth = ParentExpectedOMPLoopDepth; + + return Result; } void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { @@ -2113,9 +2131,10 @@ bool CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) { CapturedStmtInfo->lookup(OrigVD) != nullptr, VD->getInit()->getType(), VK_LValue, VD->getInit()->getExprLoc()); - EmitExprAsInit(&DRE, VD, MakeAddrLValue(Emission.getAllocatedAddress(), - VD->getType()), - /*capturedByInit=*/false); + EmitExprAsInit( + &DRE, VD, + MakeAddrLValue(Emission.getAllocatedAddress(), VD->getType()), + /*capturedByInit=*/false); EmitAutoVarCleanups(Emission); } else { EmitVarDecl(*VD); @@ -2218,9 +2237,8 @@ void CodeGenFunction::EmitOMPPrivateLoopCounters( AutoVarEmission VarEmission = EmitAutoVarAlloca(*PrivateVD); EmitAutoVarCleanups(VarEmission); LocalDeclMap.erase(PrivateVD); - (void)LoopScope.addPrivate(VD, [&VarEmission]() { - return VarEmission.getAllocatedAddress(); - }); + (void)LoopScope.addPrivate( + VD, [&VarEmission]() { return VarEmission.getAllocatedAddress(); }); if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) || VD->hasGlobalStorage()) { (void)LoopScope.addPrivate(PrivateVD, [this, VD, E]() { @@ -2272,7 +2290,7 @@ static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, // Create temp loop control variables with their init values to support // non-rectangular loops. CodeGenFunction::OMPMapVars PreCondVars; - for (const Expr * E: S.dependent_counters()) { + for (const Expr *E : S.dependent_counters()) { if (!E) continue; assert(!E->getType().getNonReferenceType()->isRecordType() && @@ -2587,6 +2605,46 @@ void CodeGenFunction::EmitOMPTileDirective(const OMPTileDirective &S) { } void CodeGenFunction::EmitOMPUnrollDirective(const OMPUnrollDirective &S) { + bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder; + + if (UseOMPIRBuilder) { + auto DL = SourceLocToDebugLoc(S.getBeginLoc()); + const Stmt *Inner = S.getRawStmt(); + + // Consume nested loop. Clear the entire remaining loop stack because a + // fully unrolled loop is non-transformable. For partial unrolling the + // generated outer loop is pushed back to the stack. + llvm::CanonicalLoopInfo *CLI = EmitOMPCollapsedCanonicalLoopNest(Inner, 1); + OMPLoopNestStack.clear(); + + llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); + + bool NeedsUnrolledCLI = ExpectedOMPLoopDepth >= 1; + llvm::CanonicalLoopInfo *UnrolledCLI = nullptr; + + if (S.hasClausesOfKind()) { + assert(ExpectedOMPLoopDepth == 0); + OMPBuilder.unrollLoopFull(DL, CLI); + } else if (auto *PartialClause = S.getSingleClause()) { + uint64_t Factor = 0; + if (Expr *FactorExpr = PartialClause->getFactor()) { + Factor = FactorExpr->EvaluateKnownConstInt(getContext()).getZExtValue(); + assert(Factor >= 1 && "Only positive factors are valid"); + } + OMPBuilder.unrollLoopPartial(DL, CLI, Factor, + NeedsUnrolledCLI ? &UnrolledCLI : nullptr); + } else { + OMPBuilder.unrollLoopHeuristic(DL, CLI); + } + + assert((!NeedsUnrolledCLI || UnrolledCLI) && + "NeedsUnrolledCLI implies UnrolledCLI to be set"); + if (UnrolledCLI) + OMPLoopNestStack.push_back(UnrolledCLI); + + return; + } + // This function is only called if the unrolled loop is not consumed by any // other loop-associated construct. Such a loop-associated construct will have // used the transformed AST. @@ -2732,12 +2790,10 @@ void CodeGenFunction::EmitOMPForOuterLoop( CGOpenMPRuntime &RT = CGM.getOpenMPRuntime(); // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime). - const bool DynamicOrOrdered = - Ordered || RT.isDynamic(ScheduleKind.Schedule); + const bool DynamicOrOrdered = Ordered || RT.isDynamic(ScheduleKind.Schedule); - assert((Ordered || - !RT.isStaticNonchunked(ScheduleKind.Schedule, - LoopArgs.Chunk != nullptr)) && + assert((Ordered || !RT.isStaticNonchunked(ScheduleKind.Schedule, + LoopArgs.Chunk != nullptr)) && "static non-chunked schedule does not need outer loop"); // Emit outer loop. @@ -3057,15 +3113,15 @@ void CodeGenFunction::EmitOMPTargetSimdDirective( } namespace { - struct ScheduleKindModifiersTy { - OpenMPScheduleClauseKind Kind; - OpenMPScheduleClauseModifier M1; - OpenMPScheduleClauseModifier M2; - ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind, - OpenMPScheduleClauseModifier M1, - OpenMPScheduleClauseModifier M2) - : Kind(Kind), M1(M1), M2(M2) {} - }; +struct ScheduleKindModifiersTy { + OpenMPScheduleClauseKind Kind; + OpenMPScheduleClauseModifier M1; + OpenMPScheduleClauseModifier M2; + ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind, + OpenMPScheduleClauseModifier M1, + OpenMPScheduleClauseModifier M2) + : Kind(Kind), M1(M1), M2(M2) {} +}; } // namespace bool CodeGenFunction::EmitOMPWorksharingLoop( @@ -3185,8 +3241,10 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( // If the static schedule kind is specified or if the ordered clause is // specified, and if no monotonic modifier is specified, the effect will // be as if the monotonic modifier was specified. - bool StaticChunkedOne = RT.isStaticChunked(ScheduleKind.Schedule, - /* Chunked */ Chunk != nullptr) && HasChunkSizeOne && + bool StaticChunkedOne = + RT.isStaticChunked(ScheduleKind.Schedule, + /* Chunked */ Chunk != nullptr) && + HasChunkSizeOne && isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()); bool IsMonotonic = Ordered || @@ -3620,7 +3678,8 @@ void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { CGM.getOpenMPRuntime().getOMPBuilder(); llvm::OpenMPIRBuilder::InsertPointTy AllocaIP( AllocaInsertPt->getParent(), AllocaInsertPt->getIterator()); - OMPBuilder.createWorkshareLoop(Builder, CLI, AllocaIP, NeedsBarrier); + OMPBuilder.applyWorkshareLoop(Builder.getCurrentDebugLocation(), CLI, + AllocaIP, NeedsBarrier); return; } @@ -4440,7 +4499,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( const auto *OrigVD = cast(Pair.second->getDecl()); DeclRefExpr DRE(CGF.getContext(), const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/ - CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr, + CGF.CapturedStmtInfo->lookup(OrigVD) != nullptr, Pair.second->getType(), VK_LValue, Pair.second->getExprLoc()); Scope.addPrivate(Pair.first, [&CGF, &DRE]() { @@ -4661,7 +4720,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective( [&InputInfo]() { return InputInfo.SizesArray; }); // If there is no user-defined mapper, the mapper array will be nullptr. In // this case, we don't need to privatize it. - if (!dyn_cast_or_null( + if (!isa_and_nonnull( InputInfo.MappersArray.getPointer())) { MVD = createImplicitFirstprivateForType( getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc()); @@ -4786,7 +4845,14 @@ void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) { } void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { - CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc()); + OMPTaskDataTy Data; + // Build list of dependences + for (const auto *C : S.getClausesOfKind()) { + OMPTaskDataTy::DependData &DD = + Data.Dependences.emplace_back(C->getDependencyKind(), C->getModifier()); + DD.DepExprs.append(C->varlist_begin(), C->varlist_end()); + } + CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data); } void CodeGenFunction::EmitOMPTaskgroupDirective( @@ -5168,8 +5234,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, // iteration space is divided into chunks that are approximately equal // in size, and at most one chunk is distributed to each team of the // league. The size of the chunks is unspecified in this case. - bool StaticChunked = RT.isStaticChunked( - ScheduleKind, /* Chunked */ Chunk != nullptr) && + bool StaticChunked = + RT.isStaticChunked(ScheduleKind, /* Chunked */ Chunk != nullptr) && isOpenMPLoopBoundSharingDirective(S.getDirectiveKind()); if (RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr) || @@ -5307,12 +5373,78 @@ static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM, CGF.CapturedStmtInfo = &CapStmtInfo; llvm::Function *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S, Loc); Fn->setDoesNotRecurse(); - if (CGM.getCodeGenOpts().OptimizationLevel != 0) - Fn->addFnAttr(llvm::Attribute::AlwaysInline); return Fn; } void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { + if (CGM.getLangOpts().OpenMPIRBuilder) { + llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); + using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; + + if (S.hasClausesOfKind()) { + // The ordered directive with depend clause. + assert(!S.hasAssociatedStmt() && + "No associated statement must be in ordered depend construct."); + InsertPointTy AllocaIP(AllocaInsertPt->getParent(), + AllocaInsertPt->getIterator()); + for (const auto *DC : S.getClausesOfKind()) { + unsigned NumLoops = DC->getNumLoops(); + QualType Int64Ty = CGM.getContext().getIntTypeForBitwidth( + /*DestWidth=*/64, /*Signed=*/1); + llvm::SmallVector StoreValues; + for (unsigned I = 0; I < NumLoops; I++) { + const Expr *CounterVal = DC->getLoopData(I); + assert(CounterVal); + llvm::Value *StoreValue = EmitScalarConversion( + EmitScalarExpr(CounterVal), CounterVal->getType(), Int64Ty, + CounterVal->getExprLoc()); + StoreValues.emplace_back(StoreValue); + } + bool IsDependSource = false; + if (DC->getDependencyKind() == OMPC_DEPEND_source) + IsDependSource = true; + Builder.restoreIP(OMPBuilder.createOrderedDepend( + Builder, AllocaIP, NumLoops, StoreValues, ".cnt.addr", + IsDependSource)); + } + } else { + // The ordered directive with threads or simd clause, or without clause. + // Without clause, it behaves as if the threads clause is specified. + const auto *C = S.getSingleClause(); + + auto FiniCB = [this](InsertPointTy IP) { + OMPBuilderCBHelpers::FinalizeOMPRegion(*this, IP); + }; + + auto BodyGenCB = [&S, C, this](InsertPointTy AllocaIP, + InsertPointTy CodeGenIP, + llvm::BasicBlock &FiniBB) { + const CapturedStmt *CS = S.getInnermostCapturedStmt(); + if (C) { + llvm::SmallVector CapturedVars; + GenerateOpenMPCapturedVars(*CS, CapturedVars); + llvm::Function *OutlinedFn = + emitOutlinedOrderedFunction(CGM, CS, S.getBeginLoc()); + assert(S.getBeginLoc().isValid() && + "Outlined function call location must be valid."); + ApplyDebugLocation::CreateDefaultArtificial(*this, S.getBeginLoc()); + OMPBuilderCBHelpers::EmitCaptureStmt(*this, CodeGenIP, FiniBB, + OutlinedFn, CapturedVars); + } else { + OMPBuilderCBHelpers::InlinedRegionBodyRAII IRB(*this, AllocaIP, + FiniBB); + OMPBuilderCBHelpers::EmitOMPRegionBody(*this, CS->getCapturedStmt(), + CodeGenIP, FiniBB); + } + }; + + OMPLexicalScope Scope(*this, S, OMPD_unknown); + Builder.restoreIP( + OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, !C)); + } + return; + } + if (S.hasClausesOfKind()) { assert(!S.hasAssociatedStmt() && "No associated statement must be in ordered depend construct."); @@ -5863,6 +5995,12 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_novariants: case OMPC_nocontext: case OMPC_filter: + case OMPC_when: + case OMPC_adjust_args: + case OMPC_append_args: + case OMPC_memory_order: + case OMPC_bind: + case OMPC_align: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } @@ -5940,8 +6078,7 @@ static void emitCommonOMPTargetDirective(CodeGenFunction &CGF, return; } - auto LPCRegion = - CGOpenMPRuntime::LastprivateConditionalRAII::disable(CGF, S); + auto LPCRegion = CGOpenMPRuntime::LastprivateConditionalRAII::disable(CGF, S); llvm::Function *Fn = nullptr; llvm::Constant *FnID = nullptr; @@ -6471,7 +6608,8 @@ void CodeGenFunction::EmitOMPUseDevicePtrClause( auto OrigVarIt = C.varlist_begin(); auto InitIt = C.inits().begin(); for (const Expr *PvtVarIt : C.private_copies()) { - const auto *OrigVD = cast(cast(*OrigVarIt)->getDecl()); + const auto *OrigVD = + cast(cast(*OrigVarIt)->getDecl()); const auto *InitVD = cast(cast(*InitIt)->getDecl()); const auto *PvtVD = cast(cast(PvtVarIt)->getDecl()); @@ -6494,31 +6632,30 @@ void CodeGenFunction::EmitOMPUseDevicePtrClause( if (InitAddrIt == CaptureDeviceAddrMap.end()) continue; - bool IsRegistered = PrivateScope.addPrivate(OrigVD, [this, OrigVD, - InitAddrIt, InitVD, - PvtVD]() { - // Initialize the temporary initialization variable with the address we - // get from the runtime library. We have to cast the source address - // because it is always a void *. References are materialized in the - // privatization scope, so the initialization here disregards the fact - // the original variable is a reference. - QualType AddrQTy = - getContext().getPointerType(OrigVD->getType().getNonReferenceType()); - llvm::Type *AddrTy = ConvertTypeForMem(AddrQTy); - Address InitAddr = Builder.CreateBitCast(InitAddrIt->second, AddrTy); - setAddrOfLocalVar(InitVD, InitAddr); + bool IsRegistered = PrivateScope.addPrivate( + OrigVD, [this, OrigVD, InitAddrIt, InitVD, PvtVD]() { + // Initialize the temporary initialization variable with the address + // we get from the runtime library. We have to cast the source address + // because it is always a void *. References are materialized in the + // privatization scope, so the initialization here disregards the fact + // the original variable is a reference. + QualType AddrQTy = getContext().getPointerType( + OrigVD->getType().getNonReferenceType()); + llvm::Type *AddrTy = ConvertTypeForMem(AddrQTy); + Address InitAddr = Builder.CreateBitCast(InitAddrIt->second, AddrTy); + setAddrOfLocalVar(InitVD, InitAddr); - // Emit private declaration, it will be initialized by the value we - // declaration we just added to the local declarations map. - EmitDecl(*PvtVD); + // Emit private declaration, it will be initialized by the value we + // declaration we just added to the local declarations map. + EmitDecl(*PvtVD); - // The initialization variables reached its purpose in the emission - // of the previous declaration, so we don't need it anymore. - LocalDeclMap.erase(InitVD); + // The initialization variables reached its purpose in the emission + // of the previous declaration, so we don't need it anymore. + LocalDeclMap.erase(InitVD); - // Return the address of the private variable. - return GetAddrOfLocalVar(PvtVD); - }); + // Return the address of the private variable. + return GetAddrOfLocalVar(PvtVD); + }); assert(IsRegistered && "firstprivate var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; @@ -6879,11 +7016,11 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { // TODO: Check if we should emit tied or untied task. Data.Tied = true; // Set scheduling for taskloop - if (const auto* Clause = S.getSingleClause()) { + if (const auto *Clause = S.getSingleClause()) { // grainsize clause Data.Schedule.setInt(/*IntVal=*/false); Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize())); - } else if (const auto* Clause = S.getSingleClause()) { + } else if (const auto *Clause = S.getSingleClause()) { // num_tasks clause Data.Schedule.setInt(/*IntVal=*/true); Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks())); @@ -7111,6 +7248,16 @@ void CodeGenFunction::EmitOMPTargetUpdateDirective( CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); } +void CodeGenFunction::EmitOMPGenericLoopDirective( + const OMPGenericLoopDirective &S) { + // Unimplemented, just inline the underlying statement for now. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); + }; + OMPLexicalScope Scope(*this, S, OMPD_unknown); + CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_loop, CodeGen); +} + void CodeGenFunction::EmitSimpleOMPExecutableDirective( const OMPExecutableDirective &D) { if (const auto *SD = dyn_cast(&D)) { diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 9eb65081423..482499da1b0 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -201,7 +201,7 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, Address ThisPtr(&*AI, CGM.getClassPointerAlignment(MD->getParent())); llvm::BasicBlock *EntryBB = &Fn->front(); llvm::BasicBlock::iterator ThisStore = - std::find_if(EntryBB->begin(), EntryBB->end(), [&](llvm::Instruction &I) { + llvm::find_if(*EntryBB, [&](llvm::Instruction &I) { return isa(I) && I.getOperand(0) == ThisPtr.getPointer(); }); diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index b30bd11edba..52c54d3c7a7 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -25,8 +25,10 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/Hashing.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -50,6 +52,8 @@ using namespace clang; using namespace llvm; +#define DEBUG_TYPE "codegenaction" + namespace clang { class BackendConsumer; class ClangDiagnosticHandler final : public DiagnosticHandler { @@ -125,6 +129,17 @@ namespace clang { SmallVector LinkModules; + // A map from mangled names to their function's source location, used for + // backend diagnostics as the Clang AST may be unavailable. We actually use + // the mangled name's hash as the key because mangled names can be very + // long and take up lots of space. Using a hash can cause name collision, + // but that is rare and the consequences are pointing to a wrong source + // location which is not severe. This is a vector instead of an actual map + // because we optimize for time building this map rather than time + // retrieving an entry, as backend diagnostics are uncommon. + std::vector> + ManglingFullSourceLocs; + // This is here so that the diagnostic printer knows the module a diagnostic // refers to. llvm::Module *CurLinkModule = nullptr; @@ -160,7 +175,7 @@ namespace clang { const PreprocessorOptions &PPOpts, const CodeGenOptions &CodeGenOpts, const TargetOptions &TargetOpts, - const LangOptions &LangOpts, + const LangOptions &LangOpts, llvm::Module *Module, SmallVector LinkModules, LLVMContext &C, CoverageSourceInfo *CoverageInfo = nullptr) : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), @@ -170,7 +185,7 @@ namespace clang { LLVMIRGenerationRefCount(0), Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts, CodeGenOpts, C, CoverageInfo)), - LinkModules(std::move(LinkModules)) { + LinkModules(std::move(LinkModules)), CurLinkModule(Module) { TimerIsEnabled = CodeGenOpts.TimePasses; llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses; llvm::TimePassesPerRun = CodeGenOpts.TimePassesPerRun; @@ -329,6 +344,27 @@ namespace clang { if (LinkInModules()) return; + for (auto &F : getModule()->functions()) { + if (const Decl *FD = Gen->GetDeclForMangledName(F.getName())) { + auto Loc = FD->getASTContext().getFullLoc(FD->getLocation()); + // TODO: use a fast content hash when available. + auto NameHash = llvm::hash_value(F.getName()); + ManglingFullSourceLocs.push_back(std::make_pair(NameHash, Loc)); + } + } + + if (CodeGenOpts.ClearASTBeforeBackend) { + LLVM_DEBUG(llvm::dbgs() << "Clearing AST...\n"); + // Access to the AST is no longer available after this. + // Other things that the ASTContext manages are still available, e.g. + // the SourceManager. It'd be nice if we could separate out all the + // things in ASTContext used after this point and null out the + // ASTContext, but too many various parts of the ASTContext are still + // used in various parts. + C.cleanup(); + C.getAllocator().Reset(); + } + EmbedBitcode(getModule(), CodeGenOpts, llvm::MemoryBufferRef()); EmitBackendOutput(Diags, HeaderSearchOpts, CodeGenOpts, TargetOpts, @@ -375,6 +411,8 @@ namespace clang { bool &BadDebugInfo, StringRef &Filename, unsigned &Line, unsigned &Column) const; + Optional getFunctionSourceLocation(const Function &F) const; + void DiagnosticHandlerImpl(const llvm::DiagnosticInfo &DI); /// Specialized handler for InlineAsm diagnostic. /// \return True if the diagnostic has been successfully reported, false @@ -401,6 +439,7 @@ namespace clang { const llvm::OptimizationRemarkAnalysisAliasing &D); void OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D); + void DontCallDiagHandler(const DiagnosticInfoDontCall &D); }; void BackendConsumer::anchor() {} @@ -567,17 +606,16 @@ BackendConsumer::StackSizeDiagHandler(const llvm::DiagnosticInfoStackSize &D) { // We do not know how to format other severities. return false; - if (const Decl *ND = Gen->GetDeclForMangledName(D.getFunction().getName())) { - // FIXME: Shouldn't need to truncate to uint32_t - Diags.Report(ND->getASTContext().getFullLoc(ND->getLocation()), - diag::warn_fe_frame_larger_than) - << static_cast(D.getStackSize()) - << static_cast(D.getStackLimit()) - << Decl::castToDeclContext(ND); - return true; - } + auto Loc = getFunctionSourceLocation(D.getFunction()); + if (!Loc) + return false; - return false; + // FIXME: Shouldn't need to truncate to uint32_t + Diags.Report(*Loc, diag::warn_fe_frame_larger_than) + << static_cast(D.getStackSize()) + << static_cast(D.getStackLimit()) + << llvm::demangle(D.getFunction().getName().str()); + return true; } const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc( @@ -606,9 +644,10 @@ const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc( // function definition. We use the definition's right brace to differentiate // from diagnostics that genuinely relate to the function itself. FullSourceLoc Loc(DILoc, SourceMgr); - if (Loc.isInvalid()) - if (const Decl *FD = Gen->GetDeclForMangledName(D.getFunction().getName())) - Loc = FD->getASTContext().getFullLoc(FD->getLocation()); + if (Loc.isInvalid()) { + if (auto MaybeLoc = getFunctionSourceLocation(D.getFunction())) + Loc = *MaybeLoc; + } if (DILoc.isInvalid() && D.isLocationAvailable()) // If we were not able to translate the file:line:col information @@ -621,6 +660,16 @@ const FullSourceLoc BackendConsumer::getBestLocationFromDebugLoc( return Loc; } +Optional +BackendConsumer::getFunctionSourceLocation(const Function &F) const { + auto Hash = llvm::hash_value(F.getName()); + for (const auto &Pair : ManglingFullSourceLocs) { + if (Pair.first == Hash) + return Pair.second; + } + return Optional(); +} + void BackendConsumer::UnsupportedDiagHandler( const llvm::DiagnosticInfoUnsupported &D) { // We only support warnings or errors. @@ -758,6 +807,21 @@ void BackendConsumer::OptimizationFailureHandler( EmitOptimizationMessage(D, diag::warn_fe_backend_optimization_failure); } +void BackendConsumer::DontCallDiagHandler(const DiagnosticInfoDontCall &D) { + SourceLocation LocCookie = + SourceLocation::getFromRawEncoding(D.getLocCookie()); + + // FIXME: we can't yet diagnose indirect calls. When/if we can, we + // should instead assert that LocCookie.isValid(). + if (!LocCookie.isValid()) + return; + + Diags.Report(LocCookie, D.getSeverity() == DiagnosticSeverity::DS_Error + ? diag::err_fe_backend_error_attr + : diag::warn_fe_backend_warning_attr) + << llvm::demangle(D.getFunctionName().str()) << D.getNote(); +} + /// This function is invoked when the backend needs /// to report something to the user. void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { @@ -779,11 +843,7 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { ComputeDiagID(Severity, backend_frame_larger_than, DiagID); break; case DK_Linker: - assert(CurLinkModule); - // FIXME: stop eating the warnings and notes. - if (Severity != DS_Error) - return; - DiagID = diag::err_fe_cannot_link_module; + ComputeDiagID(Severity, linking_module, DiagID); break; case llvm::DK_OptimizationRemark: // Optimization remarks are always handled completely by this @@ -833,6 +893,9 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { case llvm::DK_Unsupported: UnsupportedDiagHandler(cast(DI)); return; + case llvm::DK_DontCall: + DontCallDiagHandler(cast(DI)); + return; default: // Plugin IDs are not bound to any value as they are set dynamically. ComputeDiagRemarkID(Severity, backend_plugin, DiagID); @@ -845,9 +908,9 @@ void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { DI.print(DP); } - if (DiagID == diag::err_fe_cannot_link_module) { - Diags.Report(diag::err_fe_cannot_link_module) - << CurLinkModule->getModuleIdentifier() << MsgStorage; + if (DI.getKind() == DK_Linker) { + assert(CurLinkModule && "CurLinkModule must be set for linker diagnostics"); + Diags.Report(DiagID) << CurLinkModule->getModuleIdentifier() << MsgStorage; return; } @@ -1088,7 +1151,7 @@ void CodeGenAction::ExecuteAction() { // BackendConsumer. BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(), CI.getPreprocessorOpts(), CI.getCodeGenOpts(), - CI.getTargetOpts(), CI.getLangOpts(), + CI.getTargetOpts(), CI.getLangOpts(), TheModule.get(), std::move(LinkModules), *VMContext, nullptr); // PR44896: Force DiscardValueNames as false. DiscardValueNames cannot be // true here because the valued names are needed for reading textual IR. diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index a2384456ea9..d87cf2d4972 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -45,6 +45,7 @@ #include "llvm/Support/CRC.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" + using namespace clang; using namespace CodeGen; @@ -78,7 +79,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) EHStack.setCGF(this); SetFastMathFlags(CurFPFeatures); - SetFPModel(); } CodeGenFunction::~CodeGenFunction() { @@ -109,17 +109,6 @@ clang::ToConstrainedExceptMD(LangOptions::FPExceptionModeKind Kind) { llvm_unreachable("Unsupported FP Exception Behavior"); } -void CodeGenFunction::SetFPModel() { - llvm::RoundingMode RM = getLangOpts().getFPRoundingMode(); - auto fpExceptionBehavior = ToConstrainedExceptMD( - getLangOpts().getFPExceptionMode()); - - Builder.setDefaultConstrainedRounding(RM); - Builder.setDefaultConstrainedExcept(fpExceptionBehavior); - Builder.setIsFPConstrained(fpExceptionBehavior != llvm::fp::ebIgnore || - RM != llvm::RoundingMode::NearestTiesToEven); -} - void CodeGenFunction::SetFastMathFlags(FPOptions FPFeatures) { llvm::FastMathFlags FMF; FMF.setAllowReassoc(FPFeatures.getAllowFPReassociate()); @@ -393,6 +382,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { "__cyg_profile_func_exit"); } + if (ShouldSkipSanitizerInstrumentation()) + CurFn->addFnAttr(llvm::Attribute::DisableSanitizerInstrumentation); + // Emit debug descriptor for function end. if (CGDebugInfo *DI = getDebugInfo()) DI->EmitFunctionEnd(Builder, CurFn); @@ -432,6 +424,14 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { AllocaInsertPt = nullptr; Ptr->eraseFromParent(); + // PostAllocaInsertPt, if created, was lazily created when it was required, + // remove it now since it was just created for our own convenience. + if (PostAllocaInsertPt) { + llvm::Instruction *PostPtr = PostAllocaInsertPt; + PostAllocaInsertPt = nullptr; + PostPtr->eraseFromParent(); + } + // If someone took the address of a label but never did an indirect goto, we // made a zero entry PHI node, which is illegal, zap it now. if (IndirectBranch) { @@ -496,11 +496,13 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { // function. CurFn->addFnAttr("min-legal-vector-width", llvm::utostr(LargestVectorWidth)); - // Add vscale attribute if appropriate. - if (getLangOpts().ArmSveVectorBits) { - unsigned VScale = getLangOpts().ArmSveVectorBits / 128; - CurFn->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs(getLLVMContext(), - VScale, VScale)); + // Add vscale_range attribute if appropriate. + Optional> VScaleRange = + getContext().getTargetInfo().getVScaleRange(getLangOpts()); + if (VScaleRange) { + CurFn->addFnAttr(llvm::Attribute::getWithVScaleRangeArgs( + getLLVMContext(), VScaleRange.getValue().first, + VScaleRange.getValue().second)); } // If we generated an unreachable return block, delete it now. @@ -529,6 +531,12 @@ bool CodeGenFunction::ShouldInstrumentFunction() { return true; } +bool CodeGenFunction::ShouldSkipSanitizerInstrumentation() { + if (!CurFuncDecl) + return false; + return CurFuncDecl->hasAttr(); +} + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool CodeGenFunction::ShouldXRayInstrumentFunction() const { @@ -947,10 +955,16 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, (getLangOpts().CUDA && FD->hasAttr()))) Fn->addFnAttr(llvm::Attribute::NoRecurse); - if (FD) { - Builder.setIsFPConstrained(FD->hasAttr()); - if (FD->hasAttr()) - Fn->addFnAttr(llvm::Attribute::StrictFP); + llvm::RoundingMode RM = getLangOpts().getFPRoundingMode(); + llvm::fp::ExceptionBehavior FPExceptionBehavior = + ToConstrainedExceptMD(getLangOpts().getFPExceptionMode()); + Builder.setDefaultConstrainedRounding(RM); + Builder.setDefaultConstrainedExcept(FPExceptionBehavior); + if ((FD && (FD->UsesFPIntrin() || FD->hasAttr())) || + (!FD && (FPExceptionBehavior != llvm::fp::ebIgnore || + RM != llvm::RoundingMode::NearestTiesToEven))) { + Builder.setIsFPConstrained(true); + Fn->addFnAttr(llvm::Attribute::StrictFP); } // If a custom alignment is used, force realigning to this alignment on @@ -975,7 +989,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // precise source location of the checked return statement. if (requiresReturnValueCheck()) { ReturnLocation = CreateDefaultAlignTempAlloca(Int8PtrTy, "return.sloc.ptr"); - InitTempAlloca(ReturnLocation, llvm::ConstantPointerNull::get(Int8PtrTy)); + Builder.CreateStore(llvm::ConstantPointerNull::get(Int8PtrTy), + ReturnLocation); } // Emit subprogram debug descriptor. @@ -983,16 +998,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // Reconstruct the type from the argument list so that implicit parameters, // such as 'this' and 'vtt', show up in the debug info. Preserve the calling // convention. - CallingConv CC = CallingConv::CC_C; - if (FD) - if (const auto *SrcFnTy = FD->getType()->getAs()) - CC = SrcFnTy->getCallConv(); - SmallVector ArgTypes; - for (const VarDecl *VD : Args) - ArgTypes.push_back(VD->getType()); - QualType FnType = getContext().getFunctionType( - RetTy, ArgTypes, FunctionProtoType::ExtProtoInfo(CC)); - DI->emitFunctionStart(GD, Loc, StartLoc, FnType, CurFn, CurFuncIsThunk); + DI->emitFunctionStart(GD, Loc, StartLoc, + DI->getFunctionType(FD, RetTy, Args), CurFn, + CurFuncIsThunk); } if (ShouldInstrumentFunction()) { @@ -1044,7 +1052,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, Fn->addFnAttr("packed-stack"); } - if (CGM.getCodeGenOpts().WarnStackSize != UINT_MAX) + if (CGM.getCodeGenOpts().WarnStackSize != UINT_MAX && + !CGM.getDiags().isIgnored(diag::warn_fe_backend_frame_larger_than, Loc)) Fn->addFnAttr("warn-stack-size", std::to_string(CGM.getCodeGenOpts().WarnStackSize)); @@ -1295,6 +1304,45 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, FunctionArgList Args; QualType ResTy = BuildFunctionArgList(GD, Args); + // When generating code for a builtin with an inline declaration, use a + // mangled name to hold the actual body, while keeping an external definition + // in case the function pointer is referenced somewhere. + if (Fn) { + if (FD->isInlineBuiltinDeclaration()) { + std::string FDInlineName = (Fn->getName() + ".inline").str(); + llvm::Module *M = Fn->getParent(); + llvm::Function *Clone = M->getFunction(FDInlineName); + if (!Clone) { + Clone = llvm::Function::Create(Fn->getFunctionType(), + llvm::GlobalValue::InternalLinkage, + Fn->getAddressSpace(), FDInlineName, M); + Clone->addFnAttr(llvm::Attribute::AlwaysInline); + } + Fn->setLinkage(llvm::GlobalValue::ExternalLinkage); + Fn = Clone; + } + + // Detect the unusual situation where an inline version is shadowed by a + // non-inline version. In that case we should pick the external one + // everywhere. That's GCC behavior too. Unfortunately, I cannot find a way + // to detect that situation before we reach codegen, so do some late + // replacement. + else { + for (const FunctionDecl *PD = FD->getPreviousDecl(); PD; + PD = PD->getPreviousDecl()) { + if (LLVM_UNLIKELY(PD->isInlineBuiltinDeclaration())) { + std::string FDInlineName = (Fn->getName() + ".inline").str(); + llvm::Module *M = Fn->getParent(); + if (llvm::Function *Clone = M->getFunction(FDInlineName)) { + Clone->replaceAllUsesWith(Fn); + Clone->eraseFromParent(); + } + break; + } + } + } + } + // Check if we should generate debug info for this function. if (FD->hasAttr()) { // Clear non-distinct debug info that was possibly attached to the function @@ -2399,15 +2447,19 @@ Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D, assert(D->hasAttr() && "no annotate attribute"); llvm::Value *V = Addr.getPointer(); llvm::Type *VTy = V->getType(); - llvm::Function *F = CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, - CGM.Int8PtrTy); + auto *PTy = dyn_cast(VTy); + unsigned AS = PTy ? PTy->getAddressSpace() : 0; + llvm::PointerType *IntrinTy = + llvm::PointerType::getWithSamePointeeType(CGM.Int8PtrTy, AS); + llvm::Function *F = + CGM.getIntrinsic(llvm::Intrinsic::ptr_annotation, IntrinTy); for (const auto *I : D->specific_attrs()) { // FIXME Always emit the cast inst so we can differentiate between // annotation on the first field of a struct and annotation on the struct // itself. - if (VTy != CGM.Int8PtrTy) - V = Builder.CreateBitCast(V, CGM.Int8PtrTy); + if (VTy != IntrinTy) + V = Builder.CreateBitCast(V, IntrinTy); V = EmitAnnotationCall(F, V, I->getAnnotation(), D->getLocation(), I); V = Builder.CreateBitCast(V, VTy); } @@ -2478,8 +2530,7 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc, // Return if the builtin doesn't have any required features. if (FeatureList.empty()) return; - assert(FeatureList.find(' ') == StringRef::npos && - "Space in feature list"); + assert(!FeatureList.contains(' ') && "Space in feature list"); TargetFeatures TF(CallerFeatureMap); if (!TF.hasRequiredFeatures(FeatureList)) CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature) diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 4e087ce51e3..ff5b6634da1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -291,6 +291,10 @@ public: /// nest would extend. SmallVector OMPLoopNestStack; + /// Number of nested loop to be consumed by the last surrounding + /// loop-associated directive. + int ExpectedOMPLoopDepth = 0; + // CodeGen lambda for loops and support for ordered clause typedef llvm::function_ref @@ -375,6 +379,34 @@ public: /// we prefer to insert allocas. llvm::AssertingVH AllocaInsertPt; +private: + /// PostAllocaInsertPt - This is a place in the prologue where code can be + /// inserted that will be dominated by all the static allocas. This helps + /// achieve two things: + /// 1. Contiguity of all static allocas (within the prologue) is maintained. + /// 2. All other prologue code (which are dominated by static allocas) do + /// appear in the source order immediately after all static allocas. + /// + /// PostAllocaInsertPt will be lazily created when it is *really* required. + llvm::AssertingVH PostAllocaInsertPt = nullptr; + +public: + /// Return PostAllocaInsertPt. If it is not yet created, then insert it + /// immediately after AllocaInsertPt. + llvm::Instruction *getPostAllocaInsertPoint() { + if (!PostAllocaInsertPt) { + assert(AllocaInsertPt && + "Expected static alloca insertion point at function prologue"); + assert(AllocaInsertPt->getParent()->isEntryBlock() && + "EBB should be entry block of the current code gen function"); + PostAllocaInsertPt = AllocaInsertPt->clone(); + PostAllocaInsertPt->setName("postallocapt"); + PostAllocaInsertPt->insertAfter(AllocaInsertPt); + } + + return PostAllocaInsertPt; + } + /// API for captured statement code generation. class CGCapturedStmtInfo { public: @@ -467,7 +499,7 @@ public: AbstractCallee(const FunctionDecl *FD) : CalleeDecl(FD) {} AbstractCallee(const ObjCMethodDecl *OMD) : CalleeDecl(OMD) {} bool hasFunctionDecl() const { - return dyn_cast_or_null(CalleeDecl); + return isa_and_nonnull(CalleeDecl); } const Decl *getDecl() const { return CalleeDecl; } unsigned getNumParams() const { @@ -1775,6 +1807,24 @@ public: CGF.Builder.CreateBr(&FiniBB); } + static void EmitCaptureStmt(CodeGenFunction &CGF, InsertPointTy CodeGenIP, + llvm::BasicBlock &FiniBB, llvm::Function *Fn, + ArrayRef Args) { + llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); + if (llvm::Instruction *CodeGenIPBBTI = CodeGenIPBB->getTerminator()) + CodeGenIPBBTI->eraseFromParent(); + + CGF.Builder.SetInsertPoint(CodeGenIPBB); + + if (Fn->doesNotThrow()) + CGF.EmitNounwindRuntimeCall(Fn, Args); + else + CGF.EmitRuntimeCall(Fn, Args); + + if (CGF.Builder.saveIP().isSet()) + CGF.Builder.CreateBr(&FiniBB); + } + /// RAII for preserving necessary info during Outlined region body codegen. class OutlinedRegionBodyRAII { @@ -2286,6 +2336,10 @@ public: /// instrumented with __cyg_profile_func_* calls bool ShouldInstrumentFunction(); + /// ShouldSkipSanitizerInstrumentation - Return true if the current function + /// should not be instrumented with sanitizers. + bool ShouldSkipSanitizerInstrumentation(); + /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; @@ -2519,15 +2573,6 @@ public: Address CreateDefaultAlignTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp"); - /// InitTempAlloca - Provide an initial value for the given alloca which - /// will be observable at all locations in the function. - /// - /// The address should be something that was returned from one of - /// the CreateTempAlloca or CreateMemTemp routines, and the - /// initializer must be valid in the entry block (i.e. it must - /// either be a constant or an argument value). - void InitTempAlloca(Address Alloca, llvm::Value *Value); - /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary /// value needs to be stored into an alloca (for example, to avoid explicit @@ -3438,6 +3483,7 @@ public: const RegionCodeGenTy &BodyGen, OMPTargetDataInfo &InputInfo); + void EmitOMPMetaDirective(const OMPMetaDirective &S); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); void EmitOMPTileDirective(const OMPTileDirective &S); @@ -3511,6 +3557,7 @@ public: const OMPTargetTeamsDistributeParallelForSimdDirective &S); void EmitOMPTargetTeamsDistributeSimdDirective( const OMPTargetTeamsDistributeSimdDirective &S); + void EmitOMPGenericLoopDirective(const OMPGenericLoopDirective &S); /// Emit device code for the target directive. static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM, @@ -4051,10 +4098,9 @@ public: RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, ReturnValueSlot ReturnValue); - RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue); - RValue EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E, - ReturnValueSlot ReturnValue); + RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E); + RValue EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E); + RValue EmitOpenMPDevicePrintfCallExpr(const CallExpr *E); RValue EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); @@ -4126,30 +4172,30 @@ public: /// SVEBuiltinMemEltTy - Returns the memory element type for this memory /// access builtin. Only required if it can't be inferred from the base /// pointer operand. - llvm::Type *SVEBuiltinMemEltTy(SVETypeFlags TypeFlags); + llvm::Type *SVEBuiltinMemEltTy(const SVETypeFlags &TypeFlags); - SmallVector getSVEOverloadTypes(SVETypeFlags TypeFlags, - llvm::Type *ReturnType, - ArrayRef Ops); - llvm::Type *getEltType(SVETypeFlags TypeFlags); + SmallVector + getSVEOverloadTypes(const SVETypeFlags &TypeFlags, llvm::Type *ReturnType, + ArrayRef Ops); + llvm::Type *getEltType(const SVETypeFlags &TypeFlags); llvm::ScalableVectorType *getSVEType(const SVETypeFlags &TypeFlags); - llvm::ScalableVectorType *getSVEPredType(SVETypeFlags TypeFlags); - llvm::Value *EmitSVEAllTruePred(SVETypeFlags TypeFlags); + llvm::ScalableVectorType *getSVEPredType(const SVETypeFlags &TypeFlags); + llvm::Value *EmitSVEAllTruePred(const SVETypeFlags &TypeFlags); llvm::Value *EmitSVEDupX(llvm::Value *Scalar); llvm::Value *EmitSVEDupX(llvm::Value *Scalar, llvm::Type *Ty); llvm::Value *EmitSVEReinterpret(llvm::Value *Val, llvm::Type *Ty); - llvm::Value *EmitSVEPMull(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEPMull(const SVETypeFlags &TypeFlags, llvm::SmallVectorImpl &Ops, unsigned BuiltinID); - llvm::Value *EmitSVEMovl(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEMovl(const SVETypeFlags &TypeFlags, llvm::ArrayRef Ops, unsigned BuiltinID); llvm::Value *EmitSVEPredicateCast(llvm::Value *Pred, llvm::ScalableVectorType *VTy); - llvm::Value *EmitSVEGatherLoad(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEGatherLoad(const SVETypeFlags &TypeFlags, llvm::SmallVectorImpl &Ops, unsigned IntID); - llvm::Value *EmitSVEScatterStore(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEScatterStore(const SVETypeFlags &TypeFlags, llvm::SmallVectorImpl &Ops, unsigned IntID); llvm::Value *EmitSVEMaskedLoad(const CallExpr *, llvm::Type *ReturnTy, @@ -4158,15 +4204,16 @@ public: llvm::Value *EmitSVEMaskedStore(const CallExpr *, SmallVectorImpl &Ops, unsigned BuiltinID); - llvm::Value *EmitSVEPrefetchLoad(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEPrefetchLoad(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned BuiltinID); - llvm::Value *EmitSVEGatherPrefetch(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEGatherPrefetch(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID); - llvm::Value *EmitSVEStructLoad(SVETypeFlags TypeFlags, - SmallVectorImpl &Ops, unsigned IntID); - llvm::Value *EmitSVEStructStore(SVETypeFlags TypeFlags, + llvm::Value *EmitSVEStructLoad(const SVETypeFlags &TypeFlags, + SmallVectorImpl &Ops, + unsigned IntID); + llvm::Value *EmitSVEStructStore(const SVETypeFlags &TypeFlags, SmallVectorImpl &Ops, unsigned IntID); llvm::Value *EmitAArch64SVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E); @@ -4588,9 +4635,6 @@ public: /// point operation, expressed as the maximum relative error in ulp. void SetFPAccuracy(llvm::Value *Val, float Accuracy); - /// SetFPModel - Control floating point behavior via fp-model settings. - void SetFPModel(); - /// Set the codegen fast-math flags. void SetFastMathFlags(FPOptions FPFeatures); @@ -4726,8 +4770,6 @@ public: void EmitMultiVersionResolver(llvm::Function *Resolver, ArrayRef Options); - static uint64_t GetX86CpuSupportsMask(ArrayRef FeatureStrs); - private: QualType getVarArgType(const Expr *Arg); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 9b40b88ea3c..59f3e027057 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -19,8 +19,7 @@ #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CGOpenMPRuntime.h" -#include "CGOpenMPRuntimeAMDGCN.h" -#include "CGOpenMPRuntimeNVPTX.h" +#include "CGOpenMPRuntimeGPU.h" #include "CodeGenFunction.h" #include "CodeGenPGO.h" #include "ConstantEmitter.h" @@ -63,6 +62,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" #include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/X86TargetParser.h" using namespace clang; using namespace CodeGen; @@ -130,8 +130,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, C.getTargetInfo().getMaxPointerWidth()); Int8PtrTy = Int8Ty->getPointerTo(0); Int8PtrPtrTy = Int8PtrTy->getPointerTo(0); - AllocaInt8PtrTy = Int8Ty->getPointerTo( - M.getDataLayout().getAllocaAddrSpace()); + const llvm::DataLayout &DL = M.getDataLayout(); + AllocaInt8PtrTy = Int8Ty->getPointerTo(DL.getAllocaAddrSpace()); + GlobalsInt8PtrTy = Int8Ty->getPointerTo(DL.getDefaultGlobalsAddressSpace()); ASTAllocaAddressSpace = getTargetCodeGenInfo().getASTAllocaAddressSpace(); RuntimeCC = getTargetCodeGenInfo().getABIInfo().getRuntimeCC(); @@ -186,7 +187,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, !getModule().getSourceFileName().empty()) { std::string Path = getModule().getSourceFileName(); // Check if a path substitution is needed from the MacroPrefixMap. - for (const auto &Entry : PPO.MacroPrefixMap) + for (const auto &Entry : LangOpts.MacroPrefixMap) if (Path.rfind(Entry.first, 0) != std::string::npos) { Path = Entry.second + Path.substr(Entry.first.size()); break; @@ -242,14 +243,10 @@ void CodeGenModule::createOpenMPRuntime() { switch (getTriple().getArch()) { case llvm::Triple::nvptx: case llvm::Triple::nvptx64: - assert(getLangOpts().OpenMPIsDevice && - "OpenMP NVPTX is only prepared to deal with device code."); - OpenMPRuntime.reset(new CGOpenMPRuntimeNVPTX(*this)); - break; case llvm::Triple::amdgcn: assert(getLangOpts().OpenMPIsDevice && - "OpenMP AMDGCN is only prepared to deal with device code."); - OpenMPRuntime.reset(new CGOpenMPRuntimeAMDGCN(*this)); + "OpenMP AMDGPU/NVPTX is only prepared to deal with device code."); + OpenMPRuntime.reset(new CGOpenMPRuntimeGPU(*this)); break; default: if (LangOpts.OpenMPSimd) @@ -315,22 +312,58 @@ void CodeGenModule::applyGlobalValReplacements() { // This is only used in aliases that we created and we know they have a // linear structure. -static const llvm::GlobalObject *getAliasedGlobal( - const llvm::GlobalIndirectSymbol &GIS) { - llvm::SmallPtrSet Visited; - const llvm::Constant *C = &GIS; - for (;;) { - C = C->stripPointerCasts(); - if (auto *GO = dyn_cast(C)) - return GO; - // stripPointerCasts will not walk over weak aliases. - auto *GIS2 = dyn_cast(C); - if (!GIS2) - return nullptr; - if (!Visited.insert(GIS2).second) - return nullptr; - C = GIS2->getIndirectSymbol(); +static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) { + const llvm::Constant *C; + if (auto *GA = dyn_cast(GV)) + C = GA->getAliasee(); + else if (auto *GI = dyn_cast(GV)) + C = GI->getResolver(); + else + return GV; + + const auto *AliaseeGV = dyn_cast(C->stripPointerCasts()); + if (!AliaseeGV) + return nullptr; + + const llvm::GlobalValue *FinalGV = AliaseeGV->getAliaseeObject(); + if (FinalGV == GV) + return nullptr; + + return FinalGV; +} + +static bool checkAliasedGlobal(DiagnosticsEngine &Diags, + SourceLocation Location, bool IsIFunc, + const llvm::GlobalValue *Alias, + const llvm::GlobalValue *&GV) { + GV = getAliasedGlobal(Alias); + if (!GV) { + Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; + return false; } + + if (GV->isDeclaration()) { + Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc; + return false; + } + + if (IsIFunc) { + // Check resolver function type. + const auto *F = dyn_cast(GV); + if (!F) { + Diags.Report(Location, diag::err_alias_to_undefined) + << IsIFunc << IsIFunc; + return false; + } + + llvm::FunctionType *FTy = F->getFunctionType(); + if (!FTy->getReturnType()->isPointerTy()) { + Diags.Report(Location, diag::err_ifunc_resolver_return); + return false; + } + } + + return true; } void CodeGenModule::checkAliases() { @@ -347,27 +380,19 @@ void CodeGenModule::checkAliases() { Location = A->getLocation(); else llvm_unreachable("Not an alias or ifunc?"); + StringRef MangledName = getMangledName(GD); - llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast(Entry); - const llvm::GlobalValue *GV = getAliasedGlobal(*Alias); - if (!GV) { + llvm::GlobalValue *Alias = GetGlobalValue(MangledName); + const llvm::GlobalValue *GV = nullptr; + if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) { Error = true; - Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; - } else if (GV->isDeclaration()) { - Error = true; - Diags.Report(Location, diag::err_alias_to_undefined) - << IsIFunc << IsIFunc; - } else if (IsIFunc) { - // Check resolver function type. - llvm::FunctionType *FTy = dyn_cast( - GV->getType()->getPointerElementType()); - assert(FTy); - if (!FTy->getReturnType()->isPointerTy()) - Diags.Report(Location, diag::err_ifunc_resolver_return); + continue; } - llvm::Constant *Aliasee = Alias->getIndirectSymbol(); + llvm::Constant *Aliasee = + IsIFunc ? cast(Alias)->getResolver() + : cast(Alias)->getAliasee(); + llvm::GlobalValue *AliaseeGV; if (auto CE = dyn_cast(Aliasee)) AliaseeGV = cast(CE->getOperand(0)); @@ -386,13 +411,17 @@ void CodeGenModule::checkAliases() { // compatibility with gcc we implement it by just pointing the alias // to its aliasee's aliasee. We also warn, since the user is probably // expecting the link to be weak. - if (auto GA = dyn_cast(AliaseeGV)) { + if (auto *GA = dyn_cast(AliaseeGV)) { if (GA->isInterposable()) { Diags.Report(Location, diag::warn_alias_to_weak_alias) << GV->getName() << GA->getName() << IsIFunc; Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - GA->getIndirectSymbol(), Alias->getType()); - Alias->setIndirectSymbol(Aliasee); + GA->getAliasee(), Alias->getType()); + + if (IsIFunc) + cast(Alias)->setResolver(Aliasee); + else + cast(Alias)->setAliasee(Aliasee); } } } @@ -401,8 +430,7 @@ void CodeGenModule::checkAliases() { for (const GlobalDecl &GD : Aliases) { StringRef MangledName = getMangledName(GD); - llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast(Entry); + llvm::GlobalValue *Alias = GetGlobalValue(MangledName); Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType())); Alias->eraseFromParent(); } @@ -537,6 +565,7 @@ void CodeGenModule::Release() { "__amdgpu_device_library_preserve_asan_functions_ptr", nullptr, llvm::GlobalVariable::NotThreadLocal); addCompilerUsedGlobal(Var); + getModule().addModuleFlag(llvm::Module::Override, "amdgpu_hostcall", 1); } emitLLVMUsed(); @@ -731,8 +760,9 @@ void CodeGenModule::Release() { if (getTriple().isSPIR()) { // SPIR v2.0 s2.12 - The SPIR version used by the module is stored in the // opencl.spir.version named metadata. - // C++ is backwards compatible with OpenCL v2.0. - auto Version = LangOpts.OpenCLCPlusPlus ? 200 : LangOpts.OpenCLVersion; + // C++ for OpenCL has a distinct mapping for version compatibility with + // OpenCL. + auto Version = LangOpts.getOpenCLCompatibleVersion(); llvm::Metadata *SPIRVerElts[] = { llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( Int32Ty, Version / 100)), @@ -810,6 +840,8 @@ void CodeGenModule::Release() { getCodeGenOpts().StackProtectorGuardOffset); if (getCodeGenOpts().StackAlignment) getModule().setOverrideStackAlignment(getCodeGenOpts().StackAlignment); + if (getCodeGenOpts().SkipRaxSetup) + getModule().addModuleFlag(llvm::Module::Override, "SkipRaxSetup", 1); getTargetCodeGenInfo().emitTargetMetadata(*this, MangledDeclNames); @@ -825,9 +857,8 @@ void CodeGenModule::Release() { void CodeGenModule::EmitOpenCLMetadata() { // SPIR v2.0 s2.13 - The OpenCL version used by the module is stored in the // opencl.ocl.version named metadata node. - // C++ is backwards compatible with OpenCL v2.0. - // FIXME: We might need to add CXX version at some point too? - auto Version = LangOpts.OpenCLCPlusPlus ? 200 : LangOpts.OpenCLVersion; + // C++ for OpenCL has a distinct mapping for versions compatibile with OpenCL. + auto Version = LangOpts.getOpenCLCompatibleVersion(); llvm::Metadata *OCLVerElts[] = { llvm::ConstantAsMetadata::get(llvm::ConstantInt::get( Int32Ty, Version / 100)), @@ -1781,7 +1812,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, CodeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) B.addAttribute(llvm::Attribute::NoInline); - F->addAttributes(llvm::AttributeList::FunctionIndex, B); + F->addFnAttrs(B); return; } @@ -1868,7 +1899,7 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, B.addAttribute(llvm::Attribute::MinSize); } - F->addAttributes(llvm::AttributeList::FunctionIndex, B); + F->addFnAttrs(B); unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); if (alignment) @@ -1918,13 +1949,13 @@ void CodeGenModule::setLLVMFunctionFEnvAttributes(const FunctionDecl *D, if (D->hasAttr()) { llvm::AttrBuilder FuncAttrs; FuncAttrs.addAttribute("strictfp"); - F->addAttributes(llvm::AttributeList::FunctionIndex, FuncAttrs); + F->addFnAttrs(FuncAttrs); } } void CodeGenModule::SetCommonAttributes(GlobalDecl GD, llvm::GlobalValue *GV) { const Decl *D = GD.getDecl(); - if (dyn_cast_or_null(D)) + if (isa_and_nonnull(D)) setGVProperties(GV, GD); else GV->setVisibility(llvm::GlobalValue::DefaultVisibility); @@ -2034,8 +2065,8 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD, RemoveAttrs.addAttribute("target-cpu"); RemoveAttrs.addAttribute("target-features"); RemoveAttrs.addAttribute("tune-cpu"); - F->removeAttributes(llvm::AttributeList::FunctionIndex, RemoveAttrs); - F->addAttributes(llvm::AttributeList::FunctionIndex, Attrs); + F->removeFnAttrs(RemoveAttrs); + F->addFnAttrs(Attrs); } } @@ -2118,7 +2149,7 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, F->arg_begin()->getType() ->canLosslesslyBitCastTo(F->getReturnType()) && "unexpected this return"); - F->addAttribute(1, llvm::Attribute::Returned); + F->addParamAttr(0, llvm::Attribute::Returned); } // Only a few attributes are set on declarations; these may later be @@ -2136,6 +2167,13 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, else if (const auto *SA = FD->getAttr()) F->setSection(SA->getName()); + if (const auto *EA = FD->getAttr()) { + if (EA->isError()) + F->addFnAttr("dontcall-error", EA->getUserDiagnostic()); + else if (EA->isWarning()) + F->addFnAttr("dontcall-warn", EA->getUserDiagnostic()); + } + // If we plan on emitting this inline builtin, we can't treat it as a builtin. if (FD->isInlineBuiltinDeclaration()) { const FunctionDecl *FDBody; @@ -2144,15 +2182,13 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, assert(HasBody && "Inline builtin declarations should always have an " "available body!"); if (shouldEmitFunction(FDBody)) - F->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoBuiltin); + F->addFnAttr(llvm::Attribute::NoBuiltin); } if (FD->isReplaceableGlobalAllocationFunction()) { // A replaceable global allocation function does not act like a builtin by // default, only if it is invoked by a new-expression or delete-expression. - F->addAttribute(llvm::AttributeList::FunctionIndex, - llvm::Attribute::NoBuiltin); + F->addFnAttr(llvm::Attribute::NoBuiltin); } if (isa(FD) || isa(FD)) @@ -2281,9 +2317,9 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, } // Import this module's dependencies. - for (unsigned I = Mod->Imports.size(); I > 0; --I) { - if (Visited.insert(Mod->Imports[I - 1]).second) - addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited); + for (Module *Import : llvm::reverse(Mod->Imports)) { + if (Visited.insert(Import).second) + addLinkOptionsPostorder(CGM, Import, Metadata, Visited); } // Add linker options to link against the libraries/frameworks @@ -2296,13 +2332,12 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, if (Mod->UseExportAsModuleLinkName) return; - for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) { + for (const Module::LinkLibrary &LL : llvm::reverse(Mod->LinkLibraries)) { // Link against a framework. Frameworks are currently Darwin only, so we // don't to ask TargetCodeGenInfo for the spelling of the linker option. - if (Mod->LinkLibraries[I-1].IsFramework) { - llvm::Metadata *Args[2] = { - llvm::MDString::get(Context, "-framework"), - llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library)}; + if (LL.IsFramework) { + llvm::Metadata *Args[2] = {llvm::MDString::get(Context, "-framework"), + llvm::MDString::get(Context, LL.Library)}; Metadata.push_back(llvm::MDNode::get(Context, Args)); continue; @@ -2312,13 +2347,12 @@ static void addLinkOptionsPostorder(CodeGenModule &CGM, Module *Mod, if (IsELF) { llvm::Metadata *Args[2] = { llvm::MDString::get(Context, "lib"), - llvm::MDString::get(Context, Mod->LinkLibraries[I - 1].Library), + llvm::MDString::get(Context, LL.Library), }; Metadata.push_back(llvm::MDNode::get(Context, Args)); } else { llvm::SmallString<24> Opt; - CGM.getTargetCodeGenInfo().getDependentLibraryOption( - Mod->LinkLibraries[I - 1].Library, Opt); + CGM.getTargetCodeGenInfo().getDependentLibraryOption(LL.Library, Opt); auto *OptString = llvm::MDString::get(Context, Opt); Metadata.push_back(llvm::MDNode::get(Context, OptString)); } @@ -2531,7 +2565,7 @@ llvm::Constant *CodeGenModule::EmitAnnotationLineNo(SourceLocation L) { llvm::Constant *CodeGenModule::EmitAnnotationArgs(const AnnotateAttr *Attr) { ArrayRef Exprs = {Attr->args_begin(), Attr->args_size()}; if (Exprs.empty()) - return llvm::ConstantPointerNull::get(Int8PtrTy); + return llvm::ConstantPointerNull::get(GlobalsInt8PtrTy); llvm::FoldingSetNodeID ID; for (Expr *E : Exprs) { @@ -2555,7 +2589,7 @@ llvm::Constant *CodeGenModule::EmitAnnotationArgs(const AnnotateAttr *Attr) { ".args"); GV->setSection(AnnotationSection); GV->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); - auto *Bitcasted = llvm::ConstantExpr::getBitCast(GV, Int8PtrTy); + auto *Bitcasted = llvm::ConstantExpr::getBitCast(GV, GlobalsInt8PtrTy); Lookup = Bitcasted; return Bitcasted; @@ -2570,17 +2604,19 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, *LineNoCst = EmitAnnotationLineNo(L), *Args = EmitAnnotationArgs(AA); - llvm::Constant *ASZeroGV = GV; - if (GV->getAddressSpace() != 0) { - ASZeroGV = llvm::ConstantExpr::getAddrSpaceCast( - GV, GV->getValueType()->getPointerTo(0)); + llvm::Constant *GVInGlobalsAS = GV; + if (GV->getAddressSpace() != + getDataLayout().getDefaultGlobalsAddressSpace()) { + GVInGlobalsAS = llvm::ConstantExpr::getAddrSpaceCast( + GV, GV->getValueType()->getPointerTo( + getDataLayout().getDefaultGlobalsAddressSpace())); } // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[] = { - llvm::ConstantExpr::getBitCast(ASZeroGV, Int8PtrTy), - llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), - llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(GVInGlobalsAS, GlobalsInt8PtrTy), + llvm::ConstantExpr::getBitCast(AnnoGV, GlobalsInt8PtrTy), + llvm::ConstantExpr::getBitCast(UnitGV, GlobalsInt8PtrTy), LineNoCst, Args, }; @@ -2853,7 +2889,8 @@ ConstantAddress CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { GlobalDecl(cast(VD)), /*ForVTable=*/false); else - Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), DeclTy, 0, nullptr); + Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), DeclTy, LangAS::Default, + nullptr); auto *F = cast(Aliasee); F->setLinkage(llvm::Function::ExternalWeakLinkage); @@ -3163,6 +3200,11 @@ bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) { } } + // Inline builtins declaration must be emitted. They often are fortified + // functions. + if (F->isInlineBuiltinDeclaration()) + return true; + // PR9614. Avoid cases where the source code is lying to us. An available // externally function should have an equivalent function somewhere else, // but a function that calls itself through asm label/`__builtin_` trickery is @@ -3252,6 +3294,19 @@ TargetMVPriority(const TargetInfo &TI, return Priority; } +// Multiversion functions should be at most 'WeakODRLinkage' so that a different +// TU can forward declare the function without causing problems. Particularly +// in the cases of CPUDispatch, this causes issues. This also makes sure we +// work with internal linkage functions, so that the same function name can be +// used with internal linkage in multiple TUs. +llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, + GlobalDecl GD) { + const FunctionDecl *FD = cast(GD.getDecl()); + if (FD->getFormalLinkage() == InternalLinkage) + return llvm::GlobalValue::InternalLinkage; + return llvm::GlobalValue::WeakODRLinkage; +} + void CodeGenModule::emitMultiVersionFunctions() { std::vector MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -3292,7 +3347,7 @@ void CodeGenModule::emitMultiVersionFunctions() { if (TI.supportsIFunc() || FD->isTargetMultiVersion()) { ResolverFunc = cast( GetGlobalValue((getMangledName(GD) + ".resolver").str())); - ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); } else { ResolverFunc = cast(GetGlobalValue(getMangledName(GD))); } @@ -3350,7 +3405,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *ResolverFunc = cast(GetOrCreateLLVMFunction( ResolverName, ResolverType, ResolverGD, /*ForVTable=*/false)); - ResolverFunc->setLinkage(llvm::Function::WeakODRLinkage); + ResolverFunc->setLinkage(getMultiversionLinkage(*this, GD)); if (supportsCOMDAT()) ResolverFunc->setComdat( getModule().getOrInsertComdat(ResolverFunc->getName())); @@ -3386,10 +3441,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { Target.getCPUSpecificCPUDispatchFeatures(II->getName(), Features); llvm::transform(Features, Features.begin(), [](StringRef Str) { return Str.substr(1); }); - Features.erase(std::remove_if( - Features.begin(), Features.end(), [&Target](StringRef Feat) { - return !Target.validateCpuSupports(Feat); - }), Features.end()); + llvm::erase_if(Features, [&Target](StringRef Feat) { + return !Target.validateCpuSupports(Feat); + }); Options.emplace_back(cast(Func), StringRef{}, Features); ++Index; } @@ -3397,8 +3451,8 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { llvm::stable_sort( Options, [](const CodeGenFunction::MultiVersionResolverOption &LHS, const CodeGenFunction::MultiVersionResolverOption &RHS) { - return CodeGenFunction::GetX86CpuSupportsMask(LHS.Conditions.Features) > - CodeGenFunction::GetX86CpuSupportsMask(RHS.Conditions.Features); + return llvm::X86::getCpuSupportsMask(LHS.Conditions.Features) > + llvm::X86::getCpuSupportsMask(RHS.Conditions.Features); }); // If the list contains multiple 'default' versions, such as when it contains @@ -3406,7 +3460,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { // always run on at least a 'pentium'). We do this by deleting the 'least // advanced' (read, lowest mangling letter). while (Options.size() > 1 && - CodeGenFunction::GetX86CpuSupportsMask( + llvm::X86::getCpuSupportsMask( (Options.end() - 2)->Conditions.Features) == 0) { StringRef LHSName = (Options.end() - 2)->Function->getName(); StringRef RHSName = (Options.end() - 1)->Function->getName(); @@ -3427,9 +3481,9 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) { auto *IFunc = cast(GetOrCreateLLVMFunction( AliasName, DeclTy, GD, /*ForVTable=*/false, /*DontDefer=*/true, /*IsThunk=*/false, llvm::AttributeList(), NotForDefinition)); - auto *GA = llvm::GlobalAlias::create( - DeclTy, 0, getFunctionLinkage(GD), AliasName, IFunc, &getModule()); - GA->setLinkage(llvm::Function::WeakODRLinkage); + auto *GA = llvm::GlobalAlias::create(DeclTy, 0, + getMultiversionLinkage(*this, GD), + AliasName, IFunc, &getModule()); SetCommonAttributes(GD, GA); } } @@ -3468,8 +3522,9 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver( llvm::Constant *Resolver = GetOrCreateLLVMFunction( MangledName + ".resolver", ResolverType, GlobalDecl{}, /*ForVTable=*/false); - llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create( - DeclTy, 0, llvm::Function::WeakODRLinkage, "", Resolver, &getModule()); + llvm::GlobalIFunc *GIF = + llvm::GlobalIFunc::create(DeclTy, 0, getMultiversionLinkage(*this, GD), + "", Resolver, &getModule()); GIF->setName(ResolverName); SetCommonAttributes(FD, GIF); @@ -3613,9 +3668,9 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( assert(F->getName() == MangledName && "name was uniqued!"); if (D) SetFunctionAttributes(GD, F, IsIncompleteFunction, IsThunk); - if (ExtraAttrs.hasAttributes(llvm::AttributeList::FunctionIndex)) { + if (ExtraAttrs.hasFnAttrs()) { llvm::AttrBuilder B(ExtraAttrs, llvm::AttributeList::FunctionIndex); - F->addAttributes(llvm::AttributeList::FunctionIndex, B); + F->addFnAttrs(B); } if (!DontDefer) { @@ -3761,8 +3816,7 @@ CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, bool AssumeConvergent) { if (AssumeConvergent) { ExtraAttrs = - ExtraAttrs.addAttribute(VMContext, llvm::AttributeList::FunctionIndex, - llvm::Attribute::Convergent); + ExtraAttrs.addFnAttribute(VMContext, llvm::Attribute::Convergent); } llvm::Constant *C = @@ -3827,10 +3881,11 @@ bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) { /// mangled name but some other type. llvm::Constant * CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, - unsigned AddrSpace, const VarDecl *D, + LangAS AddrSpace, const VarDecl *D, ForDefinition_t IsForDefinition) { // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + unsigned TargetAS = getContext().getTargetAddressSpace(AddrSpace); if (Entry) { if (WeakRefReferences.erase(Entry)) { if (D && !D->hasAttr()) @@ -3844,7 +3899,7 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, if (LangOpts.OpenMP && !LangOpts.OpenMPSimd && D) getOpenMPRuntime().registerTargetGlobalVariable(D, Entry); - if (Entry->getValueType() == Ty && Entry->getAddressSpace() == AddrSpace) + if (Entry->getValueType() == Ty && Entry->getAddressSpace() == TargetAS) return Entry; // If there are two attempts to define the same mangled name, issue an @@ -3868,24 +3923,23 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, } // Make sure the result is of the correct type. - if (Entry->getType()->getAddressSpace() != AddrSpace) { + if (Entry->getType()->getAddressSpace() != TargetAS) { return llvm::ConstantExpr::getAddrSpaceCast(Entry, - Ty->getPointerTo(AddrSpace)); + Ty->getPointerTo(TargetAS)); } // (If global is requested for a definition, we always need to create a new // global, not just return a bitcast.) if (!IsForDefinition) - return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo(AddrSpace)); + return llvm::ConstantExpr::getBitCast(Entry, Ty->getPointerTo(TargetAS)); } auto DAddrSpace = GetGlobalVarAddressSpace(D); - auto TargetAddrSpace = getContext().getTargetAddressSpace(DAddrSpace); auto *GV = new llvm::GlobalVariable( getModule(), Ty, false, llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr, llvm::GlobalVariable::NotThreadLocal, - TargetAddrSpace); + getContext().getTargetAddressSpace(DAddrSpace)); // If we already created a global with the same mangled name (but different // type) before, take its name and remove it from its parent. @@ -4008,10 +4062,10 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, LangAS ExpectedAS = D ? D->getType().getAddressSpace() : (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default); - assert(getContext().getTargetAddressSpace(ExpectedAS) == AddrSpace); + assert(getContext().getTargetAddressSpace(ExpectedAS) == TargetAS); if (DAddrSpace != ExpectedAS) { return getTargetCodeGenInfo().performAddrSpaceCast( - *this, GV, DAddrSpace, ExpectedAS, Ty->getPointerTo(AddrSpace)); + *this, GV, DAddrSpace, ExpectedAS, Ty->getPointerTo(TargetAS)); } return GV; @@ -4101,8 +4155,7 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, Ty = getTypes().ConvertTypeForMem(ASTTy); StringRef MangledName = getMangledName(D); - return GetOrCreateLLVMGlobal(MangledName, Ty, - getContext().getTargetAddressSpace(ASTTy), D, + return GetOrCreateLLVMGlobal(MangledName, Ty, ASTTy.getAddressSpace(), D, IsForDefinition); } @@ -4111,10 +4164,8 @@ llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D, llvm::Constant * CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty, StringRef Name) { - auto AddrSpace = - getContext().getLangOpts().OpenCL - ? getContext().getTargetAddressSpace(LangAS::opencl_global) - : 0; + LangAS AddrSpace = getContext().getLangOpts().OpenCL ? LangAS::opencl_global + : LangAS::Default; auto *Ret = GetOrCreateLLVMGlobal(Name, Ty, AddrSpace, nullptr); setDSOLocal(cast(Ret->stripPointerCasts())); return Ret; @@ -4153,16 +4204,15 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { } LangAS CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { - LangAS AddrSpace = LangAS::Default; if (LangOpts.OpenCL) { - AddrSpace = D ? D->getType().getAddressSpace() : LangAS::opencl_global; - assert(AddrSpace == LangAS::opencl_global || - AddrSpace == LangAS::opencl_global_device || - AddrSpace == LangAS::opencl_global_host || - AddrSpace == LangAS::opencl_constant || - AddrSpace == LangAS::opencl_local || - AddrSpace >= LangAS::FirstTargetAddressSpace); - return AddrSpace; + LangAS AS = D ? D->getType().getAddressSpace() : LangAS::opencl_global; + assert(AS == LangAS::opencl_global || + AS == LangAS::opencl_global_device || + AS == LangAS::opencl_global_host || + AS == LangAS::opencl_constant || + AS == LangAS::opencl_local || + AS >= LangAS::FirstTargetAddressSpace); + return AS; } if (LangOpts.SYCLIsDevice && @@ -4261,11 +4311,6 @@ static bool shouldBeInCOMDAT(CodeGenModule &CGM, const Decl &D) { if (!CGM.supportsCOMDAT()) return false; - // Do not set COMDAT attribute for CUDA/HIP stub functions to prevent - // them being "merged" by the COMDAT Folding linker optimization. - if (D.hasAttr()) - return false; - if (D.hasAttr()) return true; @@ -4438,7 +4483,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (GV && LangOpts.CUDA) { if (LangOpts.CUDAIsDevice) { if (Linkage != llvm::GlobalValue::InternalLinkage && - (D->hasAttr() || D->hasAttr())) + (D->hasAttr() || D->hasAttr() || + D->getType()->isCUDADeviceBuiltinSurfaceType() || + D->getType()->isCUDADeviceBuiltinTextureType())) GV->setExternallyInitialized(true); } else { getCUDARuntime().internalizeDeviceSideVar(D, Linkage); @@ -4529,8 +4576,8 @@ void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) { if (getCodeGenOpts().hasReducedDebugInfo()) { QualType ASTTy = D->getType(); llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType()); - llvm::Constant *GV = GetOrCreateLLVMGlobal( - D->getName(), Ty, getContext().getTargetAddressSpace(ASTTy), D); + llvm::Constant *GV = + GetOrCreateLLVMGlobal(D->getName(), Ty, ASTTy.getAddressSpace(), D); DI->EmitExternalVariable( cast(GV->stripPointerCasts()), D); } @@ -4747,7 +4794,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, } // Add any parameter attributes. - newArgAttrs.push_back(oldAttrs.getParamAttributes(argNo)); + newArgAttrs.push_back(oldAttrs.getParamAttrs(argNo)); argNo++; } if (dontTransform) @@ -4762,7 +4809,7 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, callSite->getOperandBundlesAsDefs(newBundles); llvm::CallBase *newCall; - if (dyn_cast(callSite)) { + if (isa(callSite)) { newCall = llvm::CallInst::Create(newFn, newArgs, newBundles, "", callSite); } else { @@ -4775,9 +4822,9 @@ static void replaceUsesOfNonProtoConstant(llvm::Constant *old, if (!newCall->getType()->isVoidTy()) newCall->takeName(callSite); - newCall->setAttributes(llvm::AttributeList::get( - newFn->getContext(), oldAttrs.getFnAttributes(), - oldAttrs.getRetAttributes(), newArgAttrs)); + newCall->setAttributes( + llvm::AttributeList::get(newFn->getContext(), oldAttrs.getFnAttrs(), + oldAttrs.getRetAttrs(), newArgAttrs)); newCall->setCallingConv(callSite->getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. @@ -4902,7 +4949,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { /*ForVTable=*/false); LT = getFunctionLinkage(GD); } else { - Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), DeclTy, 0, + Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), DeclTy, LangAS::Default, /*D=*/nullptr); if (const auto *VD = dyn_cast(GD.getDecl())) LT = getLLVMLinkageVarDefinition(VD, D->getType().isConstQualified()); @@ -4983,8 +5030,9 @@ void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) { Aliases.push_back(GD); llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + llvm::Type *ResolverTy = llvm::GlobalIFunc::getResolverFunctionType(DeclTy); llvm::Constant *Resolver = - GetOrCreateLLVMFunction(IFA->getResolver(), DeclTy, GD, + GetOrCreateLLVMFunction(IFA->getResolver(), ResolverTy, {}, /*ForVTable=*/false); llvm::GlobalIFunc *GIF = llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage, @@ -5360,7 +5408,7 @@ CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S, if (!LangOpts.WritableStrings) { Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { - if (Alignment.getQuantity() > GV->getAlignment()) + if (uint64_t(Alignment.getQuantity()) > GV->getAlignment()) GV->setAlignment(Alignment.getAsAlign()); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), Alignment); @@ -5423,7 +5471,7 @@ ConstantAddress CodeGenModule::GetAddrOfConstantCString( if (!LangOpts.WritableStrings) { Entry = &ConstantStringMap[C]; if (auto GV = *Entry) { - if (Alignment.getQuantity() > GV->getAlignment()) + if (uint64_t(Alignment.getQuantity()) > GV->getAlignment()) GV->setAlignment(Alignment.getAsAlign()); return ConstantAddress(castStringLiteralToDefaultAddressSpace(*this, GV), Alignment); @@ -6448,5 +6496,5 @@ bool CodeGenModule::stopAutoInit() { void CodeGenModule::printPostfixForExternalizedStaticVar( llvm::raw_ostream &OS) const { - OS << ".static." << getContext().getCUIDHash(); + OS << "__static__" << getContext().getCUIDHash(); } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 47dc6f415b6..fbed22376c8 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1478,8 +1478,8 @@ private: void UpdateMultiVersionNames(GlobalDecl GD, const FunctionDecl *FD); llvm::Constant * - GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, - unsigned AddrSpace, const VarDecl *D, + GetOrCreateLLVMGlobal(StringRef MangledName, llvm::Type *Ty, LangAS AddrSpace, + const VarDecl *D, ForDefinition_t IsForDefinition = NotForDefinition); bool GetCPUAndFeaturesAttributes(GlobalDecl GD, diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index d828ac0eb5e..ab953c2c7d5 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -649,6 +649,14 @@ struct ComputeRegionCounts : public ConstStmtVisitor { void VisitIfStmt(const IfStmt *S) { RecordStmtCount(S); + + if (S->isConsteval()) { + const Stmt *Stm = S->isNegatedConsteval() ? S->getThen() : S->getElse(); + if (Stm) + Visit(Stm); + return; + } + uint64_t ParentCount = CurrentCount; if (S->getInit()) Visit(S->getInit()); diff --git a/clang/lib/CodeGen/CodeGenTypeCache.h b/clang/lib/CodeGen/CodeGenTypeCache.h index f258234fb4d..577f88367a3 100644 --- a/clang/lib/CodeGen/CodeGenTypeCache.h +++ b/clang/lib/CodeGen/CodeGenTypeCache.h @@ -69,6 +69,12 @@ struct CodeGenTypeCache { llvm::PointerType *AllocaInt8PtrTy; }; + /// void* in default globals address space + union { + llvm::PointerType *GlobalsVoidPtrTy; + llvm::PointerType *GlobalsInt8PtrTy; + }; + /// The size and alignment of the builtin C type 'int'. This comes /// up enough in various ABI lowering tasks to be worth pre-computing. union { diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 9cb42941cb9..fb05475a4e8 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -512,6 +512,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { case BuiltinType::Double: case BuiltinType::LongDouble: case BuiltinType::Float128: + case BuiltinType::Ibm128: ResultType = getTypeForFormat(getLLVMContext(), Context.getFloatTypeSemantics(T), /* UseNativeHalf = */ false); diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index 8a11da600e4..9b81c8a670f 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -751,13 +751,11 @@ struct CounterCoverageMappingBuilder /// is already added to \c SourceRegions. bool isRegionAlreadyAdded(SourceLocation StartLoc, SourceLocation EndLoc, bool isBranch = false) { - return SourceRegions.rend() != - std::find_if(SourceRegions.rbegin(), SourceRegions.rend(), - [&](const SourceMappingRegion &Region) { - return Region.getBeginLoc() == StartLoc && - Region.getEndLoc() == EndLoc && - Region.isBranch() == isBranch; - }); + return llvm::any_of( + llvm::reverse(SourceRegions), [&](const SourceMappingRegion &Region) { + return Region.getBeginLoc() == StartLoc && + Region.getEndLoc() == EndLoc && Region.isBranch() == isBranch; + }); } /// Adjust the most recently visited location to \c EndLoc. @@ -971,7 +969,7 @@ struct CounterCoverageMappingBuilder // If last statement contains terminate statements, add a gap area // between the two statements. Skipping attributed statements, because // they don't have valid start location. - if (LastStmt && HasTerminateStmt && !dyn_cast(Child)) { + if (LastStmt && HasTerminateStmt && !isa(Child)) { auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child)); if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index d3dc0e6212b..04163aeaddc 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -334,6 +334,19 @@ public: ArrayRef CXXThreadLocalInits, ArrayRef CXXThreadLocalInitVars) override; + bool mayNeedDestruction(const VarDecl *VD) const { + if (VD->needsDestruction(getContext())) + return true; + + // If the variable has an incomplete class type (or array thereof), it + // might need destruction. + const Type *T = VD->getType()->getBaseElementTypeUnsafe(); + if (T->getAs() && T->isIncompleteType()) + return true; + + return false; + } + /// Determine whether we will definitely emit this variable with a constant /// initializer, either because the language semantics demand it or because /// we know that the initializer is a constant. @@ -364,7 +377,7 @@ public: // If we have the only definition, we don't need a thread wrapper if we // will emit the value as a constant. if (isUniqueGVALinkage(getContext().GetGVALinkageForVariable(VD))) - return !VD->needsDestruction(getContext()) && InitDecl->evaluateValue(); + return !mayNeedDestruction(VD) && InitDecl->evaluateValue(); // Otherwise, we need a thread wrapper unless we know that every // translation unit will emit the value as a constant. We rely on the @@ -376,7 +389,7 @@ public: bool usesThreadWrapperFunction(const VarDecl *VD) const override { return !isEmittedWithConstantInitializer(VD) || - VD->needsDestruction(getContext()); + mayNeedDestruction(VD); } LValue EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, const VarDecl *VD, QualType LValType) override; @@ -2445,11 +2458,6 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, (CGM.getTarget().getTriple().isOSBinFormatELF() || CGM.getTarget().getTriple().isOSBinFormatWasm())) { guard->setComdat(C); - // An inline variable's guard function is run from the per-TU - // initialization function, not via a dedicated global ctor function, so - // we can't put it in a comdat. - if (!NonTemplateInline) - CGF.CurFn->setComdat(C); } else if (CGM.supportsCOMDAT() && guard->isWeakForLinker()) { guard->setComdat(CGM.getModule().getOrInsertComdat(guard->getName())); } @@ -2968,7 +2976,7 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( // also when the symbol is weak. if (CGM.getTriple().isOSAIX() && VD->hasDefinition() && isEmittedWithConstantInitializer(VD, true) && - !VD->needsDestruction(getContext())) { + !mayNeedDestruction(VD)) { // Init should be null. If it were non-null, then the logic above would // either be defining the function to be an alias or declaring the // function with the expectation that the definition of the variable @@ -3274,6 +3282,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { case BuiltinType::LongDouble: case BuiltinType::Float16: case BuiltinType::Float128: + case BuiltinType::Ibm128: case BuiltinType::Char8: case BuiltinType::Char16: case BuiltinType::Char32: diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 990648b131f..0fd5a0ffe06 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -847,7 +847,7 @@ MicrosoftCXXABI::getRecordArgABI(const CXXRecordDecl *RD) const { // arguments was not supported and resulted in a compiler error. In 19.14 // and later versions, such arguments are now passed indirectly. TypeInfo Info = getContext().getTypeInfo(RD->getTypeForDecl()); - if (Info.AlignIsRequired && Info.Align > 4) + if (Info.isAlignRequired() && Info.Align > 4) return RAA_Indirect; // If C++ prohibits us from making a copy, construct the arguments directly @@ -1810,8 +1810,8 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, #endif } - const std::unique_ptr *VFPtrI = std::find_if( - VFPtrs.begin(), VFPtrs.end(), [&](const std::unique_ptr& VPI) { + const std::unique_ptr *VFPtrI = + llvm::find_if(VFPtrs, [&](const std::unique_ptr &VPI) { return VPI->FullOffsetInMDC == VPtrOffset; }); if (VFPtrI == VFPtrs.end()) { @@ -1844,7 +1844,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, VFTablesMap[ID] = VFTable; VTable = VTableAliasIsRequred ? cast( - cast(VFTable)->getBaseObject()) + cast(VFTable)->getAliaseeObject()) : cast(VFTable); return VTable; } @@ -4348,6 +4348,7 @@ llvm::GlobalVariable *MicrosoftCXXABI::getThrowInfo(QualType T) { void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { const Expr *SubExpr = E->getSubExpr(); + assert(SubExpr && "SubExpr cannot be null"); QualType ThrowType = SubExpr->getType(); // The exception object lives on the stack and it's address is passed to the // runtime function. diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index b63f756ca28..f6642a79e1e 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -122,6 +122,10 @@ namespace { return D; } + llvm::StringRef GetMangledName(GlobalDecl GD) { + return Builder->getMangledName(GD); + } + llvm::Constant *GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) { return Builder->GetAddrOfGlobal(global, ForDefinition_t(isForDefinition)); } @@ -325,6 +329,10 @@ const Decl *CodeGenerator::GetDeclForMangledName(llvm::StringRef name) { return static_cast(this)->GetDeclForMangledName(name); } +llvm::StringRef CodeGenerator::GetMangledName(GlobalDecl GD) { + return static_cast(this)->GetMangledName(GD); +} + llvm::Constant *CodeGenerator::GetAddrOfGlobal(GlobalDecl global, bool isForDefinition) { return static_cast(this) diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp index 1adf0ad9c0e..f7b83c45022 100644 --- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -27,10 +27,10 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Object/COFF.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Path.h" -#include "llvm/Support/TargetRegistry.h" #include #include @@ -264,31 +264,48 @@ public: std::string Error; auto Triple = Ctx.getTargetInfo().getTriple(); if (!llvm::TargetRegistry::lookupTarget(Triple.getTriple(), Error)) - llvm::report_fatal_error(Error); + llvm::report_fatal_error(llvm::Twine(Error)); // Emit the serialized Clang AST into its own section. assert(Buffer->IsComplete && "serialization did not complete"); auto &SerializedAST = Buffer->Data; auto Size = SerializedAST.size(); - auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); - auto *Ty = llvm::ArrayType::get(Int8Ty, Size); - auto *Data = llvm::ConstantDataArray::getString( - *VMContext, StringRef(SerializedAST.data(), Size), - /*AddNull=*/false); - auto *ASTSym = new llvm::GlobalVariable( - *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, Data, - "__clang_ast"); - // The on-disk hashtable needs to be aligned. - ASTSym->setAlignment(llvm::Align(8)); - // Mach-O also needs a segment name. - if (Triple.isOSBinFormatMachO()) - ASTSym->setSection("__CLANG,__clangast"); - // COFF has an eight character length limit. - else if (Triple.isOSBinFormatCOFF()) - ASTSym->setSection("clangast"); - else - ASTSym->setSection("__clangast"); + if (Triple.isOSBinFormatWasm()) { + // Emit __clangast in custom section instead of named data segment + // to find it while iterating sections. + // This could be avoided if all data segements (the wasm sense) were + // represented as their own sections (in the llvm sense). + // TODO: https://github.com/WebAssembly/tool-conventions/issues/138 + llvm::NamedMDNode *MD = + M->getOrInsertNamedMetadata("wasm.custom_sections"); + llvm::Metadata *Ops[2] = { + llvm::MDString::get(*VMContext, "__clangast"), + llvm::MDString::get(*VMContext, + StringRef(SerializedAST.data(), Size))}; + auto *NameAndContent = llvm::MDTuple::get(*VMContext, Ops); + MD->addOperand(NameAndContent); + } else { + auto Int8Ty = llvm::Type::getInt8Ty(*VMContext); + auto *Ty = llvm::ArrayType::get(Int8Ty, Size); + auto *Data = llvm::ConstantDataArray::getString( + *VMContext, StringRef(SerializedAST.data(), Size), + /*AddNull=*/false); + auto *ASTSym = new llvm::GlobalVariable( + *M, Ty, /*constant*/ true, llvm::GlobalVariable::InternalLinkage, + Data, "__clang_ast"); + // The on-disk hashtable needs to be aligned. + ASTSym->setAlignment(llvm::Align(8)); + + // Mach-O also needs a segment name. + if (Triple.isOSBinFormatMachO()) + ASTSym->setSection("__CLANG,__clangast"); + // COFF has an eight character length limit. + else if (Triple.isOSBinFormatCOFF()) + ASTSym->setSection("clangast"); + else + ASTSym->setSection("__clangast"); + } LLVM_DEBUG({ // Print the IR for the PCH container to the debug output. diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index a2b68a04d35..302dc653c46 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -392,6 +392,36 @@ static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, } +static Address complexTempStructure(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty, CharUnits SlotSize, + CharUnits EltSize, const ComplexType *CTy) { + Address Addr = + emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, SlotSize * 2, + SlotSize, SlotSize, /*AllowHigher*/ true); + + Address RealAddr = Addr; + Address ImagAddr = RealAddr; + if (CGF.CGM.getDataLayout().isBigEndian()) { + RealAddr = + CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize - EltSize); + ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr, + 2 * SlotSize - EltSize); + } else { + ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize); + } + + llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType()); + RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy); + ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy); + llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal"); + llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag"); + + Address Temp = CGF.CreateMemTemp(Ty, "vacplx"); + CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty), + /*init*/ true); + return Temp; +} + static Address emitMergePHI(CodeGenFunction &CGF, Address Addr1, llvm::BasicBlock *Block1, Address Addr2, llvm::BasicBlock *Block2, @@ -827,19 +857,19 @@ public: llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-import-module", Attr->getImportModule()); - Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-import-name", Attr->getImportName()); - Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + Fn->addFnAttrs(B); } if (const auto *Attr = FD->getAttr()) { llvm::Function *Fn = cast(GV); llvm::AttrBuilder B; B.addAttribute("wasm-export-name", Attr->getExportName()); - Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + Fn->addFnAttrs(B); } } @@ -1170,7 +1200,8 @@ public: IsRetSmallStructInRegABI(RetSmallStructInRegABI), IsWin32StructABI(Win32StructABI), IsSoftFloatABI(SoftFloatABI), IsMCUABI(CGT.getTarget().getTriple().isOSIAMCU()), - IsLinuxABI(CGT.getTarget().getTriple().isOSLinux()), + IsLinuxABI(CGT.getTarget().getTriple().isOSLinux() || + CGT.getTarget().getTriple().isOSCygMing()), DefaultNumRegisterParameters(NumRegisterParameters) {} bool shouldPassIndirectlyForSwift(ArrayRef scalars, @@ -1524,6 +1555,14 @@ ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy, if (isEmptyRecord(getContext(), RetTy, true)) return ABIArgInfo::getIgnore(); + // Return complex of _Float16 as <2 x half> so the backend will use xmm0. + if (const ComplexType *CT = RetTy->getAs()) { + QualType ET = getContext().getCanonicalType(CT->getElementType()); + if (ET->isFloat16Type()) + return ABIArgInfo::getDirect(llvm::FixedVectorType::get( + llvm::Type::getHalfTy(getVMContext()), 2)); + } + // Small structures which are register sized are generally returned // in a register. if (shouldReturnTypeInRegister(RetTy, getContext())) { @@ -1831,7 +1870,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // Pass over-aligned aggregates on Windows indirectly. This behavior was // added in MSVC 2015. - if (IsWin32StructABI && TI.AlignIsRequired && TI.Align > 32) + if (IsWin32StructABI && TI.isAlignRequired() && TI.Align > 32) return getIndirectResult(Ty, /*ByVal=*/false, State); // Expand small (<= 128-bit) record types when we know that the stack layout @@ -2607,7 +2646,7 @@ static std::string qualifyWindowsLibrary(llvm::StringRef Lib) { // If the argument does not end in .lib, automatically add the suffix. // If the argument contains a space, enclose it in quotes. // This matches the behavior of MSVC. - bool Quote = (Lib.find(' ') != StringRef::npos); + bool Quote = Lib.contains(' '); std::string ArgStr = Quote ? "\"" : ""; ArgStr += Lib; if (!Lib.endswith_insensitive(".lib") && !Lib.endswith_insensitive(".a")) @@ -2812,7 +2851,8 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Hi = Integer; } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { Current = Integer; - } else if (k == BuiltinType::Float || k == BuiltinType::Double) { + } else if (k == BuiltinType::Float || k == BuiltinType::Double || + k == BuiltinType::Float16) { Current = SSE; } else if (k == BuiltinType::LongDouble) { const llvm::fltSemantics *LDF = &getTarget().getLongDoubleFormat(); @@ -2943,7 +2983,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Current = Integer; else if (Size <= 128) Lo = Hi = Integer; - } else if (ET == getContext().FloatTy) { + } else if (ET->isFloat16Type() || ET == getContext().FloatTy) { Current = SSE; } else if (ET == getContext().DoubleTy) { Lo = Hi = SSE; @@ -3367,55 +3407,77 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, return false; } -/// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a -/// float member at the specified offset. For example, {int,{float}} has a -/// float at offset 4. It is conservatively correct for this routine to return -/// false. -static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, - const llvm::DataLayout &TD) { - // Base case if we find a float. - if (IROffset == 0 && IRType->isFloatTy()) - return true; +/// getFPTypeAtOffset - Return a floating point type at the specified offset. +static llvm::Type *getFPTypeAtOffset(llvm::Type *IRType, unsigned IROffset, + const llvm::DataLayout &TD) { + if (IROffset == 0 && IRType->isFloatingPointTy()) + return IRType; // If this is a struct, recurse into the field at the specified offset. if (llvm::StructType *STy = dyn_cast(IRType)) { + if (!STy->getNumContainedTypes()) + return nullptr; + const llvm::StructLayout *SL = TD.getStructLayout(STy); unsigned Elt = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(Elt); - return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD); + return getFPTypeAtOffset(STy->getElementType(Elt), IROffset, TD); } // If this is an array, recurse into the field at the specified offset. if (llvm::ArrayType *ATy = dyn_cast(IRType)) { llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = TD.getTypeAllocSize(EltTy); - IROffset -= IROffset/EltSize*EltSize; - return ContainsFloatAtOffset(EltTy, IROffset, TD); + IROffset -= IROffset / EltSize * EltSize; + return getFPTypeAtOffset(EltTy, IROffset, TD); } - return false; + return nullptr; } - /// GetSSETypeAtOffset - Return a type that will be passed by the backend in the /// low 8 bytes of an XMM register, corresponding to the SSE class. llvm::Type *X86_64ABIInfo:: GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { - // The only three choices we have are either double, <2 x float>, or float. We - // pass as float if the last 4 bytes is just padding. This happens for - // structs that contain 3 floats. - if (BitsContainNoUserData(SourceTy, SourceOffset*8+32, - SourceOffset*8+64, getContext())) - return llvm::Type::getFloatTy(getVMContext()); + const llvm::DataLayout &TD = getDataLayout(); + unsigned SourceSize = + (unsigned)getContext().getTypeSize(SourceTy) / 8 - SourceOffset; + llvm::Type *T0 = getFPTypeAtOffset(IRType, IROffset, TD); + if (!T0 || T0->isDoubleTy()) + return llvm::Type::getDoubleTy(getVMContext()); - // We want to pass as <2 x float> if the LLVM IR type contains a float at - // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the - // case. - if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) && - ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout())) - return llvm::FixedVectorType::get(llvm::Type::getFloatTy(getVMContext()), - 2); + // Get the adjacent FP type. + llvm::Type *T1 = nullptr; + unsigned T0Size = TD.getTypeAllocSize(T0); + if (SourceSize > T0Size) + T1 = getFPTypeAtOffset(IRType, IROffset + T0Size, TD); + if (T1 == nullptr) { + // Check if IRType is a half + float. float type will be in IROffset+4 due + // to its alignment. + if (T0->isHalfTy() && SourceSize > 4) + T1 = getFPTypeAtOffset(IRType, IROffset + 4, TD); + // If we can't get a second FP type, return a simple half or float. + // avx512fp16-abi.c:pr51813_2 shows it works to return float for + // {float, i8} too. + if (T1 == nullptr) + return T0; + } + + if (T0->isFloatTy() && T1->isFloatTy()) + return llvm::FixedVectorType::get(T0, 2); + + if (T0->isHalfTy() && T1->isHalfTy()) { + llvm::Type *T2 = nullptr; + if (SourceSize > 4) + T2 = getFPTypeAtOffset(IRType, IROffset + 4, TD); + if (T2 == nullptr) + return llvm::FixedVectorType::get(T0, 2); + return llvm::FixedVectorType::get(T0, 4); + } + + if (T0->isHalfTy() || T1->isHalfTy()) + return llvm::FixedVectorType::get(llvm::Type::getHalfTy(getVMContext()), 4); return llvm::Type::getDoubleTy(getVMContext()); } @@ -3521,11 +3583,11 @@ GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, // struct. if (HiStart != 8) { // There are usually two sorts of types the ABI generation code can produce - // for the low part of a pair that aren't 8 bytes in size: float or + // for the low part of a pair that aren't 8 bytes in size: half, float or // i8/i16/i32. This can also include pointers when they are 32-bit (X32 and // NaCl). // Promote these to a larger type. - if (Lo->isFloatTy()) + if (Lo->isHalfTy() || Lo->isFloatTy()) Lo = llvm::Type::getDoubleTy(Lo->getContext()); else { assert((Lo->isIntegerTy() || Lo->isPointerTy()) @@ -4572,14 +4634,25 @@ CharUnits AIXABIInfo::getParamTypeAlignment(QualType Ty) const { Address AIXABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty) const { - if (Ty->isAnyComplexType()) - llvm::report_fatal_error("complex type is not supported on AIX yet"); auto TypeInfo = getContext().getTypeInfoInChars(Ty); TypeInfo.Align = getParamTypeAlignment(Ty); CharUnits SlotSize = CharUnits::fromQuantity(PtrByteSize); + // If we have a complex type and the base type is smaller than the register + // size, the ABI calls for the real and imaginary parts to be right-adjusted + // in separate words in 32bit mode or doublewords in 64bit mode. However, + // Clang expects us to produce a pointer to a structure with the two parts + // packed tightly. So generate loads of the real and imaginary parts relative + // to the va_list pointer, and store them to a temporary structure. We do the + // same as the PPC64ABI here. + if (const ComplexType *CTy = Ty->getAs()) { + CharUnits EltSize = TypeInfo.Width / 2; + if (EltSize < SlotSize) + return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy); + } + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*Indirect*/ false, TypeInfo, SlotSize, /*AllowHigher*/ true); } @@ -5168,8 +5241,9 @@ bool PPC64_SVR4_ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { if (BT->getKind() == BuiltinType::Float || BT->getKind() == BuiltinType::Double || BT->getKind() == BuiltinType::LongDouble || + BT->getKind() == BuiltinType::Ibm128 || (getContext().getTargetInfo().hasFloat128Type() && - (BT->getKind() == BuiltinType::Float128))) { + (BT->getKind() == BuiltinType::Float128))) { if (IsSoftFloatABI) return false; return true; @@ -5346,33 +5420,8 @@ Address PPC64_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // and store them to a temporary structure. if (const ComplexType *CTy = Ty->getAs()) { CharUnits EltSize = TypeInfo.Width / 2; - if (EltSize < SlotSize) { - Address Addr = emitVoidPtrDirectVAArg(CGF, VAListAddr, CGF.Int8Ty, - SlotSize * 2, SlotSize, - SlotSize, /*AllowHigher*/ true); - - Address RealAddr = Addr; - Address ImagAddr = RealAddr; - if (CGF.CGM.getDataLayout().isBigEndian()) { - RealAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, - SlotSize - EltSize); - ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(ImagAddr, - 2 * SlotSize - EltSize); - } else { - ImagAddr = CGF.Builder.CreateConstInBoundsByteGEP(RealAddr, SlotSize); - } - - llvm::Type *EltTy = CGF.ConvertTypeForMem(CTy->getElementType()); - RealAddr = CGF.Builder.CreateElementBitCast(RealAddr, EltTy); - ImagAddr = CGF.Builder.CreateElementBitCast(ImagAddr, EltTy); - llvm::Value *Real = CGF.Builder.CreateLoad(RealAddr, ".vareal"); - llvm::Value *Imag = CGF.Builder.CreateLoad(ImagAddr, ".vaimag"); - - Address Temp = CGF.CreateMemTemp(Ty, "vacplx"); - CGF.EmitStoreOfComplex({Real, Imag}, CGF.MakeAddrLValue(Temp, Ty), - /*init*/ true); - return Temp; - } + if (EltSize < SlotSize) + return complexTempStructure(CGF, VAListAddr, Ty, SlotSize, EltSize, CTy); } // Otherwise, just use the general rule. @@ -5526,6 +5575,20 @@ public: Fn->addFnAttr("branch-target-enforcement", BPI.BranchTargetEnforcement ? "true" : "false"); } + + bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF, + llvm::Type *Ty) const override { + if (CGF.getTarget().hasFeature("ls64")) { + auto *ST = dyn_cast(Ty); + if (ST && ST->getNumElements() == 1) { + auto *AT = dyn_cast(ST->getElementType(0)); + if (AT && AT->getNumElements() == 8 && + AT->getElementType()->isIntegerTy(64)) + return true; + } + } + return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty); + } }; class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { @@ -6329,7 +6392,7 @@ public: // the backend to perform a realignment as part of the function prologue. llvm::AttrBuilder B; B.addStackAlignmentAttr(8); - Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + Fn->addFnAttrs(B); } }; @@ -6920,7 +6983,7 @@ Address ARMABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, TyAlignForABI = CharUnits::fromQuantity(4); } - TypeInfoChars TyInfo(TySize, TyAlignForABI, false); + TypeInfoChars TyInfo(TySize, TyAlignForABI, AlignRequirementKind::None); return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, /*AllowHigherAlign*/ true); } @@ -10106,24 +10169,26 @@ void XCoreTargetCodeGenInfo::emitTargetMetadata( } } } + //===----------------------------------------------------------------------===// -// SPIR ABI Implementation +// Base ABI and target codegen info implementation common between SPIR and +// SPIR-V. //===----------------------------------------------------------------------===// namespace { -class SPIRABIInfo : public DefaultABIInfo { +class CommonSPIRABIInfo : public DefaultABIInfo { public: - SPIRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) { setCCs(); } + CommonSPIRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) { setCCs(); } private: void setCCs(); }; } // end anonymous namespace namespace { -class SPIRTargetCodeGenInfo : public TargetCodeGenInfo { +class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { public: - SPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) - : TargetCodeGenInfo(std::make_unique(CGT)) {} + CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} LangAS getASTAllocaAddressSpace() const override { return getLangASFromTargetAS( @@ -10134,7 +10199,7 @@ public: }; } // End anonymous namespace. -void SPIRABIInfo::setCCs() { +void CommonSPIRABIInfo::setCCs() { assert(getRuntimeCC() == llvm::CallingConv::C); RuntimeCC = llvm::CallingConv::SPIR_FUNC; } @@ -10148,7 +10213,7 @@ void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { } } -unsigned SPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { +unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { return llvm::CallingConv::SPIR_KERNEL; } @@ -11217,7 +11282,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return SetCGInfo(new ARCTargetCodeGenInfo(Types)); case llvm::Triple::spir: case llvm::Triple::spir64: - return SetCGInfo(new SPIRTargetCodeGenInfo(Types)); + case llvm::Triple::spirv32: + case llvm::Triple::spirv64: + return SetCGInfo(new CommonSPIRTargetCodeGenInfo(Types)); case llvm::Triple::ve: return SetCGInfo(new VETargetCodeGenInfo(Types)); } diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index e6e474544fc..aa8bbb60a75 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -148,6 +148,13 @@ public: return Ty; } + /// Target hook to decide whether an inline asm operand can be passed + /// by value. + virtual bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF, + llvm::Type *Ty) const { + return false; + } + /// Adds constraints and types for result registers. virtual void addReturnRegisterOutputs( CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue, diff --git a/clang/lib/CodeGen/VarBypassDetector.h b/clang/lib/CodeGen/VarBypassDetector.h index b654eefd963..164e88c0b2f 100644 --- a/clang/lib/CodeGen/VarBypassDetector.h +++ b/clang/lib/CodeGen/VarBypassDetector.h @@ -55,7 +55,7 @@ public: /// Returns true if the variable declaration was by bypassed by any goto or /// switch statement. bool IsBypassed(const VarDecl *D) const { - return AlwaysBypassed || Bypasses.find(D) != Bypasses.end(); + return AlwaysBypassed || Bypasses.contains(D); } private: diff --git a/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp b/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp index 1f040f60ff1..110d402436e 100644 --- a/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp +++ b/clang/lib/DirectoryWatcher/windows/DirectoryWatcher-windows.cpp @@ -88,10 +88,15 @@ DirectoryWatcherWindows::DirectoryWatcherWindows( // handle to the watcher and performing synchronous operations. { DWORD Size = GetFinalPathNameByHandleW(DirectoryHandle, NULL, 0, 0); - std::unique_ptr Buffer{new WCHAR[Size]}; + std::unique_ptr Buffer{new WCHAR[Size + 1]}; Size = GetFinalPathNameByHandleW(DirectoryHandle, Buffer.get(), Size, 0); Buffer[Size] = L'\0'; - llvm::sys::windows::UTF16ToUTF8(Buffer.get(), Size, Path); + WCHAR *Data = Buffer.get(); + if (Size >= 4 && ::memcmp(Data, L"\\\\?\\", 8) == 0) { + Data += 4; + Size -= 4; + } + llvm::sys::windows::UTF16ToUTF8(Data, Size, Path); } size_t EntrySize = sizeof(FILE_NOTIFY_INFORMATION) + MAX_PATH * sizeof(WCHAR); diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 0144d808cf1..67d941c6c2a 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -174,7 +174,7 @@ int Compilation::ExecuteCommand(const Command &C, !getDriver().CCPrintOptionsFilename.empty()) { std::error_code EC; OwnedStream.reset(new llvm::raw_fd_ostream( - getDriver().CCPrintOptionsFilename.c_str(), EC, + getDriver().CCPrintOptionsFilename, EC, llvm::sys::fs::OF_Append | llvm::sys::fs::OF_TextWithCRLF)); if (EC) { getDriver().Diag(diag::err_drv_cc_print_options_failure) diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index c4cf4e48b5b..5ac38c34d11 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -90,6 +90,7 @@ static Distro::DistroType DetectLsbRelease(llvm::vfs::FileSystem &VFS) { .Case("groovy", Distro::UbuntuGroovy) .Case("hirsute", Distro::UbuntuHirsute) .Case("impish", Distro::UbuntuImpish) + .Case("jammy", Distro::UbuntuJammy) .Default(Distro::UnknownDistro); return Version; } @@ -118,11 +119,11 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { return Distro::Fedora; if (Data.startswith("Red Hat Enterprise Linux") || Data.startswith("CentOS") || Data.startswith("Scientific Linux")) { - if (Data.find("release 7") != StringRef::npos) + if (Data.contains("release 7")) return Distro::RHEL7; - else if (Data.find("release 6") != StringRef::npos) + else if (Data.contains("release 6")) return Distro::RHEL6; - else if (Data.find("release 5") != StringRef::npos) + else if (Data.contains("release 5")) return Distro::RHEL5; } return Distro::UnknownDistro; @@ -150,6 +151,8 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { return Distro::DebianBuster; case 11: return Distro::DebianBullseye; + case 12: + return Distro::DebianBookworm; default: return Distro::UnknownDistro; } @@ -161,6 +164,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { .Case("stretch/sid", Distro::DebianStretch) .Case("buster/sid", Distro::DebianBuster) .Case("bullseye/sid", Distro::DebianBullseye) + .Case("bookworm/sid", Distro::DebianBookworm) .Default(Distro::UnknownDistro); } diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 5c323cb6ea2..8023d03013a 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -67,6 +67,7 @@ #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptSpecifier.h" @@ -84,7 +85,6 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include "llvm/Support/StringSaver.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/raw_ostream.h" #include @@ -277,7 +277,8 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, if (CCCIsCPP() || (PhaseArg = DAL.getLastArg(options::OPT_E)) || (PhaseArg = DAL.getLastArg(options::OPT__SLASH_EP)) || (PhaseArg = DAL.getLastArg(options::OPT_M, options::OPT_MM)) || - (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P))) { + (PhaseArg = DAL.getLastArg(options::OPT__SLASH_P)) || + CCGenDiagnostics) { FinalPhase = phases::Preprocess; // --precompile only runs up to precompilation. @@ -304,6 +305,9 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, } else if ((PhaseArg = DAL.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; + } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { + FinalPhase = phases::IfsMerge; + // Otherwise do everything. } else FinalPhase = phases::Link; @@ -432,8 +436,7 @@ static llvm::Triple computeTargetTriple(const Driver &D, // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made // -gnu* only, and we can not change this, so we have to detect that case as // being the Hurd OS. - if (TargetTriple.find("-unknown-gnu") != StringRef::npos || - TargetTriple.find("-pc-gnu") != StringRef::npos) + if (TargetTriple.contains("-unknown-gnu") || TargetTriple.contains("-pc-gnu")) Target.setOSName("hurd"); // Handle Apple-specific options available here. @@ -522,8 +525,11 @@ static llvm::Triple computeTargetTriple(const Driver &D, Target.setEnvironment(llvm::Triple::CODE16); } - if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) + if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) { Target.setArch(AT); + if (Target.isWindowsGNUEnvironment()) + toolchains::MinGW::fixTripleArch(D, Target, Args); + } } // Handle -miamcu flag. @@ -585,53 +591,34 @@ static llvm::Triple computeTargetTriple(const Driver &D, // Parse the LTO options and record the type of LTO compilation // based on which -f(no-)?lto(=.*)? or -f(no-)?offload-lto(=.*)? // option occurs last. -static llvm::Optional -parseLTOMode(Driver &D, const llvm::opt::ArgList &Args, OptSpecifier OptPos, - OptSpecifier OptNeg, OptSpecifier OptEq, bool IsOffload) { - driver::LTOKind LTOMode = LTOK_None; - // Non-offload LTO allows -flto=auto and -flto=jobserver. Offload LTO does - // not support those options. - if (!Args.hasFlag(OptPos, OptEq, OptNeg, false) && - (IsOffload || - (!Args.hasFlag(options::OPT_flto_EQ_auto, options::OPT_fno_lto, false) && - !Args.hasFlag(options::OPT_flto_EQ_jobserver, options::OPT_fno_lto, - false)))) - return None; - - StringRef LTOName("full"); +static driver::LTOKind parseLTOMode(Driver &D, const llvm::opt::ArgList &Args, + OptSpecifier OptEq, OptSpecifier OptNeg) { + if (!Args.hasFlag(OptEq, OptNeg, false)) + return LTOK_None; const Arg *A = Args.getLastArg(OptEq); - if (A) - LTOName = A->getValue(); + StringRef LTOName = A->getValue(); - LTOMode = llvm::StringSwitch(LTOName) - .Case("full", LTOK_Full) - .Case("thin", LTOK_Thin) - .Default(LTOK_Unknown); + driver::LTOKind LTOMode = llvm::StringSwitch(LTOName) + .Case("full", LTOK_Full) + .Case("thin", LTOK_Thin) + .Default(LTOK_Unknown); if (LTOMode == LTOK_Unknown) { - assert(A); D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << A->getValue(); - return None; + return LTOK_None; } return LTOMode; } // Parse the LTO options. void Driver::setLTOMode(const llvm::opt::ArgList &Args) { - LTOMode = LTOK_None; - if (auto M = parseLTOMode(*this, Args, options::OPT_flto, - options::OPT_fno_lto, options::OPT_flto_EQ, - /*IsOffload=*/false)) - LTOMode = M.getValue(); + LTOMode = + parseLTOMode(*this, Args, options::OPT_flto_EQ, options::OPT_fno_lto); - OffloadLTOMode = LTOK_None; - if (auto M = parseLTOMode(*this, Args, options::OPT_foffload_lto, - options::OPT_fno_offload_lto, - options::OPT_foffload_lto_EQ, - /*IsOffload=*/true)) - OffloadLTOMode = M.getValue(); + OffloadLTOMode = parseLTOMode(*this, Args, options::OPT_foffload_lto_EQ, + options::OPT_fno_offload_lto); } /// Compute the desired OpenMP runtime from the flags provided. @@ -699,6 +686,12 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, } C.addOffloadDeviceToolChain(CudaTC.get(), OFK); } else if (IsHIP) { + if (auto *OMPTargetArg = + C.getInputArgs().getLastArg(options::OPT_fopenmp_targets_EQ)) { + Diag(clang::diag::err_drv_unsupported_opt_for_language_mode) + << OMPTargetArg->getSpelling() << "HIP"; + return; + } const ToolChain *HostTC = C.getSingleOffloadToolChain(); const llvm::Triple &HostTriple = HostTC->getTriple(); auto OFK = Action::OFK_HIP; @@ -889,10 +882,9 @@ bool Driver::loadConfigFile() { std::vector ConfigFiles = CLOptions->getAllArgValues(options::OPT_config); if (ConfigFiles.size() > 1) { - if (!std::all_of(ConfigFiles.begin(), ConfigFiles.end(), - [ConfigFiles](const std::string &s) { - return s == ConfigFiles[0]; - })) { + if (!llvm::all_of(ConfigFiles, [ConfigFiles](const std::string &s) { + return s == ConfigFiles[0]; + })) { Diag(diag::err_drv_duplicate_config); return true; } @@ -1091,7 +1083,8 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { // Silence driver warnings if requested Diags.setIgnoreAllWarnings(Args.hasArg(options::OPT_w)); - // -no-canonical-prefixes is used very early in main. + // -canonical-prefixes, -no-canonical-prefixes are used very early in main. + Args.ClaimAllArgs(options::OPT_canonical_prefixes); Args.ClaimAllArgs(options::OPT_no_canonical_prefixes); // f(no-)integated-cc1 is also used very early in main. @@ -1228,8 +1221,14 @@ Compilation *Driver::BuildCompilation(ArrayRef ArgList) { static void printArgList(raw_ostream &OS, const llvm::opt::ArgList &Args) { llvm::opt::ArgStringList ASL; - for (const auto *A : Args) + for (const auto *A : Args) { + // Use user's original spelling of flags. For example, use + // `/source-charset:utf-8` instead of `-finput-charset=utf-8` if the user + // wrote the former. + while (A->getAlias()) + A = A->getAlias(); A->render(Args, ASL); + } for (auto I = ASL.begin(), E = ASL.end(); I != E; ++I) { if (I != ASL.begin()) @@ -1346,7 +1345,6 @@ void Driver::generateCompilationDiagnostics( PrintVersion(C, llvm::errs()); // Suppress driver output and emit preprocessor output to temp file. - Mode = CPPMode; CCGenDiagnostics = true; // Save the original job command(s). @@ -2148,19 +2146,6 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, if (getVFS().exists(Value)) return true; - if (IsCLMode()) { - if (!llvm::sys::path::is_absolute(Twine(Value)) && - llvm::sys::Process::FindInEnvPath("LIB", Value, ';')) - return true; - - if (Args.hasArg(options::OPT__SLASH_link) && Ty == types::TY_Object) { - // Arguments to the /link flag might cause the linker to search for object - // and library files in paths we don't know about. Don't error in such - // cases. - return true; - } - } - if (TypoCorrect) { // Check if the filename is a typo for an option flag. OptTable thinks // that all args that are not known options and that start with / are @@ -2180,6 +2165,43 @@ bool Driver::DiagnoseInputExistence(const DerivedArgList &Args, StringRef Value, } } + // In CL mode, don't error on apparently non-existent linker inputs, because + // they can be influenced by linker flags the clang driver might not + // understand. + // Examples: + // - `clang-cl main.cc ole32.lib` in a a non-MSVC shell will make the driver + // module look for an MSVC installation in the registry. (We could ask + // the MSVCToolChain object if it can find `ole32.lib`, but the logic to + // look in the registry might move into lld-link in the future so that + // lld-link invocations in non-MSVC shells just work too.) + // - `clang-cl ... /link ...` can pass arbitrary flags to the linker, + // including /libpath:, which is used to find .lib and .obj files. + // So do not diagnose this on the driver level. Rely on the linker diagnosing + // it. (If we don't end up invoking the linker, this means we'll emit a + // "'linker' input unused [-Wunused-command-line-argument]" warning instead + // of an error.) + // + // Only do this skip after the typo correction step above. `/Brepo` is treated + // as TY_Object, but it's clearly a typo for `/Brepro`. It seems fine to emit + // an error if we have a flag that's within an edit distance of 1 from a + // flag. (Users can use `-Wl,` or `/linker` to launder the flag past the + // driver in the unlikely case they run into this.) + // + // Don't do this for inputs that start with a '/', else we'd pass options + // like /libpath: through to the linker silently. + // + // Emitting an error for linker inputs can also cause incorrect diagnostics + // with the gcc driver. The command + // clang -fuse-ld=lld -Wl,--chroot,some/dir /file.o + // will make lld look for some/dir/file.o, while we will diagnose here that + // `/file.o` does not exist. However, configure scripts check if + // `clang /GR-` compiles without error to see if the compiler is cl.exe, + // so we can't downgrade diagnostics for `/GR-` from an error to a warning + // in cc mode. (We can in cl mode because cl.exe itself only warns on + // unknown flags.) + if (IsCLMode() && Ty == types::TY_Object && !Value.startswith("/")) + return true; + Diag(clang::diag::err_drv_no_such_file) << Value; return false; } @@ -2242,6 +2264,7 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, // // Otherwise emit an error but still use a valid type to avoid // spurious errors (e.g., no inputs). + assert(!CCGenDiagnostics && "stdin produces no crash reproducer"); if (!Args.hasArgNoClaim(options::OPT_E) && !CCCIsCPP()) Diag(IsCLMode() ? clang::diag::err_drv_unknown_stdin_type_clang_cl : clang::diag::err_drv_unknown_stdin_type); @@ -2257,10 +2280,10 @@ void Driver::BuildInputs(const ToolChain &TC, DerivedArgList &Args, Ty = TC.LookupTypeForExtension(Ext + 1); if (Ty == types::TY_INVALID) { - if (CCCIsCPP()) - Ty = types::TY_C; - else if (IsCLMode() && Args.hasArgNoClaim(options::OPT_E)) + if (IsCLMode() && (Args.hasArgNoClaim(options::OPT_E) || CCGenDiagnostics)) Ty = types::TY_CXX; + else if (CCCIsCPP() || CCGenDiagnostics) + Ty = types::TY_C; else Ty = types::TY_Object; } @@ -2634,7 +2657,7 @@ class OffloadingActionBuilder final { assert(CudaDeviceActions.size() == GpuArchList.size() && "Expecting one action per GPU architecture."); assert(ToolChains.size() == 1 && - "Expecting to have a sing CUDA toolchain."); + "Expecting to have a single CUDA toolchain."); for (unsigned I = 0, E = GpuArchList.size(); I != E; ++I) AddTopLevel(CudaDeviceActions[I], GpuArchList[I]); @@ -2765,7 +2788,7 @@ class OffloadingActionBuilder final { CudaActionBuilder(Compilation &C, DerivedArgList &Args, const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_Cuda) { - DefaultCudaArch = CudaArch::SM_20; + DefaultCudaArch = CudaArch::SM_35; } StringRef getCanonicalOffloadArch(StringRef ArchStr) override { @@ -2891,7 +2914,6 @@ class OffloadingActionBuilder final { class HIPActionBuilder final : public CudaActionBuilderBase { /// The linker inputs obtained for each device arch. SmallVector DeviceLinkerInputs; - bool GPUSanitize; // The default bundling behavior depends on the type of output, therefore // BundleOutput needs to be tri-value: None, true, or false. // Bundle code objects except --no-gpu-output is specified for device @@ -2904,8 +2926,6 @@ class OffloadingActionBuilder final { const Driver::InputList &Inputs) : CudaActionBuilderBase(C, Args, Inputs, Action::OFK_HIP) { DefaultCudaArch = CudaArch::GFX803; - GPUSanitize = Args.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false); if (Args.hasArg(options::OPT_gpu_bundle_output, options::OPT_no_gpu_bundle_output)) BundleOutput = Args.hasFlag(options::OPT_gpu_bundle_output, @@ -3823,7 +3843,7 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, if (Args.hasArg(options::OPT_emit_interface_stubs)) { auto PhaseList = types::getCompilationPhases( types::TY_IFS_CPP, - Args.hasArg(options::OPT_c) ? phases::Compile : phases::LastPhase); + Args.hasArg(options::OPT_c) ? phases::Compile : phases::IfsMerge); ActionList MergerInputs; @@ -4124,7 +4144,7 @@ void Driver::BuildJobs(Compilation &C) const { << '\n'; Out.flush(); std::error_code EC; - llvm::raw_fd_ostream OS(CCPrintStatReportFilename.c_str(), EC, + llvm::raw_fd_ostream OS(CCPrintStatReportFilename, EC, llvm::sys::fs::OF_Append | llvm::sys::fs::OF_Text); if (EC) @@ -4674,8 +4694,14 @@ InputInfo Driver::BuildJobsForActionNoCache( CachedResults, A->getOffloadingDeviceKind())); } - // Always use the first input as the base input. + // Always use the first file input as the base input. const char *BaseInput = InputInfos[0].getBaseInput(); + for (auto &Info : InputInfos) { + if (Info.isFilename()) { + BaseInput = Info.getBaseInput(); + break; + } + } // ... except dsymutil actions, which use their actual input as the base // input. @@ -4870,11 +4896,11 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, bool MultipleArchs, StringRef OffloadingPrefix) const { std::string BoundArch = OrigBoundArch.str(); -#if defined(_WIN32) - // BoundArch may contains ':', which is invalid in file names on Windows, - // therefore replace it with '%'. - std::replace(BoundArch.begin(), BoundArch.end(), ':', '@'); -#endif + if (is_style_windows(llvm::sys::path::Style::native)) { + // BoundArch may contains ':', which is invalid in file names on Windows, + // therefore replace it with '%'. + std::replace(BoundArch.begin(), BoundArch.end(), ':', '@'); + } llvm::PrettyStackTraceString CrashInfo("Computing output path"); // Output to a user requested destination? @@ -4939,7 +4965,13 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, return ""; } } else { - TmpName = GetTemporaryPath(Split.first, Suffix); + if (MultipleArchs && !BoundArch.empty()) { + TmpName = GetTemporaryDirectory(Split.first); + llvm::sys::path::append(TmpName, + Split.first + "-" + BoundArch + "." + Suffix); + } else { + TmpName = GetTemporaryPath(Split.first, Suffix); + } } return C.addTempFile(C.getArgs().MakeArgString(TmpName)); } @@ -5568,7 +5600,6 @@ llvm::StringRef clang::driver::getDriverMode(StringRef ProgName, if (!Arg.startswith(OptName)) continue; Opt = Arg; - break; } if (Opt.empty()) Opt = ToolChain::getTargetAndModeFromProgramName(ProgName).DriverMode; diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp index 5dd55553bcb..ab44ba50b5d 100644 --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -299,7 +299,7 @@ MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F, } void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) { - Ms.erase(std::remove_if(Ms.begin(), Ms.end(), F), Ms.end()); + llvm::erase_if(Ms, F); } raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 8770fb1cf9f..d31529748b6 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -91,6 +91,8 @@ enum CoverageFeature { CoveragePCTable = 1 << 13, CoverageStackDepth = 1 << 14, CoverageInlineBoolFlag = 1 << 15, + CoverageTraceLoads = 1 << 16, + CoverageTraceStores = 1 << 17, }; /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any @@ -100,7 +102,8 @@ static SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, /// Parse -f(no-)?sanitize-coverage= flag values, diagnosing any invalid /// components. Returns OR of members of \c CoverageFeature enumeration. -static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A); +static int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors); /// Produce an argument string from ArgList \p Args, which shows how it /// provides some sanitizer kind from \p Mask. For example, the argument list @@ -123,19 +126,21 @@ static std::string toString(const clang::SanitizerSet &Sanitizers); static void validateSpecialCaseListFormat(const Driver &D, std::vector &SCLFiles, - unsigned MalformedSCLErrorDiagID) { + unsigned MalformedSCLErrorDiagID, + bool DiagnoseErrors) { if (SCLFiles.empty()) return; std::string BLError; std::unique_ptr SCL( llvm::SpecialCaseList::create(SCLFiles, D.getVFS(), BLError)); - if (!SCL.get()) + if (!SCL.get() && DiagnoseErrors) D.Diag(MalformedSCLErrorDiagID) << BLError; } static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, - std::vector &IgnorelistFiles) { + std::vector &IgnorelistFiles, + bool DiagnoseErrors) { struct Ignorelist { const char *File; SanitizerMask Mask; @@ -159,13 +164,14 @@ static void addDefaultIgnorelists(const Driver &D, SanitizerMask Kinds, llvm::sys::path::append(Path, "share", BL.File); if (D.getVFS().exists(Path)) IgnorelistFiles.push_back(std::string(Path.str())); - else if (BL.Mask == SanitizerKind::CFI) + else if (BL.Mask == SanitizerKind::CFI && DiagnoseErrors) // If cfi_ignorelist.txt cannot be found in the resource dir, driver // should fail. D.Diag(clang::diag::err_drv_no_such_file) << Path; } validateSpecialCaseListFormat( - D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist); + D, IgnorelistFiles, clang::diag::err_drv_malformed_sanitizer_ignorelist, + DiagnoseErrors); } /// Parse -f(no-)?sanitize-(coverage-)?(white|ignore)list argument's values, @@ -175,7 +181,8 @@ static void parseSpecialCaseListArg(const Driver &D, std::vector &SCLFiles, llvm::opt::OptSpecifier SCLOptionID, llvm::opt::OptSpecifier NoSCLOptionID, - unsigned MalformedSCLErrorDiagID) { + unsigned MalformedSCLErrorDiagID, + bool DiagnoseErrors) { for (const auto *Arg : Args) { // Match -fsanitize-(coverage-)?(white|ignore)list. if (Arg->getOption().matches(SCLOptionID)) { @@ -183,7 +190,7 @@ static void parseSpecialCaseListArg(const Driver &D, std::string SCLPath = Arg->getValue(); if (D.getVFS().exists(SCLPath)) { SCLFiles.push_back(SCLPath); - } else { + } else if (DiagnoseErrors) { D.Diag(clang::diag::err_drv_no_such_file) << SCLPath; } // Match -fno-sanitize-ignorelist. @@ -192,7 +199,8 @@ static void parseSpecialCaseListArg(const Driver &D, SCLFiles.clear(); } } - validateSpecialCaseListFormat(D, SCLFiles, MalformedSCLErrorDiagID); + validateSpecialCaseListFormat(D, SCLFiles, MalformedSCLErrorDiagID, + DiagnoseErrors); } /// Sets group bits for every group that has at least one representative already @@ -207,21 +215,21 @@ static SanitizerMask setGroupBits(SanitizerMask Kinds) { } static SanitizerMask parseSanitizeTrapArgs(const Driver &D, - const llvm::opt::ArgList &Args) { + const llvm::opt::ArgList &Args, + bool DiagnoseErrors) { SanitizerMask TrapRemove; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. SanitizerMask TrappingKinds; SanitizerMask TrappingSupportedWithGroups = setGroupBits(TrappingSupported); - for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); - I != E; ++I) { - const auto *Arg = *I; + for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) { if (Arg->getOption().matches(options::OPT_fsanitize_trap_EQ)) { Arg->claim(); SanitizerMask Add = parseArgValues(D, Arg, true); Add &= ~TrapRemove; - if (SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups) { + SanitizerMask InvalidValues = Add & ~TrappingSupportedWithGroups; + if (InvalidValues && DiagnoseErrors) { SanitizerSet S; S.Mask = InvalidValues; D.Diag(diag::err_drv_unsupported_option_argument) << "-fsanitize-trap" @@ -230,7 +238,8 @@ static SanitizerMask parseSanitizeTrapArgs(const Driver &D, TrappingKinds |= expandSanitizerGroups(Add) & ~TrapRemove; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_trap_EQ)) { Arg->claim(); - TrapRemove |= expandSanitizerGroups(parseArgValues(D, Arg, true)); + TrapRemove |= + expandSanitizerGroups(parseArgValues(D, Arg, DiagnoseErrors)); } } @@ -278,7 +287,8 @@ bool SanitizerArgs::needsLTO() const { } SanitizerArgs::SanitizerArgs(const ToolChain &TC, - const llvm::opt::ArgList &Args) { + const llvm::opt::ArgList &Args, + bool DiagnoseErrors) { SanitizerMask AllRemove; // During the loop below, the accumulated set of // sanitizers disabled by the current sanitizer // argument or any argument after it. @@ -298,7 +308,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); const Driver &D = TC.getDriver(); - SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args); + SanitizerMask TrappingKinds = parseSanitizeTrapArgs(D, Args, DiagnoseErrors); SanitizerMask InvalidTrappingKinds = TrappingKinds & NotAllowedWithTrap; MinimalRuntime = @@ -310,19 +320,17 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, bool RemoveObjectSizeAtO0 = !OptLevel || OptLevel->getOption().matches(options::OPT_O0); - for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend(); - I != E; ++I) { - const auto *Arg = *I; + for (const llvm::opt::Arg *Arg : llvm::reverse(Args)) { if (Arg->getOption().matches(options::OPT_fsanitize_EQ)) { Arg->claim(); - SanitizerMask Add = parseArgValues(D, Arg, /*AllowGroups=*/true); + SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); if (RemoveObjectSizeAtO0) { AllRemove |= SanitizerKind::ObjectSize; // The user explicitly enabled the object size sanitizer. Warn // that this does nothing at -O0. - if (Add & SanitizerKind::ObjectSize) + if ((Add & SanitizerKind::ObjectSize) && DiagnoseErrors) D.Diag(diag::warn_drv_object_size_disabled_O0) << Arg->getAsString(Args); } @@ -336,9 +344,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Diagnose them. if (SanitizerMask KindsToDiagnose = Add & InvalidTrappingKinds & ~DiagnosedKinds) { - std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); - D.Diag(diag::err_drv_argument_not_allowed_with) - << Desc << "-fsanitize-trap=undefined"; + if (DiagnoseErrors) { + std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-trap=undefined"; + } DiagnosedKinds |= KindsToDiagnose; } Add &= ~InvalidTrappingKinds; @@ -346,9 +356,11 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (MinimalRuntime) { if (SanitizerMask KindsToDiagnose = Add & NotAllowedWithMinimalRuntime & ~DiagnosedKinds) { - std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); - D.Diag(diag::err_drv_argument_not_allowed_with) - << Desc << "-fsanitize-minimal-runtime"; + if (DiagnoseErrors) { + std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); + D.Diag(diag::err_drv_argument_not_allowed_with) + << Desc << "-fsanitize-minimal-runtime"; + } DiagnosedKinds |= KindsToDiagnose; } Add &= ~NotAllowedWithMinimalRuntime; @@ -365,17 +377,20 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Fixing both of those may require changes to the cross-DSO CFI // interface. if (CfiCrossDso && (Add & SanitizerKind::CFIMFCall & ~DiagnosedKinds)) { - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fsanitize=cfi-mfcall" - << "-fsanitize-cfi-cross-dso"; + if (DiagnoseErrors) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize=cfi-mfcall" + << "-fsanitize-cfi-cross-dso"; Add &= ~SanitizerKind::CFIMFCall; DiagnosedKinds |= SanitizerKind::CFIMFCall; } if (SanitizerMask KindsToDiagnose = Add & ~Supported & ~DiagnosedKinds) { - std::string Desc = describeSanitizeArg(*I, KindsToDiagnose); - D.Diag(diag::err_drv_unsupported_opt_for_target) - << Desc << TC.getTriple().str(); + if (DiagnoseErrors) { + std::string Desc = describeSanitizeArg(Arg, KindsToDiagnose); + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Desc << TC.getTriple().str(); + } DiagnosedKinds |= KindsToDiagnose; } Add &= Supported; @@ -389,12 +404,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, "RTTI disabled without -fno-rtti option?"); // The user explicitly passed -fno-rtti with -fsanitize=vptr, but // the vptr sanitizer requires RTTI, so this is a user error. - D.Diag(diag::err_drv_argument_not_allowed_with) - << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); + if (DiagnoseErrors) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize=vptr" << NoRTTIArg->getAsString(Args); } else { // The vptr sanitizer requires RTTI, but RTTI is disabled (by // default). Warn that the vptr sanitizer is being disabled. - D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); + if (DiagnoseErrors) + D.Diag(diag::warn_drv_disabling_vptr_no_rtti_default); } // Take out the Vptr sanitizer from the enabled sanitizers @@ -429,7 +446,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Kinds |= Add; } else if (Arg->getOption().matches(options::OPT_fno_sanitize_EQ)) { Arg->claim(); - SanitizerMask Remove = parseArgValues(D, Arg, true); + SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); AllRemove |= expandSanitizerGroups(Remove); } } @@ -490,7 +507,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } // Check that LTO is enabled if we need it. - if ((Kinds & NeedsLTO) && !D.isUsingLTO()) { + if ((Kinds & NeedsLTO) && !D.isUsingLTO() && DiagnoseErrors) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } @@ -499,7 +516,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, ((TC.getTriple().isAArch64() && !llvm::AArch64::isX18ReservedByDefault(TC.getTriple())) || TC.getTriple().isRISCV()) && - !Args.hasArg(options::OPT_ffixed_x18)) { + !Args.hasArg(options::OPT_ffixed_x18) && DiagnoseErrors) { D.Diag(diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, Kinds & SanitizerKind::ShadowCallStack) << "-ffixed-x18"; @@ -518,8 +535,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (KindsToDiagnose) { SanitizerSet S; S.Mask = KindsToDiagnose; - D.Diag(diag::err_drv_unsupported_opt_for_target) - << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); + if (DiagnoseErrors) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << ("-fno-sanitize-trap=" + toString(S)) << TC.getTriple().str(); Kinds &= ~KindsToDiagnose; } } @@ -529,9 +547,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask Group = G.first; if (Kinds & Group) { if (SanitizerMask Incompatible = Kinds & G.second) { - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << lastArgumentForMask(D, Args, Group) - << lastArgumentForMask(D, Args, Incompatible); + if (DiagnoseErrors) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << lastArgumentForMask(D, Args, Group) + << lastArgumentForMask(D, Args, Incompatible); Kinds &= ~Incompatible; } } @@ -547,29 +566,31 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, SanitizerMask DiagnosedAlwaysRecoverableKinds; for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_recover_EQ)) { - SanitizerMask Add = parseArgValues(D, Arg, true); + SanitizerMask Add = parseArgValues(D, Arg, DiagnoseErrors); // Report error if user explicitly tries to recover from unrecoverable // sanitizer. if (SanitizerMask KindsToDiagnose = Add & Unrecoverable & ~DiagnosedUnrecoverableKinds) { SanitizerSet SetToDiagnose; SetToDiagnose.Mask |= KindsToDiagnose; - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + if (DiagnoseErrors) + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getOption().getName() << toString(SetToDiagnose); DiagnosedUnrecoverableKinds |= KindsToDiagnose; } RecoverableKinds |= expandSanitizerGroups(Add); Arg->claim(); } else if (Arg->getOption().matches(options::OPT_fno_sanitize_recover_EQ)) { - SanitizerMask Remove = parseArgValues(D, Arg, true); + SanitizerMask Remove = parseArgValues(D, Arg, DiagnoseErrors); // Report error if user explicitly tries to disable recovery from // always recoverable sanitizer. if (SanitizerMask KindsToDiagnose = Remove & AlwaysRecoverable & ~DiagnosedAlwaysRecoverableKinds) { SanitizerSet SetToDiagnose; SetToDiagnose.Mask |= KindsToDiagnose; - D.Diag(diag::err_drv_unsupported_option_argument) - << Arg->getOption().getName() << toString(SetToDiagnose); + if (DiagnoseErrors) + D.Diag(diag::err_drv_unsupported_option_argument) + << Arg->getOption().getName() << toString(SetToDiagnose); DiagnosedAlwaysRecoverableKinds |= KindsToDiagnose; } RecoverableKinds &= ~expandSanitizerGroups(Remove); @@ -586,14 +607,14 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Add default ignorelist from resource directory for activated sanitizers, // and validate special case lists format. if (!Args.hasArgNoClaim(options::OPT_fno_sanitize_ignorelist)) - addDefaultIgnorelists(D, Kinds, SystemIgnorelistFiles); + addDefaultIgnorelists(D, Kinds, SystemIgnorelistFiles, DiagnoseErrors); // Parse -f(no-)?sanitize-ignorelist options. // This also validates special case lists format. - parseSpecialCaseListArg(D, Args, UserIgnorelistFiles, - options::OPT_fsanitize_ignorelist_EQ, - options::OPT_fno_sanitize_ignorelist, - clang::diag::err_drv_malformed_sanitizer_ignorelist); + parseSpecialCaseListArg( + D, Args, UserIgnorelistFiles, options::OPT_fsanitize_ignorelist_EQ, + options::OPT_fno_sanitize_ignorelist, + clang::diag::err_drv_malformed_sanitizer_ignorelist, DiagnoseErrors); // Parse -f[no-]sanitize-memory-track-origins[=level] options. if (AllAddedKinds & SanitizerKind::Memory) { @@ -610,7 +631,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, StringRef S = A->getValue(); if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 || MsanTrackOrigins > 2) { - D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; + if (DiagnoseErrors) + D.Diag(clang::diag::err_drv_invalid_value) + << A->getAsString(Args) << S; } } } @@ -643,7 +666,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, CfiICallGeneralizePointers = Args.hasArg(options::OPT_fsanitize_cfi_icall_generalize_pointers); - if (CfiCrossDso && CfiICallGeneralizePointers) + if (CfiCrossDso && CfiICallGeneralizePointers && DiagnoseErrors) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fsanitize-cfi-cross-dso" << "-fsanitize-cfi-icall-generalize-pointers"; @@ -659,13 +682,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (MinimalRuntime) { SanitizerMask IncompatibleMask = Kinds & ~setGroupBits(CompatibleWithMinimalRuntime); - if (IncompatibleMask) + if (IncompatibleMask && DiagnoseErrors) D.Diag(clang::diag::err_drv_argument_not_allowed_with) << "-fsanitize-minimal-runtime" << lastArgumentForMask(D, Args, IncompatibleMask); SanitizerMask NonTrappingCfi = Kinds & SanitizerKind::CFI & ~TrappingKinds; - if (NonTrappingCfi) + if (NonTrappingCfi && DiagnoseErrors) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << "fsanitize-minimal-runtime" << "fsanitize-trap=cfi"; @@ -681,13 +704,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, .getAsInteger(0, LegacySanitizeCoverage)) { CoverageFeatures = 0; Arg->claim(); - if (LegacySanitizeCoverage != 0) { + if (LegacySanitizeCoverage != 0 && DiagnoseErrors) { D.Diag(diag::warn_drv_deprecated_arg) << Arg->getAsString(Args) << "-fsanitize-coverage=trace-pc-guard"; } continue; } - CoverageFeatures |= parseCoverageFeatures(D, Arg); + CoverageFeatures |= parseCoverageFeatures(D, Arg, DiagnoseErrors); // Disable coverage and not claim the flags if there is at least one // non-supporting sanitizer. @@ -698,39 +721,41 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, } } else if (Arg->getOption().matches(options::OPT_fno_sanitize_coverage)) { Arg->claim(); - CoverageFeatures &= ~parseCoverageFeatures(D, Arg); + CoverageFeatures &= ~parseCoverageFeatures(D, Arg, DiagnoseErrors); } } // Choose at most one coverage type: function, bb, or edge. - if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << "-fsanitize-coverage=func" - << "-fsanitize-coverage=bb"; - if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << "-fsanitize-coverage=func" - << "-fsanitize-coverage=edge"; - if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << "-fsanitize-coverage=bb" - << "-fsanitize-coverage=edge"; - // Basic block tracing and 8-bit counters require some type of coverage - // enabled. - if (CoverageFeatures & CoverageTraceBB) - D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=trace-bb" - << "-fsanitize-coverage=trace-pc-guard"; - if (CoverageFeatures & Coverage8bitCounters) - D.Diag(clang::diag::warn_drv_deprecated_arg) - << "-fsanitize-coverage=8bit-counters" - << "-fsanitize-coverage=trace-pc-guard"; + if (DiagnoseErrors) { + if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageBB)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=func" + << "-fsanitize-coverage=bb"; + if ((CoverageFeatures & CoverageFunc) && (CoverageFeatures & CoverageEdge)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=func" + << "-fsanitize-coverage=edge"; + if ((CoverageFeatures & CoverageBB) && (CoverageFeatures & CoverageEdge)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << "-fsanitize-coverage=bb" + << "-fsanitize-coverage=edge"; + // Basic block tracing and 8-bit counters require some type of coverage + // enabled. + if (CoverageFeatures & CoverageTraceBB) + D.Diag(clang::diag::warn_drv_deprecated_arg) + << "-fsanitize-coverage=trace-bb" + << "-fsanitize-coverage=trace-pc-guard"; + if (CoverageFeatures & Coverage8bitCounters) + D.Diag(clang::diag::warn_drv_deprecated_arg) + << "-fsanitize-coverage=8bit-counters" + << "-fsanitize-coverage=trace-pc-guard"; + } int InsertionPointTypes = CoverageFunc | CoverageBB | CoverageEdge; int InstrumentationTypes = CoverageTracePC | CoverageTracePCGuard | - CoverageInline8bitCounters | - CoverageInlineBoolFlag; + CoverageInline8bitCounters | CoverageTraceLoads | + CoverageTraceStores | CoverageInlineBoolFlag; if ((CoverageFeatures & InsertionPointTypes) && - !(CoverageFeatures & InstrumentationTypes)) { + !(CoverageFeatures & InstrumentationTypes) && DiagnoseErrors) { D.Diag(clang::diag::warn_drv_deprecated_arg) << "-fsanitize-coverage=[func|bb|edge]" << "-fsanitize-coverage=[func|bb|edge],[trace-pc-guard|trace-pc]"; @@ -755,11 +780,13 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, parseSpecialCaseListArg( D, Args, CoverageAllowlistFiles, options::OPT_fsanitize_coverage_allowlist, OptSpecifier(), - clang::diag::err_drv_malformed_sanitizer_coverage_whitelist); + clang::diag::err_drv_malformed_sanitizer_coverage_allowlist, + DiagnoseErrors); parseSpecialCaseListArg( D, Args, CoverageIgnorelistFiles, options::OPT_fsanitize_coverage_ignorelist, OptSpecifier(), - clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist); + clang::diag::err_drv_malformed_sanitizer_coverage_ignorelist, + DiagnoseErrors); } SharedRuntime = @@ -775,8 +802,9 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, Args.getLastArg(options::OPT_fsanitize_address_field_padding)) { StringRef S = A->getValue(); // Legal values are 0 and 1, 2, but in future we may add more levels. - if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || - AsanFieldPadding > 2) { + if ((S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 || + AsanFieldPadding > 2) && + DiagnoseErrors) { D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S; } } @@ -789,10 +817,12 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, case options::OPT__SLASH_MTd: case options::OPT__SLASH_MDd: case options::OPT__SLASH_LDd: - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << WindowsDebugRTArg->getAsString(Args) - << lastArgumentForMask(D, Args, SanitizerKind::Address); - D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); + if (DiagnoseErrors) { + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << WindowsDebugRTArg->getAsString(Args) + << lastArgumentForMask(D, Args, SanitizerKind::Address); + D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime); + } } } @@ -840,7 +870,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (const auto *Arg = Args.getLastArg(options::OPT_sanitize_address_destructor_EQ)) { auto parsedAsanDtorKind = AsanDtorKindFromString(Arg->getValue()); - if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid) { + if (parsedAsanDtorKind == llvm::AsanDtorKind::Invalid && DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) << Arg->getOption().getName() << Arg->getValue(); } @@ -852,7 +882,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, auto parsedAsanUseAfterReturn = AsanDetectStackUseAfterReturnModeFromString(Arg->getValue()); if (parsedAsanUseAfterReturn == - llvm::AsanDetectStackUseAfterReturnMode::Invalid) { + llvm::AsanDetectStackUseAfterReturnMode::Invalid && + DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_unsupported_option_argument) << Arg->getOption().getName() << Arg->getValue(); } @@ -864,7 +895,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // -fsanitize=pointer-compare/pointer-subtract requires -fsanitize=address. SanitizerMask DetectInvalidPointerPairs = SanitizerKind::PointerCompare | SanitizerKind::PointerSubtract; - if (AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) { + if ((AllAddedKinds & DetectInvalidPointerPairs & ~AllRemove) && + DiagnoseErrors) { TC.getDriver().Diag(clang::diag::err_drv_argument_only_allowed_with) << lastArgumentForMask(D, Args, SanitizerKind::PointerCompare | @@ -877,7 +909,8 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, if (Arg *HwasanAbiArg = Args.getLastArg(options::OPT_fsanitize_hwaddress_abi_EQ)) { HwasanAbi = HwasanAbiArg->getValue(); - if (HwasanAbi != "platform" && HwasanAbi != "interceptor") + if (HwasanAbi != "platform" && HwasanAbi != "interceptor" && + DiagnoseErrors) D.Diag(clang::diag::err_drv_invalid_value) << HwasanAbiArg->getAsString(Args) << HwasanAbi; } else { @@ -977,8 +1010,8 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, // AMDGPU sanitizer support is experimental and controlled by -fgpu-sanitize. if (TC.getTriple().isNVPTX() || (TC.getTriple().isAMDGPU() && - !Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, - false))) + !Args.hasFlag(options::OPT_fgpu_sanitize, + options::OPT_fno_gpu_sanitize))) return; // Translate available CoverageFeatures to corresponding clang-cc1 flags. @@ -1003,7 +1036,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, "-fsanitize-coverage-inline-bool-flag"), std::make_pair(CoveragePCTable, "-fsanitize-coverage-pc-table"), std::make_pair(CoverageNoPrune, "-fsanitize-coverage-no-prune"), - std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth")}; + std::make_pair(CoverageStackDepth, "-fsanitize-coverage-stack-depth"), + std::make_pair(CoverageTraceLoads, "-fsanitize-coverage-trace-loads"), + std::make_pair(CoverageTraceStores, "-fsanitize-coverage-trace-stores")}; for (auto F : CoverageFlags) { if (CoverageFeatures & F.first) CmdArgs.push_back(F.second); @@ -1146,7 +1181,7 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back(Args.MakeArgString("hwasan-abi=" + HwasanAbi)); } - if (Sanitizers.has(SanitizerKind::HWAddress) && TC.getTriple().isAArch64()) { + if (Sanitizers.has(SanitizerKind::HWAddress) && !HwasanUseAliases) { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+tagged-globals"); } @@ -1220,7 +1255,8 @@ SanitizerMask parseArgValues(const Driver &D, const llvm::opt::Arg *A, return Kinds; } -int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { +int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A, + bool DiagnoseErrors) { assert(A->getOption().matches(options::OPT_fsanitize_coverage) || A->getOption().matches(options::OPT_fno_sanitize_coverage)); int Features = 0; @@ -1243,8 +1279,10 @@ int parseCoverageFeatures(const Driver &D, const llvm::opt::Arg *A) { .Case("inline-bool-flag", CoverageInlineBoolFlag) .Case("pc-table", CoveragePCTable) .Case("stack-depth", CoverageStackDepth) + .Case("trace-loads", CoverageTraceLoads) + .Case("trace-stores", CoverageTraceStores) .Default(0); - if (F == 0) + if (F == 0 && DiagnoseErrors) D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; Features |= F; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 6c1b88141c4..6588cdf9fec 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -9,8 +9,8 @@ #include "clang/Driver/ToolChain.h" #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" -#include "ToolChains/InterfaceStubs.h" #include "ToolChains/Flang.h" +#include "ToolChains/InterfaceStubs.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -29,6 +29,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Config/llvm-config.h" #include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -37,7 +38,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/TargetParser.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/VirtualFileSystem.h" #include @@ -110,14 +110,11 @@ bool ToolChain::useRelaxRelocations() const { return ENABLE_X86_RELAX_RELOCATIONS; } -bool ToolChain::isNoExecStackDefault() const { - return false; -} - -const SanitizerArgs& ToolChain::getSanitizerArgs() const { - if (!SanitizerArguments.get()) - SanitizerArguments.reset(new SanitizerArgs(*this, Args)); - return *SanitizerArguments.get(); +SanitizerArgs +ToolChain::getSanitizerArgs(const llvm::opt::ArgList &JobArgs) const { + SanitizerArgs SanArgs(*this, JobArgs, !SanitizerArgsChecked); + SanitizerArgsChecked = true; + return SanArgs; } const XRayArgs& ToolChain::getXRayArgs() const { @@ -169,10 +166,11 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { /// present and lower-casing the string on Windows. static std::string normalizeProgramName(llvm::StringRef Argv0) { std::string ProgName = std::string(llvm::sys::path::stem(Argv0)); -#ifdef _WIN32 - // Transform to lowercase for case insensitive file systems. - std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); -#endif + if (is_style_windows(llvm::sys::path::Style::native)) { + // Transform to lowercase for case insensitive file systems. + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), + ::tolower); + } return ProgName; } @@ -583,7 +581,7 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, // for the linker flavor is brittle. In addition, prepending "ld." or "ld64." // to a relative path is surprising. This is more complex due to priorities // among -B, COMPILER_PATH and PATH. --ld-path= should be used instead. - if (UseLinker.find('/') != StringRef::npos) + if (UseLinker.contains('/')) getDriver().Diag(diag::warn_drv_fuse_ld_path); if (llvm::sys::path::is_absolute(UseLinker)) { @@ -618,6 +616,8 @@ std::string ToolChain::GetLinkerPath(bool *LinkerIsLLD, std::string ToolChain::GetStaticLibToolPath() const { // TODO: Add support for static lib archiving on Windows + if (Triple.isOSDarwin()) + return GetProgramPath("libtool"); return GetProgramPath("llvm-ar"); } @@ -1024,7 +1024,7 @@ void ToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, void ToolChain::AddHIPIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const {} -llvm::SmallVector +llvm::SmallVector ToolChain::getHIPDeviceLibs(const ArgList &DriverArgs) const { return {}; } diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 3000b8416ad..e4bbf498b9c 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -98,6 +98,26 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-bnoentry"); } + // Specify PGO linker option without LTO + if (!D.isUsingLTO() && + (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasFlag(options::OPT_fprofile_generate, + options::OPT_fno_profile_generate, false) || + Args.hasFlag(options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fcs_profile_generate, + options::OPT_fno_profile_generate, false) || + Args.hasFlag(options::OPT_fcs_profile_generate_EQ, + options::OPT_fno_profile_generate, false) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage))) + CmdArgs.push_back("-bdbg:namedsects"); + // Specify linker output file. assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); if (Output.isFilename()) { @@ -218,15 +238,44 @@ void AIX::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, UP.str()); } +void AIX::AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdincxx) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error( + "picking up libstdc++ headers is unimplemented on AIX"); + case ToolChain::CST_Libcxx: { + llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs); + SmallString<128> PathCPP(Sysroot); + llvm::sys::path::append(PathCPP, "opt/IBM/openxlCSDK", "include", "c++", + "v1"); + addSystemInclude(DriverArgs, CC1Args, PathCPP.str()); + // Required in order to suppress conflicting C++ overloads in the system + // libc headers that were used by XL C++. + CC1Args.push_back("-D__LIBC_NO_CPP_MATH_OVERLOADS__"); + return; + } + } + + llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); +} + void AIX::AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libstdcxx: + llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); case ToolChain::CST_Libcxx: CmdArgs.push_back("-lc++"); CmdArgs.push_back("-lc++abi"); return; - case ToolChain::CST_Libstdcxx: - llvm::report_fatal_error("linking libstdc++ unimplemented on AIX"); } llvm_unreachable("Unexpected C++ library type; only libc++ is supported."); diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h index d1ec6d10fb3..e7ec3a5ece4 100644 --- a/clang/lib/Driver/ToolChains/AIX.h +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -63,13 +63,19 @@ public: return ParseInlineAsmUsingAsmParser; } bool isPICDefault() const override { return true; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return true; } void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index d63c5e12c4a..b5eaf1adca6 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -754,7 +754,7 @@ AMDGPUToolChain::detectSystemGPUs(const ArgList &Args, std::string ErrorMessage; if (int Result = llvm::sys::ExecuteAndWait( - Program.c_str(), {}, {}, Redirects, /* SecondsToWait */ 0, + Program, {}, {}, Redirects, /* SecondsToWait */ 0, /*MemoryLimit*/ 0, &ErrorMessage)) { if (Result > 0) { ErrorMessage = "Exited with error code " + std::to_string(Result); @@ -796,9 +796,9 @@ llvm::Error AMDGPUToolChain::getSystemGPUArch(const ArgList &Args, } GPUArch = GPUArchs[0]; if (GPUArchs.size() > 1) { - bool AllSame = std::all_of( - GPUArchs.begin(), GPUArchs.end(), - [&](const StringRef &GPUArch) { return GPUArch == GPUArchs.front(); }); + bool AllSame = llvm::all_of(GPUArchs, [&](const StringRef &GPUArch) { + return GPUArch == GPUArchs.front(); + }); if (!AllSame) return llvm::createStringError( std::error_code(), "Multiple AMD GPUs found with different archs"); @@ -893,3 +893,38 @@ bool AMDGPUToolChain::shouldSkipArgument(const llvm::opt::Arg *A) const { return true; return false; } + +llvm::SmallVector +ROCMToolChain::getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, + const std::string &GPUArch) const { + auto Kind = llvm::AMDGPU::parseArchAMDGCN(GPUArch); + const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); + + std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); + if (LibDeviceFile.empty()) { + getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GPUArch; + return {}; + } + + // If --hip-device-lib is not set, add the default bitcode libraries. + // TODO: There are way too many flags that change this. Do we need to check + // them all? + bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, + options::OPT_fno_gpu_flush_denormals_to_zero, + getDefaultDenormsAreZeroForTarget(Kind)); + bool FiniteOnly = DriverArgs.hasFlag( + options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, false); + bool UnsafeMathOpt = + DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, false); + bool FastRelaxedMath = DriverArgs.hasFlag(options::OPT_ffast_math, + options::OPT_fno_fast_math, false); + bool CorrectSqrt = DriverArgs.hasFlag( + options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, + options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); + bool Wave64 = isWave64(DriverArgs, Kind); + + return RocmInstallation.getCommonBitcodeLibs( + DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, + FastRelaxedMath, CorrectSqrt); +} diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 50ed3b3ded9..156bfd1fbdb 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -51,7 +51,7 @@ protected: const std::map OptionsDefault; Tool *buildLinker() const override; - const StringRef getOptionDefault(options::ID OptID) const { + StringRef getOptionDefault(options::ID OptID) const { auto opt = OptionsDefault.find(OptID); assert(opt != OptionsDefault.end() && "No Default for Option"); return opt->second; @@ -60,14 +60,16 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 4; } + unsigned GetDefaultDwarfVersion() const override { return 5; } bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } bool useIntegratedAs() const override { return true; } bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } @@ -136,6 +138,11 @@ public: addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override; + + // Returns a list of device library names shared by different languages + llvm::SmallVector + getCommonDeviceLibNames(const llvm::opt::ArgList &DriverArgs, + const std::string &GPUArch) const; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp index fe1d19c2dd6..863e2c597d5 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.cpp @@ -9,12 +9,14 @@ #include "AMDGPUOpenMP.h" #include "AMDGPU.h" #include "CommonArgs.h" +#include "ToolChains/ROCm.h" #include "clang/Basic/DiagnosticDriver.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -84,14 +86,54 @@ static bool checkSystemForAMDGPU(const ArgList &Args, const AMDGPUToolChain &TC, } // namespace const char *AMDGCN::OpenMPLinker::constructLLVMLinkCommand( - Compilation &C, const JobAction &JA, const InputInfoList &Inputs, - const ArgList &Args, StringRef SubArchName, - StringRef OutputFilePrefix) const { + const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, + const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, + StringRef SubArchName, StringRef OutputFilePrefix) const { ArgStringList CmdArgs; for (const auto &II : Inputs) if (II.isFilename()) CmdArgs.push_back(II.getFilename()); + + if (Args.hasArg(options::OPT_l)) { + auto Lm = Args.getAllArgValues(options::OPT_l); + bool HasLibm = false; + for (auto &Lib : Lm) { + if (Lib == "m") { + HasLibm = true; + break; + } + } + + if (HasLibm) { + // This is not certain to work. The device libs added here, and passed to + // llvm-link, are missing attributes that they expect to be inserted when + // passed to mlink-builtin-bitcode. The amdgpu backend does not generate + // conservatively correct code when attributes are missing, so this may + // be the root cause of miscompilations. Passing via mlink-builtin-bitcode + // ultimately hits CodeGenModule::addDefaultFunctionDefinitionAttributes + // on each function, see D28538 for context. + // Potential workarounds: + // - unconditionally link all of the device libs to every translation + // unit in clang via mlink-builtin-bitcode + // - build a libm bitcode file as part of the DeviceRTL and explictly + // mlink-builtin-bitcode the rocm device libs components at build time + // - drop this llvm-link fork in favour or some calls into LLVM, chosen + // to do basically the same work as llvm-link but with that call first + // - write an opt pass that sets that on every function it sees and pipe + // the device-libs bitcode through that on the way to this llvm-link + SmallVector BCLibs = + AMDGPUOpenMPTC.getCommonDeviceLibNames(Args, SubArchName.str()); + llvm::for_each(BCLibs, [&](StringRef BCFile) { + CmdArgs.push_back(Args.MakeArgString(BCFile)); + }); + } + } + + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "amdgcn", + SubArchName, + /* bitcode SDL?*/ true, + /* PostClang Link? */ false); // Add an intermediate output file. CmdArgs.push_back("-o"); const char *OutputFileName = @@ -180,8 +222,8 @@ void AMDGCN::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, assert(Prefix.length() && "no linker inputs are files "); // Each command outputs different files. - const char *LLVMLinkCommand = - constructLLVMLinkCommand(C, JA, Inputs, Args, GPUArch, Prefix); + const char *LLVMLinkCommand = constructLLVMLinkCommand( + AMDGPUOpenMPTC, C, JA, Inputs, Args, GPUArch, Prefix); // Produce readable assembly if save-temps is enabled. if (C.getDriver().isSaveTempsEnabled()) @@ -226,7 +268,7 @@ void AMDGPUOpenMPToolChain::addClangTargetOptions( std::string BitcodeSuffix; if (DriverArgs.hasFlag(options::OPT_fopenmp_target_new_runtime, options::OPT_fno_openmp_target_new_runtime, false)) - BitcodeSuffix = "new-amdgcn-" + GPUArch; + BitcodeSuffix = "new-amdgpu-" + GPUArch; else BitcodeSuffix = "amdgcn-" + GPUArch; diff --git a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h index effca7e212c..233256bf737 100644 --- a/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h +++ b/clang/lib/Driver/ToolChains/AMDGPUOpenMP.h @@ -16,6 +16,10 @@ namespace clang { namespace driver { +namespace toolchains { +class AMDGPUOpenMPToolChain; +} + namespace tools { namespace AMDGCN { @@ -35,11 +39,11 @@ public: private: /// \return llvm-link output file name. - const char *constructLLVMLinkCommand(Compilation &C, const JobAction &JA, - const InputInfoList &Inputs, - const llvm::opt::ArgList &Args, - llvm::StringRef SubArchName, - llvm::StringRef OutputFilePrefix) const; + const char *constructLLVMLinkCommand( + const toolchains::AMDGPUOpenMPToolChain &AMDGPUOpenMPTC, Compilation &C, + const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, llvm::StringRef SubArchName, + llvm::StringRef OutputFilePrefix) const; /// \return llc output file name. const char *constructLlcCommand(Compilation &C, const JobAction &JA, diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index f147292038a..a66cae8b4d6 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -28,9 +28,9 @@ using namespace llvm::opt; namespace { -const struct { +constexpr struct { StringRef Name; - std::string SubPath; + StringRef SubPath; StringRef Family; unsigned DataAddr; } MCUInfo[] = { @@ -298,6 +298,7 @@ llvm::Optional GetMCUSectionAddressData(StringRef MCUName) { } const StringRef PossibleAVRLibcLocations[] = { + "/avr", "/usr/avr", "/usr/lib/avr", }; @@ -314,7 +315,7 @@ AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs) && !Args.hasArg(options::OPT_c /* does not apply when not linking */)) { - std::string CPU = getCPUName(Args, Triple); + std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty()) { // We cannot link any standard libraries without an MCU specified. @@ -370,6 +371,16 @@ void AVRToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, AVRInc); } +void AVRToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + // By default, use `.ctors` (not `.init_array`), as required by libgcc, which + // runs constructors/destructors on AVR. + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, false)) + CC1Args.push_back("-fno-use-init-array"); +} + Tool *AVRToolChain::buildLinker() const { return new tools::AVR::Linker(getTriple(), *this, LinkStdlib); } @@ -378,8 +389,10 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + // Compute information about the target AVR. - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); llvm::Optional FamilyName = GetMCUFamilyName(CPU); llvm::Optional SectionAddressData = GetMCUSectionAddressData(CPU); @@ -403,9 +416,7 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(DataSectionArg)); } else { // We do not have an entry for this CPU in the address mapping table yet. - getToolChain().getDriver().Diag( - diag::warn_drv_avr_linker_section_addresses_not_implemented) - << CPU; + D.Diag(diag::warn_drv_avr_linker_section_addresses_not_implemented) << CPU; } // If the family name is known, we can link with the device-specific libgcc. @@ -414,6 +425,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (LinkStdlib) { assert(!CPU.empty() && "CPU name must be known in order to link stdlibs"); + CmdArgs.push_back("--start-group"); + // Add the object file for the CRT. std::string CrtFileName = std::string("-l:crt") + CPU + std::string(".o"); CmdArgs.push_back(Args.MakeArgString(CrtFileName)); @@ -425,6 +438,8 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Add the link library specific to the MCU. CmdArgs.push_back(Args.MakeArgString(std::string("-l") + CPU)); + CmdArgs.push_back("--end-group"); + // Specify the family name as the emulation mode to use. // This is almost always required because otherwise avr-ld // will assume 'avr2' and warn about the program being larger @@ -438,11 +453,21 @@ void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, } llvm::Optional AVRToolChain::findAVRLibcInstallation() const { + // Search avr-libc installation according to avr-gcc installation. + std::string GCCParent(GCCInstallation.getParentLibPath()); + std::string Path(GCCParent + "/avr"); + if (llvm::sys::fs::is_directory(Path)) + return Path; + Path = GCCParent + "/../avr"; + if (llvm::sys::fs::is_directory(Path)) + return Path; + + // Search avr-libc installation from possible locations, and return the first + // one that exists, if there is no avr-gcc installed. for (StringRef PossiblePath : PossibleAVRLibcLocations) { std::string Path = getDriver().SysRoot + PossiblePath.str(); - // Return the first avr-libc installation that exists. if (llvm::sys::fs::is_directory(Path)) - return Optional(Path); + return Path; } return llvm::None; diff --git a/clang/lib/Driver/ToolChains/AVR.h b/clang/lib/Driver/ToolChains/AVR.h index f612aa69118..2d027957ed7 100644 --- a/clang/lib/Driver/ToolChains/AVR.h +++ b/clang/lib/Driver/ToolChains/AVR.h @@ -11,8 +11,8 @@ #include "Gnu.h" #include "clang/Driver/InputInfo.h" -#include "clang/Driver/ToolChain.h" #include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" namespace clang { namespace driver { @@ -26,6 +26,11 @@ public: AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + protected: Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index ed8c7e94b01..0b60d097b9c 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -79,10 +79,32 @@ static bool DecodeAArch64Features(const Driver &D, StringRef text, else return false; - // +sve implies +f32mm if the base architecture is v8.6A or v8.7A - // it isn't the case in general that sve implies both f64mm and f32mm + if (Feature == "sve2") + Features.push_back("+sve"); + else if (Feature == "sve2-bitperm" || Feature == "sve2-sha3" || + Feature == "sve2-aes" || Feature == "sve2-sm4") { + Features.push_back("+sve"); + Features.push_back("+sve2"); + } else if (Feature == "nosve") { + Features.push_back("-sve2"); + Features.push_back("-sve2-bitperm"); + Features.push_back("-sve2-sha3"); + Features.push_back("-sve2-aes"); + Features.push_back("-sve2-sm4"); + } else if (Feature == "nosve2") { + Features.push_back("-sve2-bitperm"); + Features.push_back("-sve2-sha3"); + Features.push_back("-sve2-aes"); + Features.push_back("-sve2-sm4"); + } + + // +sve implies +f32mm if the base architecture is v8.6A, v8.7A, v9.1A or + // v9.2A. It isn't the case in general that sve implies both f64mm and f32mm if ((ArchKind == llvm::AArch64::ArchKind::ARMV8_6A || - ArchKind == llvm::AArch64::ArchKind::ARMV8_7A) && Feature == "sve") + ArchKind == llvm::AArch64::ArchKind::ARMV8_7A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_2A) && + Feature == "sve") Features.push_back("+f32mm"); } return true; @@ -127,8 +149,20 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); if (ArchKind == llvm::AArch64::ArchKind::INVALID || - !llvm::AArch64::getArchFeatures(ArchKind, Features) || - (Split.second.size() && + !llvm::AArch64::getArchFeatures(ArchKind, Features)) + return false; + + // Enable SVE2 by default on Armv9-A. + // It can still be disabled if +nosve2 is present. + // We must do this early so that DecodeAArch64Features has the correct state + if ((ArchKind == llvm::AArch64::ArchKind::ARMV9A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_1A || + ArchKind == llvm::AArch64::ArchKind::ARMV9_2A)) { + Features.push_back("+sve"); + Features.push_back("+sve2"); + } + + if ((Split.second.size() && !DecodeAArch64Features(D, Split.second, Features, ArchKind))) return false; @@ -210,6 +244,9 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, else if (Args.hasArg(options::OPT_arch) || isCPUDeterminedByTriple(Triple)) success = getAArch64ArchFeaturesFromMcpu( D, getAArch64TargetCPU(Args, Triple, A), Args, Features); + else + // Default to 'A' profile if the architecture is not specified. + success = getAArch64ArchFeaturesFromMarch(D, "armv8-a", Args, Features); if (success && (A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) success = @@ -345,7 +382,10 @@ fp16_fml_fallthrough: NoCrypto = true; } - if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd) { + if (std::find(ItBegin, ItEnd, "+v8.4a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9.1a") != ItEnd || + std::find(ItBegin, ItEnd, "+v9.2a") != ItEnd) { if (HasCrypto && !NoCrypto) { // Check if we have NOT disabled an algorithm with something like: // +crypto, -algorithm @@ -404,9 +444,11 @@ fp16_fml_fallthrough: } } - auto V8_6Pos = llvm::find(Features, "+v8.6a"); - if (V8_6Pos != std::end(Features)) - V8_6Pos = Features.insert(std::next(V8_6Pos), {"+i8mm", "+bf16"}); + const char *Archs[] = {"+v8.6a", "+v8.7a", "+v9.1a", "+v9.2a"}; + auto Pos = std::find_first_of(Features.begin(), Features.end(), + std::begin(Archs), std::end(Archs)); + if (Pos != std::end(Features)) + Pos = Features.insert(std::next(Pos), {"+i8mm", "+bf16"}); if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access)) { diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 4ab547fabe4..21c091e1a0b 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -148,13 +148,21 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { } // Select mode for reading thread pointer (-mtp=soft/cp15). -arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args) { +arm::ReadTPMode arm::getReadTPMode(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { arm::ReadTPMode ThreadPointer = llvm::StringSwitch(A->getValue()) .Case("cp15", ReadTPMode::Cp15) .Case("soft", ReadTPMode::Soft) .Default(ReadTPMode::Invalid); + if (ThreadPointer == ReadTPMode::Cp15 && + getARMSubArchVersionNumber(Triple) < 7 && + llvm::ARM::parseArch(Triple.getArchName()) != + llvm::ARM::ArchKind::ARMV6T2) { + D.Diag(diag::err_target_unsupported_tp_hard) << Triple.getArchName(); + return ReadTPMode::Invalid; + } if (ThreadPointer != ReadTPMode::Invalid) return ThreadPointer; if (StringRef(A->getValue()).empty()) @@ -314,6 +322,10 @@ arm::FloatABI arm::getDefaultFloatABI(const llvm::Triple &Triple) { // FIXME: this is invalid for WindowsCE case llvm::Triple::Win32: + // It is incorrect to select hard float ABI on MachO platforms if the ABI is + // "apcs-gnu". + if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple)) + return FloatABI::Soft; return FloatABI::Hard; case llvm::Triple::NetBSD: @@ -418,7 +430,7 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple, bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(D, Triple, Args); - arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args); + arm::ReadTPMode ThreadPointer = arm::getReadTPMode(D, Args, Triple); llvm::Optional> WaCPU, WaFPU, WaHDiv, WaArch; @@ -701,6 +713,18 @@ fp16_fml_fallthrough: if (Args.getLastArg(options::OPT_mcmse)) Features.push_back("+8msecext"); + if (Arg *A = Args.getLastArg(options::OPT_mfix_cmse_cve_2021_35465, + options::OPT_mno_fix_cmse_cve_2021_35465)) { + if (!Args.getLastArg(options::OPT_mcmse)) + D.Diag(diag::err_opt_not_valid_without_opt) + << A->getOption().getName() << "-mcmse"; + + if (A->getOption().matches(options::OPT_mfix_cmse_cve_2021_35465)) + Features.push_back("+fix-cmse-cve-2021-35465"); + else + Features.push_back("-fix-cmse-cve-2021-35465"); + } + // Look for the last occurrence of -mlong-calls or -mno-long-calls. If // neither options are specified, see if we are compiling for kernel/kext and // decide whether to pass "+long-calls" based on the OS and its version. @@ -763,7 +787,8 @@ fp16_fml_fallthrough: // which raises an alignment fault on unaligned accesses. Linux // defaults this bit to 0 and handles it as a system-wide (not // per-process) setting. It is therefore safe to assume that ARMv7+ - // Linux targets support unaligned accesses. The same goes for NaCl. + // Linux targets support unaligned accesses. The same goes for NaCl + // and Windows. // // The above behavior is consistent with GCC. int VersionNum = getARMSubArchVersionNumber(Triple); @@ -771,7 +796,8 @@ fp16_fml_fallthrough: if (VersionNum < 6 || Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m) Features.push_back("+strict-align"); - } else if (Triple.isOSLinux() || Triple.isOSNaCl()) { + } else if (Triple.isOSLinux() || Triple.isOSNaCl() || + Triple.isOSWindows()) { if (VersionNum < 7) Features.push_back("+strict-align"); } else @@ -845,7 +871,7 @@ fp16_fml_fallthrough: } -const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { +std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { std::string MArch; if (!Arch.empty()) MArch = std::string(Arch); diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.h b/clang/lib/Driver/ToolChains/Arch/ARM.h index 8e7c10ecd5d..b6fd68fbb9c 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.h +++ b/clang/lib/Driver/ToolChains/Arch/ARM.h @@ -24,7 +24,7 @@ namespace arm { std::string getARMTargetCPU(StringRef CPU, llvm::StringRef Arch, const llvm::Triple &Triple); -const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple); llvm::ARM::ArchKind getLLVMArchKindForARM(StringRef CPU, StringRef Arch, const llvm::Triple &Triple); @@ -53,7 +53,8 @@ FloatABI getARMFloatABI(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); void setFloatABIInTriple(const Driver &D, const llvm::opt::ArgList &Args, llvm::Triple &triple); -ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args); +ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); void setArchNameInTriple(const Driver &D, const llvm::opt::ArgList &Args, types::ID InputType, llvm::Triple &Triple); diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 5a509dbb2bd..c374d745da3 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -441,7 +441,8 @@ bool mips::isUCLibc(const ArgList &Args) { return A && A->getOption().matches(options::OPT_muclibc); } -bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { +bool mips::isNaN2008(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ)) return llvm::StringSwitch(NaNArg->getValue()) .Case("2008", true) @@ -449,7 +450,7 @@ bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) { .Default(false); // NaN2008 is the default for MIPS32r6/MIPS64r6. - return llvm::StringSwitch(getCPUName(Args, Triple)) + return llvm::StringSwitch(getCPUName(D, Args, Triple)) .Cases("mips32r6", "mips64r6", true) .Default(false); } diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.h b/clang/lib/Driver/ToolChains/Arch/Mips.h index 074012f40fe..f4c11a7e318 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -44,7 +44,8 @@ std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); bool isUCLibc(const llvm::opt::ArgList &Args); -bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +bool isNaN2008(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI); diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index ade93d6881a..323f588c826 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -7,462 +7,42 @@ //===----------------------------------------------------------------------===// #include "RISCV.h" +#include "ToolChains/CommonArgs.h" #include "clang/Basic/CharInfo.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" #include "llvm/ADT/Optional.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/RISCVISAInfo.h" #include "llvm/Support/TargetParser.h" #include "llvm/Support/raw_ostream.h" -#include "ToolChains/CommonArgs.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -namespace { -// Represents the major and version number components of a RISC-V extension -struct RISCVExtensionVersion { - StringRef Major; - StringRef Minor; -}; -} // end anonymous namespace - -static StringRef getExtensionTypeDesc(StringRef Ext) { - if (Ext.startswith("sx")) - return "non-standard supervisor-level extension"; - if (Ext.startswith("s")) - return "standard supervisor-level extension"; - if (Ext.startswith("x")) - return "non-standard user-level extension"; - if (Ext.startswith("z")) - return "standard user-level extension"; - return StringRef(); -} - -static StringRef getExtensionType(StringRef Ext) { - if (Ext.startswith("sx")) - return "sx"; - if (Ext.startswith("s")) - return "s"; - if (Ext.startswith("x")) - return "x"; - if (Ext.startswith("z")) - return "z"; - return StringRef(); -} - -// If the extension is supported as experimental, return the version of that -// extension that the compiler currently supports. -static Optional -isExperimentalExtension(StringRef Ext) { - if (Ext == "b" || Ext == "zba" || Ext == "zbb" || Ext == "zbc" || - Ext == "zbe" || Ext == "zbf" || Ext == "zbm" || Ext == "zbp" || - Ext == "zbr" || Ext == "zbs" || Ext == "zbt" || Ext == "zbproposedc") - return RISCVExtensionVersion{"0", "93"}; - if (Ext == "v" || Ext == "zvamo" || Ext == "zvlsseg") - return RISCVExtensionVersion{"0", "10"}; - if (Ext == "zfh") - return RISCVExtensionVersion{"0", "1"}; - return None; -} - -static bool isSupportedExtension(StringRef Ext) { - // LLVM supports "z" extensions which are marked as experimental. - if (isExperimentalExtension(Ext)) - return true; - - // LLVM does not support "sx", "s" nor "x" extensions. - return false; -} - -// Extensions may have a version number, and may be separated by -// an underscore '_' e.g.: rv32i2_m2. -// Version number is divided into major and minor version numbers, -// separated by a 'p'. If the minor version is 0 then 'p0' can be -// omitted from the version string. E.g., rv32i2p0, rv32i2, rv32i2p1. -static bool getExtensionVersion(const Driver &D, const ArgList &Args, - StringRef MArch, StringRef Ext, StringRef In, - std::string &Major, std::string &Minor) { - Major = std::string(In.take_while(isDigit)); - In = In.substr(Major.size()); - - if (Major.size() && In.consume_front("p")) { - Minor = std::string(In.take_while(isDigit)); - In = In.substr(Major.size() + 1); - - // Expected 'p' to be followed by minor version number. - if (Minor.empty()) { - std::string Error = - "minor version number missing after 'p' for extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - } - - // Expected multi-character extension with version number to have no - // subsequent characters (i.e. must either end string or be followed by - // an underscore). - if (Ext.size() > 1 && In.size()) { - std::string Error = - "multi-character extensions must be separated by underscores"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << In; - return false; - } - - // If experimental extension, require use of current version number number - if (auto ExperimentalExtension = isExperimentalExtension(Ext)) { - if (!Args.hasArg(options::OPT_menable_experimental_extensions)) { - std::string Error = - "requires '-menable-experimental-extensions' for experimental extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } else if (Major.empty() && Minor.empty()) { - std::string Error = - "experimental extension requires explicit version number"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - auto SupportedVers = *ExperimentalExtension; - if (Major != SupportedVers.Major || Minor != SupportedVers.Minor) { - std::string Error = - "unsupported version number " + Major; - if (!Minor.empty()) - Error += "." + Minor; - Error += " for experimental extension (this compiler supports " - + SupportedVers.Major.str() + "." - + SupportedVers.Minor.str() + ")"; - - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return false; - } - return true; - } - - // Allow extensions to declare no version number - if (Major.empty() && Minor.empty()) - return true; - - // TODO: Handle supported extensions with version number. - std::string Error = "unsupported version number " + Major; - if (!Minor.empty()) - Error += "." + Minor; - Error += " for extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) << MArch << Error << Ext; - - return false; -} - -// Handle other types of extensions other than the standard -// general purpose and standard user-level extensions. -// Parse the ISA string containing non-standard user-level -// extensions, standard supervisor-level extensions and -// non-standard supervisor-level extensions. -// These extensions start with 'z', 'x', 's', 'sx' prefixes, follow a -// canonical order, might have a version number (major, minor) -// and are separated by a single underscore '_'. -// Set the hardware features for the extensions that are supported. -static void getExtensionFeatures(const Driver &D, - const ArgList &Args, - std::vector &Features, - StringRef &MArch, StringRef &Exts) { - if (Exts.empty()) - return; - - // Multi-letter extensions are seperated by a single underscore - // as described in RISC-V User-Level ISA V2.2. - SmallVector Split; - Exts.split(Split, StringRef("_")); - - SmallVector Prefix{"z", "x", "s", "sx"}; - auto I = Prefix.begin(); - auto E = Prefix.end(); - - SmallVector AllExts; - - for (StringRef Ext : Split) { - if (Ext.empty()) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch - << "extension name missing after separator '_'"; - return; - } - - StringRef Type = getExtensionType(Ext); - StringRef Desc = getExtensionTypeDesc(Ext); - auto Pos = Ext.find_if(isDigit); - StringRef Name(Ext.substr(0, Pos)); - StringRef Vers(Ext.substr(Pos)); - - if (Type.empty()) { - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << "invalid extension prefix" << Ext; - return; - } - - // Check ISA extensions are specified in the canonical order. - while (I != E && *I != Type) - ++I; - - if (I == E) { - std::string Error = std::string(Desc); - Error += " not given in canonical order"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return; - } - - // The order is OK, do not advance I to the next prefix - // to allow repeated extension type, e.g.: rv32ixabc_xdef. - - if (Name.size() == Type.size()) { - std::string Error = std::string(Desc); - Error += " name missing after"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Type; - return; - } - - std::string Major, Minor; - if (!getExtensionVersion(D, Args, MArch, Name, Vers, Major, Minor)) - return; - - // Check if duplicated extension. - if (llvm::is_contained(AllExts, Name)) { - std::string Error = "duplicated "; - Error += Desc; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Name; - return; - } - - // Extension format is correct, keep parsing the extensions. - // TODO: Save Type, Name, Major, Minor to avoid parsing them later. - AllExts.push_back(Name); - } - - // Set target features. - // TODO: Hardware features to be handled in Support/TargetParser.cpp. - // TODO: Use version number when setting target features. - for (auto Ext : AllExts) { - if (!isSupportedExtension(Ext)) { - StringRef Desc = getExtensionTypeDesc(getExtensionType(Ext)); - std::string Error = "unsupported "; - Error += Desc; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << Ext; - return; - } - if (Ext == "zvlsseg") { - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - } else if (Ext == "zvamo") { - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - Features.push_back("+experimental-zvamo"); - } else if (isExperimentalExtension(Ext)) - Features.push_back(Args.MakeArgString("+experimental-" + Ext)); - else - Features.push_back(Args.MakeArgString("+" + Ext)); - } -} - // Returns false if an error is diagnosed. -static bool getArchFeatures(const Driver &D, StringRef MArch, +static bool getArchFeatures(const Driver &D, StringRef Arch, std::vector &Features, const ArgList &Args) { - // RISC-V ISA strings must be lowercase. - if (llvm::any_of(MArch, [](char c) { return isupper(c); })) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "string must be lowercase"; + bool EnableExperimentalExtensions = + Args.hasArg(options::OPT_menable_experimental_extensions); + auto ISAInfo = + llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions); + if (!ISAInfo) { + handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) { + D.Diag(diag::err_drv_invalid_riscv_arch_name) + << Arch << ErrMsg.getMessage(); + }); + return false; } - // ISA string must begin with rv32 or rv64. - if (!(MArch.startswith("rv32") || MArch.startswith("rv64")) || - (MArch.size() < 5)) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "string must begin with rv32{i,e,g} or rv64{i,g}"; - return false; - } - - bool HasRV64 = MArch.startswith("rv64"); - - // The canonical order specified in ISA manual. - // Ref: Table 22.1 in RISC-V User-Level ISA V2.2 - StringRef StdExts = "mafdqlcbjtpvn"; - bool HasF = false, HasD = false; - char Baseline = MArch[4]; - - // First letter should be 'e', 'i' or 'g'. - switch (Baseline) { - default: - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "first letter should be 'e', 'i' or 'g'"; - return false; - case 'e': { - StringRef Error; - // Currently LLVM does not support 'e'. - // Extension 'e' is not allowed in rv64. - if (HasRV64) - Error = "standard user-level extension 'e' requires 'rv32'"; - else - Error = "unsupported standard user-level extension 'e'"; - D.Diag(diag::err_drv_invalid_riscv_arch_name) << MArch << Error; - return false; - } - case 'i': - break; - case 'g': - // g = imafd - StdExts = StdExts.drop_front(4); - Features.push_back("+m"); - Features.push_back("+a"); - Features.push_back("+f"); - Features.push_back("+d"); - HasF = true; - HasD = true; - break; - } - - // Skip rvxxx - StringRef Exts = MArch.substr(5); - - // Remove multi-letter standard extensions, non-standard extensions and - // supervisor-level extensions. They have 'z', 'x', 's', 'sx' prefixes. - // Parse them at the end. - // Find the very first occurrence of 's', 'x' or 'z'. - StringRef OtherExts; - size_t Pos = Exts.find_first_of("zsx"); - if (Pos != StringRef::npos) { - OtherExts = Exts.substr(Pos); - Exts = Exts.substr(0, Pos); - } - - std::string Major, Minor; - if (!getExtensionVersion(D, Args, MArch, std::string(1, Baseline), Exts, - Major, Minor)) - return false; - - // Consume the base ISA version number and any '_' between rvxxx and the - // first extension - Exts = Exts.drop_front(Major.size()); - if (!Minor.empty()) - Exts = Exts.drop_front(Minor.size() + 1 /*'p'*/); - Exts.consume_front("_"); - - // TODO: Use version number when setting target features - - auto StdExtsItr = StdExts.begin(); - auto StdExtsEnd = StdExts.end(); - - for (auto I = Exts.begin(), E = Exts.end(); I != E; ) { - char c = *I; - - // Check ISA extensions are specified in the canonical order. - while (StdExtsItr != StdExtsEnd && *StdExtsItr != c) - ++StdExtsItr; - - if (StdExtsItr == StdExtsEnd) { - // Either c contains a valid extension but it was not given in - // canonical order or it is an invalid extension. - StringRef Error; - if (StdExts.contains(c)) - Error = "standard user-level extension not given in canonical order"; - else - Error = "invalid standard user-level extension"; - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << Error << std::string(1, c); - return false; - } - - // Move to next char to prevent repeated letter. - ++StdExtsItr; - - std::string Next, Major, Minor; - if (std::next(I) != E) - Next = std::string(std::next(I), E); - if (!getExtensionVersion(D, Args, MArch, std::string(1, c), Next, Major, - Minor)) - return false; - - // The order is OK, then push it into features. - // TODO: Use version number when setting target features - switch (c) { - default: - // Currently LLVM supports only "mafdc". - D.Diag(diag::err_drv_invalid_riscv_ext_arch_name) - << MArch << "unsupported standard user-level extension" - << std::string(1, c); - return false; - case 'm': - Features.push_back("+m"); - break; - case 'a': - Features.push_back("+a"); - break; - case 'f': - Features.push_back("+f"); - HasF = true; - break; - case 'd': - Features.push_back("+d"); - HasD = true; - break; - case 'c': - Features.push_back("+c"); - break; - case 'b': - Features.push_back("+experimental-b"); - Features.push_back("+experimental-zba"); - Features.push_back("+experimental-zbb"); - Features.push_back("+experimental-zbc"); - Features.push_back("+experimental-zbe"); - Features.push_back("+experimental-zbf"); - Features.push_back("+experimental-zbm"); - Features.push_back("+experimental-zbp"); - Features.push_back("+experimental-zbr"); - Features.push_back("+experimental-zbs"); - Features.push_back("+experimental-zbt"); - break; - case 'v': - Features.push_back("+experimental-v"); - Features.push_back("+experimental-zvlsseg"); - break; - } - - // Consume full extension name and version, including any optional '_' - // between this extension and the next - ++I; - I += Major.size(); - if (Minor.size()) - I += Minor.size() + 1 /*'p'*/; - if (*I == '_') - ++I; - } - - // Dependency check. - // It's illegal to specify the 'd' (double-precision floating point) - // extension without also specifying the 'f' (single precision - // floating-point) extension. - if (HasD && !HasF) { - D.Diag(diag::err_drv_invalid_riscv_arch_name) - << MArch << "d requires f extension to also be specified"; - return false; - } - - // Additional dependency checks. - // TODO: The 'q' extension requires rv64. - // TODO: It is illegal to specify 'e' extensions with 'f' and 'd'. - - // Handle all other types of extensions. - getExtensionFeatures(D, Args, Features, MArch, OtherExts); - + (*ISAInfo)->toFeatures( + Features, [&Args](const Twine &Str) { return Args.MakeArgString(Str); }); return true; } @@ -610,24 +190,30 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { // rv32* -> ilp32 // rv64g | rv64*d -> lp64d // rv64* -> lp64 - StringRef MArch = getRISCVArch(Args, Triple); + StringRef Arch = getRISCVArch(Args, Triple); - if (MArch.startswith_insensitive("rv32")) { - // FIXME: parse `March` to find `D` extension properly - if (MArch.substr(4).contains_insensitive("d") || - MArch.startswith_insensitive("rv32g")) - return "ilp32d"; - else if (MArch.startswith_insensitive("rv32e")) - return "ilp32e"; - else + auto ParseResult = llvm::RISCVISAInfo::parseArchString( + Arch, /* EnableExperimentalExtension */ true); + if (!ParseResult) { + // Ignore parsing error, just go 3rd step. + consumeError(ParseResult.takeError()); + } else { + auto &ISAInfo = *ParseResult; + bool HasD = ISAInfo->hasExtension("d"); + unsigned XLen = ISAInfo->getXLen(); + if (XLen == 32) { + bool HasE = ISAInfo->hasExtension("e"); + if (HasD) + return "ilp32d"; + if (HasE) + return "ilp32e"; return "ilp32"; - } else if (MArch.startswith_insensitive("rv64")) { - // FIXME: parse `March` to find `D` extension properly - if (MArch.substr(4).contains_insensitive("d") || - MArch.startswith_insensitive("rv64g")) - return "lp64d"; - else + } else if (XLen == 64) { + if (HasD) + return "lp64d"; return "lp64"; + } + llvm_unreachable("unhandled XLen"); } // 3. Choose a default based on the triple diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 12749c7ec87..bfa008f964e 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -11,6 +11,8 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Host.h" @@ -20,7 +22,7 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -std::string x86::getX86TargetCPU(const ArgList &Args, +std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args, const llvm::Triple &Triple) { if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { StringRef CPU = A->getValue(); @@ -37,29 +39,34 @@ std::string x86::getX86TargetCPU(const ArgList &Args, return std::string(CPU); } - if (const Arg *A = Args.getLastArgNoClaim(options::OPT__SLASH_arch)) { + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) { // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap(). - StringRef Arch = A->getValue(); - StringRef CPU; - if (Triple.getArch() == llvm::Triple::x86) { // 32-bit-only /arch: flags. - CPU = llvm::StringSwitch(Arch) - .Case("IA32", "i386") - .Case("SSE", "pentium3") - .Case("SSE2", "pentium4") - .Default(""); + // The keys are case-sensitive; this matches link.exe. + // 32-bit and 64-bit /arch: flags. + llvm::StringMap ArchMap({ + {"AVX", "sandybridge"}, + {"AVX2", "haswell"}, + {"AVX512F", "knl"}, + {"AVX512", "skylake-avx512"}, + }); + if (Triple.getArch() == llvm::Triple::x86) { + // 32-bit-only /arch: flags. + ArchMap.insert({ + {"IA32", "i386"}, + {"SSE", "pentium3"}, + {"SSE2", "pentium4"}, + }); } - if (CPU.empty()) { // 32-bit and 64-bit /arch: flags. - CPU = llvm::StringSwitch(Arch) - .Case("AVX", "sandybridge") - .Case("AVX2", "haswell") - .Case("AVX512F", "knl") - .Case("AVX512", "skylake-avx512") - .Default(""); - } - if (!CPU.empty()) { - A->claim(); - return std::string(CPU); + StringRef CPU = ArchMap.lookup(A->getValue()); + if (CPU.empty()) { + std::vector ValidArchs{ArchMap.keys().begin(), + ArchMap.keys().end()}; + sort(ValidArchs); + D.Diag(diag::warn_drv_invalid_arch_name_with_suggestion) + << A->getValue() << (Triple.getArch() == llvm::Triple::x86) + << join(ValidArchs, ", "); } + return std::string(CPU); } // Select the default CPU if none was given (or detection failed). diff --git a/clang/lib/Driver/ToolChains/Arch/X86.h b/clang/lib/Driver/ToolChains/Arch/X86.h index 14f0a26c8be..36a2ab52899 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.h +++ b/clang/lib/Driver/ToolChains/Arch/X86.h @@ -21,7 +21,7 @@ namespace driver { namespace tools { namespace x86 { -std::string getX86TargetCPU(const llvm::opt::ArgList &Args, +std::string getX86TargetCPU(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple); void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp index ce73e39d145..cd07692be35 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -125,6 +125,20 @@ static bool isARMBareMetal(const llvm::Triple &Triple) { return true; } +/// Is the triple aarch64-none-elf? +static bool isAArch64BareMetal(const llvm::Triple &Triple) { + if (Triple.getArch() != llvm::Triple::aarch64) + return false; + + if (Triple.getVendor() != llvm::Triple::UnknownVendor) + return false; + + if (Triple.getOS() != llvm::Triple::UnknownOS) + return false; + + return Triple.getEnvironmentName() == "elf"; +} + static bool isRISCVBareMetal(const llvm::Triple &Triple) { if (Triple.getArch() != llvm::Triple::riscv32 && Triple.getArch() != llvm::Triple::riscv64) @@ -151,7 +165,8 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, } bool BareMetal::handlesTarget(const llvm::Triple &Triple) { - return isARMBareMetal(Triple) || isRISCVBareMetal(Triple); + return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) || + isRISCVBareMetal(Triple); } Tool *BareMetal::buildLinker() const { diff --git a/clang/lib/Driver/ToolChains/BareMetal.h b/clang/lib/Driver/ToolChains/BareMetal.h index d68c43c64c9..dc718e09ad4 100644 --- a/clang/lib/Driver/ToolChains/BareMetal.h +++ b/clang/lib/Driver/ToolChains/BareMetal.h @@ -42,7 +42,9 @@ public: bool useIntegratedAs() const override { return true; } bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index a4b53a640ab..e5476e07a5c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -22,6 +22,7 @@ #include "Hexagon.h" #include "MSP430.h" #include "PS4CPU.h" +#include "clang/Basic/CLWarnings.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" @@ -612,7 +613,8 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); bool OmitLeafFP = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, options::OPT_mno_omit_leaf_frame_pointer, - Triple.isAArch64() || Triple.isPS4CPU()); + Triple.isAArch64() || Triple.isPS4CPU() || + Triple.isVE()); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (OmitLeafFP) @@ -643,7 +645,7 @@ static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgString for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else @@ -658,7 +660,7 @@ static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fmacro_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else @@ -673,7 +675,7 @@ static void addCoveragePrefixMapArg(const Driver &D, const ArgList &Args, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fcoverage_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else @@ -748,7 +750,7 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, const Driver &D, const InputInfo &Output, - const ArgList &Args, + const ArgList &Args, SanitizerArgs &SanArgs, ArgStringList &CmdArgs) { auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, @@ -795,11 +797,6 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, } if (TC.getTriple().isOSAIX()) { - if (PGOGenerateArg) - if (!D.isUsingLTO(false /*IsDeviceOffloadAction */) || - D.getLTOMode() != LTOK_Full) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << PGOGenerateArg->getSpelling() << "-flto"; if (ProfileGenerateArg) D.Diag(diag::err_drv_unsupported_opt_for_target) << ProfileGenerateArg->getSpelling() << TC.getTriple().str(); @@ -927,7 +924,7 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, else if (Val != "single") D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; - } else if (TC.getSanitizerArgs().needsTsanRt()) { + } else if (SanArgs.needsTsanRt()) { CmdArgs.push_back("-fprofile-update=atomic"); } @@ -1256,7 +1253,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // If we are offloading to a target via OpenMP we need to include the // openmp_wrappers folder which contains alternative system headers. if (JA.isDeviceOffloading(Action::OFK_OpenMP) && - getToolChain().getTriple().isNVPTX()){ + (getToolChain().getTriple().isNVPTX() || + getToolChain().getTriple().isAMDGCN())) { if (!Args.hasArg(options::OPT_nobuiltininc)) { // Add openmp_wrappers/* to our system include path. This lets us wrap // standard library headers. @@ -1587,8 +1585,8 @@ void AddAAPCSVolatileBitfieldArgs(const ArgList &Args, ArgStringList &CmdArgs) { } namespace { -void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, - ArgStringList &CmdArgs) { +void RenderARMABI(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs) { // Select the ABI to use. // FIXME: Support -meabi. // FIXME: Parts of this are duplicated in the backend, unify this somehow. @@ -1596,7 +1594,7 @@ void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { ABIName = A->getValue(); } else { - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false); ABIName = llvm::ARM::computeDefaultTargetABI(Triple, CPU).data(); } @@ -1607,7 +1605,7 @@ void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { - RenderARMABI(Triple, Args, CmdArgs); + RenderARMABI(getToolChain().getDriver(), Triple, Args, CmdArgs); // Determine floating point ABI from the options & target defaults. arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); @@ -1825,17 +1823,46 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, StringRef Val = A->getValue(); const Driver &D = getToolChain().getDriver(); if (Val.equals("128") || Val.equals("256") || Val.equals("512") || - Val.equals("1024") || Val.equals("2048")) + Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || + Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || + Val.equals("2048+")) { + unsigned Bits = 0; + if (Val.endswith("+")) + Val = Val.substr(0, Val.size() - 1); + else { + bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + assert(!Invalid && "Failed to parse value"); + CmdArgs.push_back( + Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); + } + + bool Invalid = Val.getAsInteger(10, Bits); (void)Invalid; + assert(!Invalid && "Failed to parse value"); CmdArgs.push_back( - Args.MakeArgString(llvm::Twine("-msve-vector-bits=") + Val)); + Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); // Silently drop requests for vector-length agnostic code as it's implied. - else if (!Val.equals("scalable")) + } else if (!Val.equals("scalable")) // Handle the unsupported values passed to msve-vector-bits. D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } AddAAPCSVolatileBitfieldArgs(Args, CmdArgs); + + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ)) { + StringRef Name = A->getValue(); + + std::string TuneCPU; + if (Name == "native") + TuneCPU = std::string(llvm::sys::getHostCPUName()); + else + TuneCPU = std::string(Name); + + if (!TuneCPU.empty()) { + CmdArgs.push_back("-tune-cpu"); + CmdArgs.push_back(Args.MakeArgString(TuneCPU)); + } + } } void Clang::AddMIPSTargetArgs(const ArgList &Args, @@ -2173,6 +2200,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, if (Value == "intel" || Value == "att") { CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + CmdArgs.push_back(Args.MakeArgString("-inline-asm=" + Value)); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -2182,6 +2210,11 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back("-x86-asm-syntax=intel"); } + if (Arg *A = Args.getLastArg(options::OPT_mskip_rax_setup, + options::OPT_mno_skip_rax_setup)) + if (A->getOption().matches(options::OPT_mskip_rax_setup)) + CmdArgs.push_back(Args.MakeArgString("-mskip-rax-setup")); + // Set flags to support MCU ABI. if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { CmdArgs.push_back("-mfloat-abi"); @@ -2411,7 +2444,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, bool TakeNextArg = false; bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); - bool UseNoExecStack = C.getDefaultToolChain().isNoExecStackDefault(); + bool UseNoExecStack = false; const char *MipsTargetFeature = nullptr; StringRef ImplicitIt; for (const Arg *A : @@ -2617,6 +2650,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // LLVM flags based on the final state. bool HonorINFs = true; bool HonorNaNs = true; + bool ApproxFunc = false; // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = TC.IsMathErrnoDefault(); bool AssociativeMath = false; @@ -2638,10 +2672,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath; llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math; - StringRef FPContract = "on"; + // CUDA and HIP don't rely on the frontend to pass an ffp-contract option. + // If one wasn't given by the user, don't pass it here. + StringRef FPContract; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) + FPContract = "on"; bool StrictFPModel = false; - if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); CmdArgs.push_back(A->getValue()); @@ -2685,12 +2723,12 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, // Use the gcc option in the switch below. if (!FPModel.empty() && !FPModel.equals(Val)) D.Diag(clang::diag::warn_drv_overriding_flag_option) - << Args.MakeArgString("-ffp-model=" + FPModel) - << Args.MakeArgString("-ffp-model=" + Val); + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); if (Val.equals("fast")) { optID = options::OPT_ffast_math; FPModel = Val; - FPContract = Val; + FPContract = "fast"; } else if (Val.equals("precise")) { optID = options::OPT_ffp_contract; FPModel = Val; @@ -2719,6 +2757,8 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fno_honor_infinities: HonorINFs = false; break; case options::OPT_fhonor_nans: HonorNaNs = true; break; case options::OPT_fno_honor_nans: HonorNaNs = false; break; + case options::OPT_fapprox_func: ApproxFunc = true; break; + case options::OPT_fno_approx_func: ApproxFunc = false; break; case options::OPT_fmath_errno: MathErrno = true; break; case options::OPT_fno_math_errno: MathErrno = false; break; case options::OPT_fassociative_math: AssociativeMath = true; break; @@ -2780,11 +2820,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_ffp_contract: { StringRef Val = A->getValue(); if (PreciseFPModel) { - // When -ffp-model=precise is seen on the command line, - // the boolean PreciseFPModel is set to true which indicates - // "the current option is actually PreciseFPModel". The optID - // is changed to OPT_ffp_contract and FPContract is set to "on". - // the argument Val string is "precise": it shouldn't be checked. + // -ffp-model=precise enables ffp-contract=on. + // -ffp-model=precise sets PreciseFPModel to on and Val to + // "precise". FPContract is set. ; } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; @@ -2877,12 +2915,17 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; - TrappingMath = false; - RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = DefaultDenormalFPMath; DenormalFP32Math = llvm::DenormalMode::getIEEE(); - FPContract = "on"; + if (!JA.isDeviceOffloading(Action::OFK_Cuda) && + !JA.isOffloading(Action::OFK_HIP)) + if (FPContract == "fast") { + FPContract = "on"; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-contract=fast" + << "-ffp-contract=on"; + } break; } if (StrictFPModel) { @@ -2915,6 +2958,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!HonorNaNs) CmdArgs.push_back("-menable-no-nans"); + if (ApproxFunc) + CmdArgs.push_back("-fapprox-func"); + if (MathErrno) CmdArgs.push_back("-fmath-errno"); @@ -3128,14 +3174,44 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, const std::string &TripleStr = EffectiveTriple.getTriple(); if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; - if (EffectiveTriple.isX86() && Value != "tls" && Value != "global") { + if ((EffectiveTriple.isX86() || EffectiveTriple.isARM() || + EffectiveTriple.isThumb()) && + Value != "tls" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "tls global"; return; } + if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && + Value == "tls") { + if (!Args.hasArg(options::OPT_mstack_protector_guard_offset_EQ)) { + D.Diag(diag::err_drv_ssp_missing_offset_argument) + << A->getAsString(Args); + return; + } + // Check whether the target subarch supports the hardware TLS register + if (arm::getARMSubArchVersionNumber(EffectiveTriple) < 7 && + llvm::ARM::parseArch(EffectiveTriple.getArchName()) != + llvm::ARM::ArchKind::ARMV6T2) { + D.Diag(diag::err_target_unsupported_tp_hard) + << EffectiveTriple.getArchName(); + return; + } + // Check whether the user asked for something other than -mtp=cp15 + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { + StringRef Value = A->getValue(); + if (Value != "cp15") { + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-mstack-protector-guard=tls"; + return; + } + } + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+read-tp-hard"); + } if (EffectiveTriple.isAArch64() && Value != "sysreg" && Value != "global") { D.Diag(diag::err_drv_invalid_value_with_suggestion) << A->getOption().getName() << Value << "sysreg global"; @@ -3146,7 +3222,8 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, if (Arg *A = Args.getLastArg(options::OPT_mstack_protector_guard_offset_EQ)) { StringRef Value = A->getValue(); - if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64()) + if (!EffectiveTriple.isX86() && !EffectiveTriple.isAArch64() && + !EffectiveTriple.isARM() && !EffectiveTriple.isThumb()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; int Offset; @@ -3154,6 +3231,12 @@ static void RenderSSPOptions(const Driver &D, const ToolChain &TC, D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; return; } + if ((EffectiveTriple.isARM() || EffectiveTriple.isThumb()) && + (Offset < 0 || Offset > 0xfffff)) { + D.Diag(diag::err_drv_invalid_int_value) + << A->getOption().getName() << Value; + return; + } A->render(Args, CmdArgs); } @@ -3179,7 +3262,7 @@ static void RenderSCPOptions(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); - if (!EffectiveTriple.isOSLinux()) + if (!EffectiveTriple.isOSFreeBSD() && !EffectiveTriple.isOSLinux()) return; if (!EffectiveTriple.isX86() && !EffectiveTriple.isSystemZ() && @@ -3354,7 +3437,7 @@ static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_allowlist_dir_path); } } @@ -3554,11 +3637,11 @@ static void RenderModulesOptions(Compilation &C, const Driver &D, llvm::sys::fs::file_status Status; if (llvm::sys::fs::status(A->getValue(), Status)) D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back( - Args.MakeArgString("-fbuild-session-timestamp=" + - Twine((uint64_t)Status.getLastModificationTime() - .time_since_epoch() - .count()))); + CmdArgs.push_back(Args.MakeArgString( + "-fbuild-session-timestamp=" + + Twine((uint64_t)std::chrono::duration_cast( + Status.getLastModificationTime().time_since_epoch()) + .count()))); } if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { @@ -3873,12 +3956,6 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, ArgStringList &CmdArgs, codegenoptions::DebugInfoKind &DebugInfoKind, DwarfFissionKind &DwarfFission) { - // These two forms of profiling info can't be used together. - if (const Arg *A1 = Args.getLastArg(options::OPT_fpseudo_probe_for_profiling)) - if (const Arg *A2 = Args.getLastArg(options::OPT_fdebug_info_for_profiling)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A1->getAsString(Args) << A2->getAsString(Args); - if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, options::OPT_fno_debug_info_for_profiling, false) && checkDebugInfoOption( @@ -4132,6 +4209,29 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, options::OPT_gpubnames) ? "-gpubnames" : "-ggnu-pubnames"); + const auto *SimpleTemplateNamesArg = + Args.getLastArg(options::OPT_gsimple_template_names, options::OPT_gno_simple_template_names, + options::OPT_gsimple_template_names_EQ); + bool ForwardTemplateParams = DebuggerTuning == llvm::DebuggerKind::SCE; + if (SimpleTemplateNamesArg && + checkDebugInfoOption(SimpleTemplateNamesArg, Args, D, TC)) { + const auto &Opt = SimpleTemplateNamesArg->getOption(); + if (Opt.matches(options::OPT_gsimple_template_names)) { + ForwardTemplateParams = true; + CmdArgs.push_back("-gsimple-template-names=simple"); + } else if (Opt.matches(options::OPT_gsimple_template_names_EQ)) { + ForwardTemplateParams = true; + StringRef Value = SimpleTemplateNamesArg->getValue(); + if (Value == "simple") { + CmdArgs.push_back("-gsimple-template-names=simple"); + } else if (Value == "mangled") { + CmdArgs.push_back("-gsimple-template-names=mangled"); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << Opt.getName() << SimpleTemplateNamesArg->getValue(); + } + } + } if (Args.hasFlag(options::OPT_fdebug_ranges_base_address, options::OPT_fno_debug_ranges_base_address, false)) { @@ -4178,7 +4278,7 @@ static void renderDebugOptions(const ToolChain &TC, const Driver &D, // Decide how to render forward declarations of template instantiations. // SCE wants full descriptions, others just get them in the name. - if (DebuggerTuning == llvm::DebuggerKind::SCE) + if (ForwardTemplateParams) CmdArgs.push_back("-debug-forward-template-params"); // Do we need to explicitly import anonymous namespaces into the parent @@ -4360,7 +4460,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.addClangWarningOptions(CmdArgs); // FIXME: Subclass ToolChain for SPIR and move this to addClangWarningOptions. - if (Triple.isSPIR()) + if (Triple.isSPIR() || Triple.isSPIRV()) CmdArgs.push_back("-Wspir-compat"); // Select the appropriate action. @@ -4478,28 +4578,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-llvm-uselists"); if (IsUsingLTO) { - if (!IsDeviceOffloadAction) { - if (Args.hasArg(options::OPT_flto)) - CmdArgs.push_back("-flto"); - else { - if (D.getLTOMode() == LTOK_Thin) - CmdArgs.push_back("-flto=thin"); - else - CmdArgs.push_back("-flto=full"); - } - CmdArgs.push_back("-flto-unit"); - } else if (Triple.isAMDGPU()) { - // Only AMDGPU supports device-side LTO - assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); - CmdArgs.push_back(Args.MakeArgString( - Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); - CmdArgs.push_back("-flto-unit"); - } else { + // Only AMDGPU supports device-side LTO. + if (IsDeviceOffloadAction && !Triple.isAMDGPU()) { D.Diag(diag::err_drv_unsupported_opt_for_target) << Args.getLastArg(options::OPT_foffload_lto, options::OPT_foffload_lto_EQ) ->getAsString(Args) << Triple.getTriple(); + } else { + assert(LTOMode == LTOK_Full || LTOMode == LTOK_Thin); + CmdArgs.push_back(Args.MakeArgString( + Twine("-flto=") + (LTOMode == LTOK_Thin ? "thin" : "full"))); + CmdArgs.push_back("-flto-unit"); } } } @@ -4537,7 +4627,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // reject options that shouldn't be supported in bitcode // also reject kernel/kext - static const constexpr unsigned kBitcodeOptionBlacklist[] = { + static const constexpr unsigned kBitcodeOptionIgnorelist[] = { options::OPT_mkernel, options::OPT_fapple_kext, options::OPT_ffunction_sections, @@ -4581,8 +4671,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_mllvm, }; for (const auto &A : Args) - if (llvm::find(kBitcodeOptionBlacklist, A->getOption().getID()) != - std::end(kBitcodeOptionBlacklist)) + if (llvm::is_contained(kBitcodeOptionIgnorelist, A->getOption().getID())) D.Diag(diag::err_drv_unsupported_embed_bitcode) << A->getSpelling(); // Render the CodeGen options that need to be passed. @@ -4599,7 +4688,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumbeb: - RenderARMABI(Triple, Args, CmdArgs); + RenderARMABI(D, Triple, Args, CmdArgs); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_32: @@ -4650,6 +4739,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // cleanup. if (!C.isForDiagnostics()) CmdArgs.push_back("-disable-free"); + CmdArgs.push_back("-clear-ast-before-backend"); #ifdef NDEBUG const bool IsAssertBuild = false; @@ -4665,10 +4755,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_fdiscard_value_names, options::OPT_fno_discard_value_names, !IsAssertBuild)) { if (Args.hasArg(options::OPT_fdiscard_value_names) && - (std::any_of(Inputs.begin(), Inputs.end(), - [](const clang::driver::InputInfo &II) { - return types::isLLVMIR(II.getType()); - }))) { + llvm::any_of(Inputs, [](const clang::driver::InputInfo &II) { + return types::isLLVMIR(II.getType()); + })) { D.Diag(diag::warn_ignoring_fdiscard_for_bitcode); } CmdArgs.push_back("-discard-value-names"); @@ -4721,6 +4810,22 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::to_string(FunctionAlignment))); } + // We support -falign-loops=N where N is a power of 2. GCC supports more + // forms. + if (const Arg *A = Args.getLastArg(options::OPT_falign_loops_EQ)) { + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 65536) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + else if (Value & (Value - 1)) + TC.getDriver().Diag(diag::err_drv_alignment_not_power_of_two) + << A->getAsString(Args) << A->getValue(); + // Treat =0 as unspecified (use the target preference). + if (Value) + CmdArgs.push_back(Args.MakeArgString("-falign-loops=" + + Twine(std::min(Value, 65536u)))); + } + llvm::Reloc::Model RelocationModel; unsigned PICLevel; bool IsPIE; @@ -5062,9 +5167,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Enable -mconstructor-aliases except on darwin, where we have to work around - // a linker bug (see ), and CUDA/AMDGPU device code, - // where aliases aren't supported. - if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX() && !RawTriple.isAMDGPU()) + // a linker bug (see ), and CUDA device code, where + // aliases aren't supported. + if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we @@ -5102,16 +5207,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. - bool UnwindTables = - Args.hasFlag(options::OPT_fasynchronous_unwind_tables, - options::OPT_fno_asynchronous_unwind_tables, - (TC.IsUnwindTablesDefault(Args) || - TC.getSanitizerArgs().needsUnwindTables()) && - !Freestanding); - UnwindTables = Args.hasFlag(options::OPT_funwind_tables, - options::OPT_fno_unwind_tables, UnwindTables); - if (UnwindTables) - CmdArgs.push_back("-munwind-tables"); + auto SanitizeArgs = TC.getSanitizerArgs(Args); + bool AsyncUnwindTables = Args.hasFlag( + options::OPT_fasynchronous_unwind_tables, + options::OPT_fno_asynchronous_unwind_tables, + (TC.IsUnwindTablesDefault(Args) || SanitizeArgs.needsUnwindTables()) && + !Freestanding); + bool UnwindTables = Args.hasFlag(options::OPT_funwind_tables, + options::OPT_fno_unwind_tables, false); + if (AsyncUnwindTables) + CmdArgs.push_back("-funwind-tables=2"); + else if (UnwindTables) + CmdArgs.push_back("-funwind-tables=1"); // Prepare `-aux-target-cpu` and `-aux-target-feature` unless // `--gpu-use-aux-triple-only` is specified. @@ -5120,7 +5227,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &HostArgs = C.getArgsForToolChain(nullptr, StringRef(), Action::OFK_None); std::string HostCPU = - getCPUName(HostArgs, *TC.getAuxTriple(), /*FromAs*/ false); + getCPUName(D, HostArgs, *TC.getAuxTriple(), /*FromAs*/ false); if (!HostCPU.empty()) { CmdArgs.push_back("-aux-target-cpu"); CmdArgs.push_back(Args.MakeArgString(HostCPU)); @@ -5162,7 +5269,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -5346,7 +5453,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // for sampling, overhead of call arc collection is way too high and there's // no way to collect the output. if (!Triple.isNVPTX() && !Triple.isAMDGCN()) - addPGOAndCoverageFlags(TC, C, D, Output, Args, CmdArgs); + addPGOAndCoverageFlags(TC, C, D, Output, Args, SanitizeArgs, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_fclang_abi_compat_EQ); @@ -5354,7 +5461,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (RawTriple.isPS4CPU() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { PS4cpu::addProfileRTArgs(TC, Args, CmdArgs); - PS4cpu::addSanitizerArgs(TC, CmdArgs); + PS4cpu::addSanitizerArgs(TC, Args, CmdArgs); } // Pass options for controlling the default header search paths. @@ -5416,7 +5523,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_R_Group); - Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + for (const Arg *A : + Args.filtered(options::OPT_W_Group, options::OPT__SLASH_wd)) { + A->claim(); + if (A->getOption().getID() == options::OPT__SLASH_wd) { + unsigned WarningNumber; + if (StringRef(A->getValue()).getAsInteger(10, WarningNumber)) { + D.Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + continue; + } + + if (auto Group = diagGroupFromCLWarningID(WarningNumber)) { + CmdArgs.push_back(Args.MakeArgString( + "-Wno-" + DiagnosticIDs::getWarningOptionForGroup(*Group))); + } + continue; + } + A->render(Args, CmdArgs); + } + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) CmdArgs.push_back("-pedantic"); Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); @@ -5433,6 +5559,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_relative_cxx_abi_vtables, options::OPT_fno_experimental_relative_cxx_abi_vtables); + if (Arg *A = Args.getLastArg(options::OPT_ffuchsia_api_level_EQ)) + A->render(Args, CmdArgs); + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} // (-ansi is equivalent to -std=c89 or -std=c++98). // @@ -5693,7 +5822,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var, options::OPT_fno_visibility_inlines_hidden_static_local_var); Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden); - + Args.AddLastArg(CmdArgs, options::OPT_fnew_infallible); Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); if (Args.hasFlag(options::OPT_fno_operator_names, @@ -5736,6 +5865,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + if (!Args.hasFlag(options::OPT_fopenmp_extensions, + options::OPT_fno_openmp_extensions, /*Default=*/true)) + CmdArgs.push_back("-fno-openmp-extensions"); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ); Args.AddAllArgs(CmdArgs, @@ -5751,12 +5883,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp_cuda_mode, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-mode"); + // When in OpenMP offloading mode, enable or disable the new device + // runtime. + if (Args.hasFlag(options::OPT_fopenmp_target_new_runtime, + options::OPT_fno_openmp_target_new_runtime, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-new-runtime"); + + // When in OpenMP offloading mode, enable debugging on the device. + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); + if (Args.hasFlag(options::OPT_fopenmp_target_debug, + options::OPT_fno_openmp_target_debug, /*Default=*/false)) + CmdArgs.push_back("-fopenmp-target-debug"); + // When in OpenMP offloading mode with NVPTX target, check if full runtime // is required. if (Args.hasFlag(options::OPT_fopenmp_cuda_force_full_runtime, options::OPT_fno_openmp_cuda_force_full_runtime, /*Default=*/false)) CmdArgs.push_back("-fopenmp-cuda-force-full-runtime"); + + // When in OpenMP offloading mode, forward assumptions information about + // thread and team counts in the device. + if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, + options::OPT_fno_openmp_assume_teams_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); + if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, + options::OPT_fno_openmp_assume_threads_oversubscription, + /*Default=*/false)) + CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); break; default: // By default, if Clang doesn't know how to generate useful OpenMP code @@ -5771,10 +5927,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + if (!Args.hasFlag(options::OPT_fopenmp_extensions, + options::OPT_fno_openmp_extensions, /*Default=*/true)) + CmdArgs.push_back("-fno-openmp-extensions"); } - const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); - Sanitize.addArgs(TC, Args, CmdArgs, InputType); + SanitizeArgs.addArgs(TC, Args, CmdArgs, InputType); const XRayArgs &XRay = TC.getXRayArgs(); XRay.addArgs(TC, Args, CmdArgs, InputType); @@ -5891,6 +6049,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderSCPOptions(TC, Args, CmdArgs); RenderTrivialAutoVarInitOptions(D, TC, Args, CmdArgs); + Args.AddLastArg(CmdArgs, options::OPT_fswift_async_fp_EQ); + // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, false)) @@ -6175,7 +6335,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // than 19. if (!Args.hasFlag(options::OPT_fthreadsafe_statics, options::OPT_fno_threadsafe_statics, - !IsWindowsMSVC || IsMSVC2015Compatible)) + !types::isOpenCL(InputType) && + (!IsWindowsMSVC || IsMSVC2015Compatible))) CmdArgs.push_back("-fno-threadsafe-statics"); // -fno-delayed-template-parsing is default, except when targeting MSVC. @@ -6715,12 +6876,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } bool DefaultsSplitLTOUnit = - (WholeProgramVTables || Sanitize.needsLTO()) && + (WholeProgramVTables || SanitizeArgs.needsLTO()) && (LTOMode == LTOK_Full || TC.canSplitThinLTOUnit()); bool SplitLTOUnit = Args.hasFlag(options::OPT_fsplit_lto_unit, options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); - if (Sanitize.needsLTO() && !SplitLTOUnit) + if (SanitizeArgs.needsLTO() && !SplitLTOUnit) D.Diag(diag::err_drv_argument_not_allowed_with) << "-fno-split-lto-unit" << "-fsanitize=cfi"; if (SplitLTOUnit) @@ -6819,7 +6980,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-faddrsig"); if ((Triple.isOSBinFormatELF() || Triple.isOSBinFormatMachO()) && - (EH || UnwindTables || DebugInfoKind != codegenoptions::NoDebugInfo)) + (EH || AsyncUnwindTables || UnwindTables || + DebugInfoKind != codegenoptions::NoDebugInfo)) CmdArgs.push_back("-D__GCC_HAVE_DWARF2_CFI_ASM=1"); if (Arg *A = Args.getLastArg(options::OPT_fsymbol_partition_EQ)) { @@ -7431,7 +7593,7 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Clang::getBaseInputName(Args, Input)); // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); + std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ true); if (!CPU.empty()) { CmdArgs.push_back("-target-cpu"); CmdArgs.push_back(Args.MakeArgString(CPU)); @@ -7667,18 +7829,30 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, }); } Triples += Action::GetOffloadKindName(CurKind); - Triples += "-"; - std::string NormalizedTriple = CurTC->getTriple().normalize(); - Triples += NormalizedTriple; - - if (CurDep->getOffloadingArch() != nullptr) { - // If OffloadArch is present it can only appear as the 6th hypen - // sepearated field of Bundle Entry ID. So, pad required number of - // hyphens in Triple. - for (int i = 4 - StringRef(NormalizedTriple).count("-"); i > 0; i--) - Triples += "-"; + Triples += '-'; + Triples += CurTC->getTriple().normalize(); + if ((CurKind == Action::OFK_HIP || CurKind == Action::OFK_Cuda) && + CurDep->getOffloadingArch()) { + Triples += '-'; Triples += CurDep->getOffloadingArch(); } + + // TODO: Replace parsing of -march flag. Can be done by storing GPUArch + // with each toolchain. + StringRef GPUArchName; + if (CurKind == Action::OFK_OpenMP) { + // Extract GPUArch from -march argument in TC argument list. + for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { + auto ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); + auto Arch = ArchStr.startswith_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); @@ -7701,8 +7875,11 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, assert(CurTC == nullptr && "Expected one dependence!"); CurTC = TC; }); + UB += C.addTempFile( + C.getArgs().MakeArgString(CurTC->getInputFilename(Inputs[I]))); + } else { + UB += CurTC->getInputFilename(Inputs[I]); } - UB += CurTC->getInputFilename(Inputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); @@ -7746,19 +7923,30 @@ void OffloadBundler::ConstructJobMultipleOutputs( auto &Dep = DepInfo[I]; Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); - Triples += "-"; - std::string NormalizedTriple = - Dep.DependentToolChain->getTriple().normalize(); - Triples += NormalizedTriple; - - if (!Dep.DependentBoundArch.empty()) { - // If OffloadArch is present it can only appear as the 6th hypen - // sepearated field of Bundle Entry ID. So, pad required number of - // hyphens in Triple. - for (int i = 4 - StringRef(NormalizedTriple).count("-"); i > 0; i--) - Triples += "-"; + Triples += '-'; + Triples += Dep.DependentToolChain->getTriple().normalize(); + if ((Dep.DependentOffloadKind == Action::OFK_HIP || + Dep.DependentOffloadKind == Action::OFK_Cuda) && + !Dep.DependentBoundArch.empty()) { + Triples += '-'; Triples += Dep.DependentBoundArch; } + // TODO: Replace parsing of -march flag. Can be done by storing GPUArch + // with each toolchain. + StringRef GPUArchName; + if (Dep.DependentOffloadKind == Action::OFK_OpenMP) { + // Extract GPUArch from -march argument in TC argument list. + for (unsigned ArgIndex = 0; ArgIndex < TCArgs.size(); ArgIndex++) { + StringRef ArchStr = StringRef(TCArgs.getArgString(ArgIndex)); + auto Arch = ArchStr.startswith_insensitive("-march="); + if (Arch) { + GPUArchName = ArchStr.substr(7); + Triples += "-"; + break; + } + } + Triples += GPUArchName.str(); + } } CmdArgs.push_back(TCArgs.MakeArgString(Triples)); diff --git a/clang/lib/Driver/ToolChains/CloudABI.cpp b/clang/lib/Driver/ToolChains/CloudABI.cpp index 9ee46ac857f..501e3a382ec 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.cpp +++ b/clang/lib/Driver/ToolChains/CloudABI.cpp @@ -47,7 +47,7 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--no-dynamic-linker"); // Provide PIE linker flags in case PIE is default for the architecture. - if (ToolChain.isPIEDefault()) { + if (ToolChain.isPIEDefault(Args)) { CmdArgs.push_back("-pie"); CmdArgs.push_back("-zrelro"); } @@ -125,7 +125,7 @@ Tool *CloudABI::buildLinker() const { return new tools::cloudabi::Linker(*this); } -bool CloudABI::isPIEDefault() const { +bool CloudABI::isPIEDefault(const llvm::opt::ArgList &Args) const { // Only enable PIE on architectures that support PC-relative // addressing. PC-relative addressing is required, as the process // startup code must be able to relocate itself. diff --git a/clang/lib/Driver/ToolChains/CloudABI.h b/clang/lib/Driver/ToolChains/CloudABI.h index 98bf2312770..8856fe3dde6 100644 --- a/clang/lib/Driver/ToolChains/CloudABI.h +++ b/clang/lib/Driver/ToolChains/CloudABI.h @@ -55,7 +55,7 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; SanitizerMask getDefaultSanitizers() const override; diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 83cab3ac00c..630baf9d6ae 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -34,6 +34,7 @@ #include "clang/Driver/Util.h" #include "clang/Driver/XRayArgs.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -266,6 +267,15 @@ void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, // Pass -z prefix for gcc linker compatibility. A.claim(); A.render(Args, CmdArgs); + } else if (A.getOption().matches(options::OPT_b)) { + const llvm::Triple &T = TC.getTriple(); + if (!T.isOSAIX()) { + TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A.getSpelling() << T.str(); + } + // Pass -b prefix for AIX linker. + A.claim(); + A.render(Args, CmdArgs); } else { A.renderAsInput(Args, CmdArgs); } @@ -346,8 +356,8 @@ static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { return "generic"; } -std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, - bool FromAs) { +std::string tools::getCPUName(const Driver &D, const ArgList &Args, + const llvm::Triple &T, bool FromAs) { Arg *A; switch (T.getArch()) { @@ -403,14 +413,9 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, if (!TargetCPUName.empty()) return TargetCPUName; - if (T.isOSAIX()) { - unsigned major, minor, unused_micro; - T.getOSVersion(major, minor, unused_micro); - // The minimal arch level moved from pwr4 for AIX7.1 to - // pwr7 for AIX7.2. - TargetCPUName = - (major < 7 || (major == 7 && minor < 2)) ? "pwr4" : "pwr7"; - } else if (T.getArch() == llvm::Triple::ppc64le) + if (T.isOSAIX()) + TargetCPUName = "pwr7"; + else if (T.getArch() == llvm::Triple::ppc64le) TargetCPUName = "ppc64le"; else if (T.getArch() == llvm::Triple::ppc64) TargetCPUName = "ppc64"; @@ -438,7 +443,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, case llvm::Triple::x86: case llvm::Triple::x86_64: - return x86::getX86TargetCPU(Args, T); + return x86::getX86TargetCPU(D, Args, T); case llvm::Triple::hexagon: return "hexagon" + @@ -506,7 +511,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, // the plugin. // Handle flags for selecting CPU variants. - std::string CPU = getCPUName(Args, ToolChain.getTriple()); + std::string CPU = getCPUName(D, Args, ToolChain.getTriple()); if (!CPU.empty()) CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); @@ -616,11 +621,6 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back("-plugin-opt=new-pass-manager"); } - // Pass an option to enable pseudo probe emission. - if (Args.hasFlag(options::OPT_fpseudo_probe_for_profiling, - options::OPT_fno_pseudo_probe_for_profiling, false)) - CmdArgs.push_back("-plugin-opt=pseudo-probe-for-profiling"); - // Setup statistics file output. SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D); if (!StatsFile.empty()) @@ -657,7 +657,7 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, std::string CandidateRPath = TC.getArchSpecificLibPath(); if (TC.getVFS().exists(CandidateRPath)) { CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); } } @@ -775,7 +775,8 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-ldl"); // Required for backtrace on some OSes if (TC.getTriple().isOSFreeBSD() || - TC.getTriple().isOSNetBSD()) + TC.getTriple().isOSNetBSD() || + TC.getTriple().isOSOpenBSD()) CmdArgs.push_back("-lexecinfo"); } @@ -786,7 +787,7 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl &NonWholeStaticRuntimes, SmallVectorImpl &HelperStaticRuntimes, SmallVectorImpl &RequiredSymbols) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Collect shared runtimes. if (SanArgs.needsSharedRt()) { if (SanArgs.needsAsanRt() && SanArgs.linkRuntimes()) { @@ -922,7 +923,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); // Inject libfuzzer dependencies. if (SanArgs.needsFuzzer() && SanArgs.linkRuntimes() && !Args.hasArg(options::OPT_shared)) { @@ -1115,7 +1116,7 @@ tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); const llvm::Triple &Triple = ToolChain.getTriple(); - bool PIE = ToolChain.isPIEDefault(); + bool PIE = ToolChain.isPIEDefault(Args); bool PIC = PIE || ToolChain.isPICDefault(); // The Darwin/MachO default to use PIC does not apply when using -static. if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) @@ -1587,6 +1588,292 @@ void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, } } +/// SDLSearch: Search for Static Device Library +/// The search for SDL bitcode files is consistent with how static host +/// libraries are discovered. That is, the -l option triggers a search for +/// files in a set of directories called the LINKPATH. The host library search +/// procedure looks for a specific filename in the LINKPATH. The filename for +/// a host library is lib.a or lib.so. For SDLs, there is an +/// ordered-set of filenames that are searched. We call this ordered-set of +/// filenames as SEARCH-ORDER. Since an SDL can either be device-type specific, +/// architecture specific, or generic across all architectures, a naming +/// convention and search order is used where the file name embeds the +/// architecture name (nvptx or amdgcn) and the GPU device type +/// such as sm_30 and gfx906. is absent in case of +/// device-independent SDLs. To reduce congestion in host library directories, +/// the search first looks for files in the “libdevice” subdirectory. SDLs that +/// are bc files begin with the prefix “lib”. +/// +/// Machine-code SDLs can also be managed as an archive (*.a file). The +/// convention has been to use the prefix “lib”. To avoid confusion with host +/// archive libraries, we use prefix "libbc-" for the bitcode SDL archives. +/// +bool tools::SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector LibraryPaths, std::string Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink) { + SmallVector SDLs; + + std::string LibDeviceLoc = "/libdevice"; + std::string LibBcPrefix = "/libbc-"; + std::string LibPrefix = "/lib"; + + if (isBitCodeSDL) { + // SEARCH-ORDER for Bitcode SDLs: + // libdevice/libbc---.a + // libbc---.a + // libdevice/libbc--.a + // libbc--.a + // libdevice/libbc-.a + // libbc-.a + // libdevice/lib--.bc + // lib--.bc + // libdevice/lib-.bc + // lib-.bc + // libdevice/lib.bc + // lib.bc + + for (StringRef Base : {LibBcPrefix, LibPrefix}) { + const auto *Ext = Base.contains(LibBcPrefix) ? ".a" : ".bc"; + + for (auto Suffix : {Twine(Lib + "-" + Arch + "-" + Target).str(), + Twine(Lib + "-" + Arch).str(), Twine(Lib).str()}) { + SDLs.push_back(Twine(LibDeviceLoc + Base + Suffix + Ext).str()); + SDLs.push_back(Twine(Base + Suffix + Ext).str()); + } + } + } else { + // SEARCH-ORDER for Machine-code SDLs: + // libdevice/lib--.a + // lib--.a + // libdevice/lib-.a + // lib-.a + + const auto *Ext = ".a"; + + for (auto Suffix : {Twine(Lib + "-" + Arch + "-" + Target).str(), + Twine(Lib + "-" + Arch).str()}) { + SDLs.push_back(Twine(LibDeviceLoc + LibPrefix + Suffix + Ext).str()); + SDLs.push_back(Twine(LibPrefix + Suffix + Ext).str()); + } + } + + // The CUDA toolchain does not use a global device llvm-link before the LLVM + // backend generates ptx. So currently, the use of bitcode SDL for nvptx is + // only possible with post-clang-cc1 linking. Clang cc1 has a feature that + // will link libraries after clang compilation while the LLVM IR is still in + // memory. This utilizes a clang cc1 option called “-mlink-builtin-bitcode”. + // This is a clang -cc1 option that is generated by the clang driver. The + // option value must a full path to an existing file. + bool FoundSDL = false; + for (auto LPath : LibraryPaths) { + for (auto SDL : SDLs) { + auto FullName = Twine(LPath + SDL).str(); + if (llvm::sys::fs::exists(FullName)) { + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(FullName)); + FoundSDL = true; + break; + } + } + if (FoundSDL) + break; + } + return FoundSDL; +} + +/// Search if a user provided archive file lib.a exists in any of +/// the library paths. If so, add a new command to clang-offload-bundler to +/// unbundle this archive and create a temporary device specific archive. Name +/// of this SDL is passed to the llvm-link (for amdgcn) or to the +/// clang-nvlink-wrapper (for nvptx) commands by the driver. +bool tools::GetSDLFromOffloadArchive( + Compilation &C, const Driver &D, const Tool &T, const JobAction &JA, + const InputInfoList &Inputs, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, SmallVector LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink) { + + // We don't support bitcode archive bundles for nvptx + if (isBitCodeSDL && Arch.contains("nvptx")) + return false; + + bool FoundAOB = false; + SmallVector AOBFileNames; + std::string ArchiveOfBundles; + for (auto LPath : LibraryPaths) { + ArchiveOfBundles.clear(); + + AOBFileNames.push_back(Twine(LPath + "/libdevice/lib" + Lib + ".a").str()); + AOBFileNames.push_back(Twine(LPath + "/lib" + Lib + ".a").str()); + + for (auto AOB : AOBFileNames) { + if (llvm::sys::fs::exists(AOB)) { + ArchiveOfBundles = AOB; + FoundAOB = true; + break; + } + } + + if (!FoundAOB) + continue; + + StringRef Prefix = isBitCodeSDL ? "libbc-" : "lib"; + std::string OutputLib = D.GetTemporaryPath( + Twine(Prefix + Lib + "-" + Arch + "-" + Target).str(), "a"); + + C.addTempFile(C.getArgs().MakeArgString(OutputLib.c_str())); + + ArgStringList CmdArgs; + SmallString<128> DeviceTriple; + DeviceTriple += Action::GetOffloadKindName(JA.getOffloadingDeviceKind()); + DeviceTriple += '-'; + std::string NormalizedTriple = T.getToolChain().getTriple().normalize(); + DeviceTriple += NormalizedTriple; + if (!Target.empty()) { + DeviceTriple += '-'; + DeviceTriple += Target; + } + + std::string UnbundleArg("-unbundle"); + std::string TypeArg("-type=a"); + std::string InputArg("-inputs=" + ArchiveOfBundles); + std::string OffloadArg("-targets=" + std::string(DeviceTriple)); + std::string OutputArg("-outputs=" + OutputLib); + + const char *UBProgram = DriverArgs.MakeArgString( + T.getToolChain().GetProgramPath("clang-offload-bundler")); + + ArgStringList UBArgs; + UBArgs.push_back(C.getArgs().MakeArgString(UnbundleArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(TypeArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(InputArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OffloadArg.c_str())); + UBArgs.push_back(C.getArgs().MakeArgString(OutputArg.c_str())); + + // Add this flag to not exit from clang-offload-bundler if no compatible + // code object is found in heterogenous archive library. + std::string AdditionalArgs("-allow-missing-bundles"); + UBArgs.push_back(C.getArgs().MakeArgString(AdditionalArgs.c_str())); + + C.addCommand(std::make_unique( + JA, T, ResponseFileSupport::AtFileCurCP(), UBProgram, UBArgs, Inputs, + InputInfo(&JA, C.getArgs().MakeArgString(OutputLib.c_str())))); + if (postClangLink) + CC1Args.push_back("-mlink-builtin-bitcode"); + + CC1Args.push_back(DriverArgs.MakeArgString(OutputLib)); + break; + } + + return FoundAOB; +} + +// Wrapper function used by driver for adding SDLs during link phase. +void tools::AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(&C, &T, &JA, &Inputs, C.getDriver(), DriverArgs, CC1Args, + Arch, Target, isBitCodeSDL, postClangLink); +} + +// Wrapper function used for post clang linking of bitcode SDLS for nvptx by +// the CUDA toolchain. +void tools::AddStaticDeviceLibsPostLinking(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink) { + AddStaticDeviceLibs(nullptr, nullptr, nullptr, nullptr, D, DriverArgs, + CC1Args, Arch, Target, isBitCodeSDL, postClangLink); +} + +// User defined Static Device Libraries(SDLs) can be passed to clang for +// offloading GPU compilers. Like static host libraries, the use of a SDL is +// specified with the -l command line option. The primary difference between +// host and SDLs is the filenames for SDLs (refer SEARCH-ORDER for Bitcode SDLs +// and SEARCH-ORDER for Machine-code SDLs for the naming convention). +// SDLs are of following types: +// +// * Bitcode SDLs: They can either be a *.bc file or an archive of *.bc files. +// For NVPTX, these libraries are post-clang linked following each +// compilation. For AMDGPU, these libraries are linked one time +// during the application link phase. +// +// * Machine-code SDLs: They are archive files. For NVPTX, the archive members +// contain cubin for Nvidia GPUs and are linked one time during the +// link phase by the CUDA SDK linker called nvlink. For AMDGPU, the +// process for machine code SDLs is still in development. But they +// will be linked by the LLVM tool lld. +// +// * Bundled objects that contain both host and device codes: Bundled objects +// may also contain library code compiled from source. For NVPTX, the +// bundle contains cubin. For AMDGPU, the bundle contains bitcode. +// +// For Bitcode and Machine-code SDLs, current compiler toolchains hardcode the +// inclusion of specific SDLs such as math libraries and the OpenMP device +// library libomptarget. +void tools::AddStaticDeviceLibs(Compilation *C, const Tool *T, + const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink) { + + SmallVector LibraryPaths; + // Add search directories from LIBRARY_PATH env variable + llvm::Optional LibPath = + llvm::sys::Process::GetEnv("LIBRARY_PATH"); + if (LibPath) { + SmallVector Frags; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + llvm::SplitString(*LibPath, Frags, EnvPathSeparatorStr); + for (StringRef Path : Frags) + LibraryPaths.emplace_back(Path.trim()); + } + + // Add directories from user-specified -L options + for (std::string Search_Dir : DriverArgs.getAllArgValues(options::OPT_L)) + LibraryPaths.emplace_back(Search_Dir); + + // Add path to lib-debug folders + SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); + llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + + // Build list of Static Device Libraries SDLs specified by -l option + llvm::SmallSet SDLNames; + static const StringRef HostOnlyArchives[] = { + "omp", "cudart", "m", "gcc", "gcc_s", "pthread", "hip_hcc"}; + for (auto SDLName : DriverArgs.getAllArgValues(options::OPT_l)) { + if (!HostOnlyArchives->contains(SDLName)) { + SDLNames.insert(SDLName); + } + } + + // The search stops as soon as an SDL file is found. The driver then provides + // the full filename of the SDL to the llvm-link or clang-nvlink-wrapper + // command. If no SDL is found after searching each LINKPATH with + // SEARCH-ORDER, it is possible that an archive file lib.a exists + // and may contain bundled object files. + for (auto SDLName : SDLNames) { + // This is the only call to SDLSearch + if (!SDLSearch(D, DriverArgs, CC1Args, LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL, postClangLink)) { + GetSDLFromOffloadArchive(*C, D, *T, *JA, *Inputs, DriverArgs, CC1Args, + LibraryPaths, SDLName, Arch, Target, + isBitCodeSDL, postClangLink); + } + } +} + static llvm::opt::Arg * getAMDGPUCodeObjectArgument(const Driver &D, const llvm::opt::ArgList &Args) { // The last of -mcode-object-v3, -mno-code-object-v3 and @@ -1684,6 +1971,12 @@ void tools::addOpenMPDeviceRTL(const Driver &D, StringRef BitcodeSuffix, const llvm::Triple &Triple) { SmallVector LibraryPaths; + + // Add path to clang lib / lib64 folder. + SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); + llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); + LibraryPaths.emplace_back(DefaultLibPath.c_str()); + // Add user defined library paths from LIBRARY_PATH. llvm::Optional LibPath = llvm::sys::Process::GetEnv("LIBRARY_PATH"); @@ -1695,32 +1988,31 @@ void tools::addOpenMPDeviceRTL(const Driver &D, LibraryPaths.emplace_back(Path.trim()); } - // Add path to lib / lib64 folder. - SmallString<256> DefaultLibPath = llvm::sys::path::parent_path(D.Dir); - llvm::sys::path::append(DefaultLibPath, Twine("lib") + CLANG_LIBDIR_SUFFIX); - LibraryPaths.emplace_back(DefaultLibPath.c_str()); - OptSpecifier LibomptargetBCPathOpt = Triple.isAMDGCN() ? options::OPT_libomptarget_amdgcn_bc_path_EQ : options::OPT_libomptarget_nvptx_bc_path_EQ; StringRef ArchPrefix = Triple.isAMDGCN() ? "amdgcn" : "nvptx"; + std::string LibOmpTargetName = "libomptarget-" + BitcodeSuffix.str() + ".bc"; + // First check whether user specifies bc library if (const Arg *A = DriverArgs.getLastArg(LibomptargetBCPathOpt)) { - std::string LibOmpTargetName(A->getValue()); - if (llvm::sys::fs::exists(LibOmpTargetName)) { + SmallString<128> LibOmpTargetFile(A->getValue()); + if (llvm::sys::fs::exists(LibOmpTargetFile) && + llvm::sys::fs::is_directory(LibOmpTargetFile)) { + llvm::sys::path::append(LibOmpTargetFile, LibOmpTargetName); + } + + if (llvm::sys::fs::exists(LibOmpTargetFile)) { CC1Args.push_back("-mlink-builtin-bitcode"); - CC1Args.push_back(DriverArgs.MakeArgString(LibOmpTargetName)); + CC1Args.push_back(DriverArgs.MakeArgString(LibOmpTargetFile)); } else { D.Diag(diag::err_drv_omp_offload_target_bcruntime_not_found) - << LibOmpTargetName; + << LibOmpTargetFile; } } else { bool FoundBCLibrary = false; - std::string LibOmpTargetName = - "libomptarget-" + BitcodeSuffix.str() + ".bc"; - for (StringRef LibraryPath : LibraryPaths) { SmallString<128> LibOmpTargetFile(LibraryPath); llvm::sys::path::append(LibOmpTargetFile, LibOmpTargetName); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index c94c1586466..00291a3681c 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -49,6 +49,39 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); +void AddStaticDeviceLibsLinking(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink); +void AddStaticDeviceLibsPostLinking(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink); +void AddStaticDeviceLibs(Compilation *C, const Tool *T, const JobAction *JA, + const InputInfoList *Inputs, const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, StringRef Arch, + StringRef Target, bool isBitCodeSDL, + bool postClangLink); + +bool SDLSearch(const Driver &D, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CmdArgs, + SmallVector LibraryPaths, std::string Lib, + StringRef Arch, StringRef Target, bool isBitCodeSDL, + bool postClangLink); + +bool GetSDLFromOffloadArchive(Compilation &C, const Driver &D, const Tool &T, + const JobAction &JA, const InputInfoList &Inputs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + SmallVector LibraryPaths, + StringRef Lib, StringRef Arch, StringRef Target, + bool isBitCodeSDL, bool postClangLink); + const char *SplitDebugName(const JobAction &JA, const llvm::opt::ArgList &Args, const InputInfo &Input, const InputInfo &Output); @@ -107,8 +140,8 @@ void AddTargetFeature(const llvm::opt::ArgList &Args, llvm::opt::OptSpecifier OnOpt, llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); -std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, - bool FromAs = false); +std::string getCPUName(const Driver &D, const llvm::opt::ArgList &Args, + const llvm::Triple &T, bool FromAs = false); /// Iterate \p Args and convert -mxxx to +xxx and -mno-xxx to -xxx and /// append it to \p Features. diff --git a/clang/lib/Driver/ToolChains/CrossWindows.cpp b/clang/lib/Driver/ToolChains/CrossWindows.cpp index 07abf4f83f7..2b043fbeecd 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.cpp +++ b/clang/lib/Driver/ToolChains/CrossWindows.cpp @@ -185,7 +185,7 @@ void tools::CrossWindows::Linker::ConstructJob( } } - if (TC.getSanitizerArgs().needsAsanRt()) { + if (TC.getSanitizerArgs(Args).needsAsanRt()) { // TODO handle /MT[d] /MD[d] if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); @@ -223,7 +223,7 @@ bool CrossWindowsToolChain::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } -bool CrossWindowsToolChain::isPIEDefault() const { +bool CrossWindowsToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { return getArch() == llvm::Triple::x86_64; } diff --git a/clang/lib/Driver/ToolChains/CrossWindows.h b/clang/lib/Driver/ToolChains/CrossWindows.h index ffe75332c2e..bab690ea34d 100644 --- a/clang/lib/Driver/ToolChains/CrossWindows.h +++ b/clang/lib/Driver/ToolChains/CrossWindows.h @@ -57,7 +57,7 @@ public: bool IsIntegratedAssemblerDefault() const override { return true; } bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; LangOptions::StackProtectorMode diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 769eae14df5..5397c7a9a0e 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" @@ -34,25 +35,6 @@ using namespace clang; using namespace llvm::opt; namespace { -struct CudaVersionInfo { - std::string DetectedVersion; - CudaVersion Version; -}; -// Parses the contents of version.txt in an CUDA installation. It should -// contain one line of the from e.g. "CUDA Version 7.5.2". -CudaVersionInfo parseCudaVersionFile(llvm::StringRef V) { - V = V.trim(); - if (!V.startswith("CUDA Version ")) - return {V.str(), CudaVersion::UNKNOWN}; - V = V.substr(strlen("CUDA Version ")); - SmallVector VersionParts; - V.split(VersionParts, '.'); - return {"version.txt: " + V.str() + ".", - VersionParts.size() < 2 - ? CudaVersion::UNKNOWN - : CudaStringToVersion( - join_items(".", VersionParts[0], VersionParts[1]))}; -} CudaVersion getCudaVersion(uint32_t raw_version) { if (raw_version < 7050) @@ -77,10 +59,18 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_110; if (raw_version < 11020) return CudaVersion::CUDA_111; - return CudaVersion::LATEST; + if (raw_version < 11030) + return CudaVersion::CUDA_112; + if (raw_version < 11040) + return CudaVersion::CUDA_113; + if (raw_version < 11050) + return CudaVersion::CUDA_114; + if (raw_version < 11060) + return CudaVersion::CUDA_115; + return CudaVersion::NEW; } -CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { +CudaVersion parseCudaHFile(llvm::StringRef Input) { // Helper lambda which skips the words if the line starts with them or returns // None otherwise. auto StartsWithWords = @@ -100,21 +90,27 @@ CudaVersionInfo parseCudaHFile(llvm::StringRef Input) { StartsWithWords(Input.ltrim(), {"#", "define", "CUDA_VERSION"})) { uint32_t RawVersion; Line->consumeInteger(10, RawVersion); - return {"cuda.h: CUDA_VERSION=" + Twine(RawVersion).str() + ".", - getCudaVersion(RawVersion)}; + return getCudaVersion(RawVersion); } // Find next non-empty line. Input = Input.drop_front(Input.find_first_of("\n\r")).ltrim(); } - return {"cuda.h: CUDA_VERSION not found.", CudaVersion::UNKNOWN}; + return CudaVersion::UNKNOWN; } } // namespace void CudaInstallationDetector::WarnIfUnsupportedVersion() { - if (DetectedVersionIsNotSupported) - D.Diag(diag::warn_drv_unknown_cuda_version) - << DetectedVersion - << CudaVersionToString(CudaVersion::LATEST_SUPPORTED); + if (Version > CudaVersion::PARTIALLY_SUPPORTED) { + std::string VersionString = CudaVersionToString(Version); + if (!VersionString.empty()) + VersionString.insert(0, " "); + D.Diag(diag::warn_drv_new_cuda_version) + << VersionString + << (CudaVersion::PARTIALLY_SUPPORTED != CudaVersion::FULLY_SUPPORTED) + << CudaVersionToString(CudaVersion::PARTIALLY_SUPPORTED); + } else if (Version > CudaVersion::FULLY_SUPPORTED) + D.Diag(diag::warn_drv_partially_supported_cuda_version) + << CudaVersionToString(Version); } CudaInstallationDetector::CudaInstallationDetector( @@ -206,31 +202,17 @@ CudaInstallationDetector::CudaInstallationDetector( else continue; - CudaVersionInfo VersionInfo = {"", CudaVersion::UNKNOWN}; - if (auto VersionFile = FS.getBufferForFile(InstallPath + "/version.txt")) - VersionInfo = parseCudaVersionFile((*VersionFile)->getBuffer()); - // If version file didn't give us the version, try to find it in cuda.h - if (VersionInfo.Version == CudaVersion::UNKNOWN) - if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) - VersionInfo = parseCudaHFile((*CudaHFile)->getBuffer()); - // As the last resort, make an educated guess between CUDA-7.0, (which had - // no version.txt file and had old-style libdevice bitcode ) and an unknown - // recent CUDA version (no version.txt, new style bitcode). - if (VersionInfo.Version == CudaVersion::UNKNOWN) { - VersionInfo.Version = (FS.exists(LibDevicePath + "/libdevice.10.bc")) - ? Version = CudaVersion::LATEST - : Version = CudaVersion::CUDA_70; - VersionInfo.DetectedVersion = - "No version found in version.txt or cuda.h."; + Version = CudaVersion::UNKNOWN; + if (auto CudaHFile = FS.getBufferForFile(InstallPath + "/include/cuda.h")) + Version = parseCudaHFile((*CudaHFile)->getBuffer()); + // As the last resort, make an educated guess between CUDA-7.0, which had + // old-style libdevice bitcode, and an unknown recent CUDA version. + if (Version == CudaVersion::UNKNOWN) { + Version = FS.exists(LibDevicePath + "/libdevice.10.bc") + ? CudaVersion::NEW + : CudaVersion::CUDA_70; } - Version = VersionInfo.Version; - DetectedVersion = VersionInfo.DetectedVersion; - - // TODO(tra): remove the warning once we have all features of 10.2 - // and 11.0 implemented. - DetectedVersionIsNotSupported = Version > CudaVersion::LATEST_SUPPORTED; - if (Version >= CudaVersion::CUDA_90) { // CUDA-9+ uses single libdevice file for all GPU variants. std::string FilePath = LibDevicePath + "/libdevice.10.bc"; @@ -319,8 +301,6 @@ void CudaInstallationDetector::AddCudaIncludeArgs( return; } - CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); CC1Args.push_back("-include"); CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); } @@ -632,8 +612,16 @@ void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(CubinF); } + AddStaticDeviceLibsLinking(C, *this, JA, Inputs, Args, CmdArgs, "nvptx", GPUArch, + false, false); + + // Find nvlink and pass it as "--nvlink-path=" argument of + // clang-nvlink-wrapper. + CmdArgs.push_back(Args.MakeArgString( + Twine("--nvlink-path=" + getToolChain().GetProgramPath("nvlink")))); + const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); + Args.MakeArgString(getToolChain().GetProgramPath("clang-nvlink-wrapper")); C.addCommand(std::make_unique( JA, *this, ResponseFileSupport{ResponseFileSupport::RF_Full, llvm::sys::WEM_UTF8, @@ -686,7 +674,8 @@ void CudaToolChain::addClangTargetOptions( "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs."); if (DeviceOffloadingKind == Action::OFK_Cuda) { - CC1Args.push_back("-fcuda-is-device"); + CC1Args.append( + {"-fcuda-is-device", "-mllvm", "-enable-memcpyopt-without-libcalls"}); if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) @@ -720,6 +709,9 @@ void CudaToolChain::addClangTargetOptions( case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(115, 75); + CASE_CUDA_VERSION(114, 74); + CASE_CUDA_VERSION(113, 73); CASE_CUDA_VERSION(112, 72); CASE_CUDA_VERSION(111, 71); CASE_CUDA_VERSION(110, 70); @@ -760,6 +752,8 @@ void CudaToolChain::addClangTargetOptions( addOpenMPDeviceRTL(getDriver(), DriverArgs, CC1Args, BitcodeSuffix, getTriple()); + AddStaticDeviceLibsPostLinking(getDriver(), DriverArgs, CC1Args, "nvptx", GpuArch, + /* bitcode SDL?*/ true, /* PostClang Link? */ true); } } @@ -831,17 +825,9 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // flags are not duplicated. // Also append the compute capability. if (DeviceOffloadKind == Action::OFK_OpenMP) { - for (Arg *A : Args) { - bool IsDuplicate = false; - for (Arg *DALArg : *DAL) { - if (A == DALArg) { - IsDuplicate = true; - break; - } - } - if (!IsDuplicate) + for (Arg *A : Args) + if (!llvm::is_contained(*DAL, A)) DAL->append(A); - } StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); if (Arch.empty()) @@ -884,6 +870,11 @@ CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); + + if (!DriverArgs.hasArg(options::OPT_nogpuinc) && CudaInstallation.isValid()) + CC1Args.append( + {"-internal-isystem", + DriverArgs.MakeArgString(CudaInstallation.getIncludePath())}); } void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/Cuda.h b/clang/lib/Driver/ToolChains/Cuda.h index 6ae4415a563..a7e6e84f490 100644 --- a/clang/lib/Driver/ToolChains/Cuda.h +++ b/clang/lib/Driver/ToolChains/Cuda.h @@ -30,8 +30,6 @@ private: const Driver &D; bool IsValid = false; CudaVersion Version = CudaVersion::UNKNOWN; - std::string DetectedVersion; - bool DetectedVersionIsNotSupported = false; std::string InstallPath; std::string BinPath; std::string LibPath; @@ -62,7 +60,10 @@ public: void print(raw_ostream &OS) const; /// Get the detected Cuda install's version. - CudaVersion version() const { return Version; } + CudaVersion version() const { + return Version == CudaVersion::NEW ? CudaVersion::PARTIALLY_SUPPORTED + : Version; + } /// Get the detected Cuda installation path. StringRef getInstallPath() const { return InstallPath; } /// Get the detected path to Cuda's bin directory. @@ -156,7 +157,9 @@ public: bool useIntegratedAs() const override { return false; } bool isCrossCompiling() const override { return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } bool supportsDebugInfoOption(const llvm::opt::Arg *A) const override; diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 261f522f6c4..06d3edc70e4 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -34,7 +34,7 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; -static const VersionTuple minimumMacCatalystDeploymentTarget() { +static VersionTuple minimumMacCatalystDeploymentTarget() { return VersionTuple(13, 1); } @@ -94,6 +94,8 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const llvm::Triple &T(getToolChain().getTriple()); + ArgStringList CmdArgs; assert(Inputs.size() == 1 && "Unexpected number of inputs."); @@ -112,7 +114,6 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: at run-time detect assembler capabilities or rely on version // information forwarded by -target-assembler-version. if (Args.hasArg(options::OPT_fno_integrated_as)) { - const llvm::Triple &T(getToolChain().getTriple()); if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) CmdArgs.push_back("-Q"); } @@ -130,8 +131,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, AddMachOArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getTriple().isX86() || - Args.hasArg(options::OPT_force__cpusubtype__ALL)) + if (T.isX86() || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); if (getToolChain().getArch() != llvm::Triple::x86_64 && @@ -729,6 +729,54 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(std::move(Cmd)); } +void darwin::StaticLibTool::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + // libtool + ArgStringList CmdArgs; + // Create and insert file members with a deterministic index. + CmdArgs.push_back("-static"); + CmdArgs.push_back("-D"); + CmdArgs.push_back("-no_warning_for_no_symbols"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + } + } + + // Delete old output archive file if it already exists before generating a new + // archive file. + const auto *OutputFileName = Output.getFilename(); + if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) { + if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) { + D.Diag(diag::err_drv_unable_to_remove_file) << EC.message(); + return; + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath()); + C.addCommand(std::make_unique(JA, *this, + ResponseFileSupport::AtFileUTF8(), + Exec, CmdArgs, Inputs, Output)); +} + void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -982,6 +1030,10 @@ Tool *MachO::getTool(Action::ActionClass AC) const { Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } +Tool *MachO::buildStaticLibTool() const { + return new tools::darwin::StaticLibTool(*this); +} + Tool *MachO::buildAssembler() const { return new tools::darwin::Assembler(*this); } @@ -1305,7 +1357,7 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, return; } - const SanitizerArgs &Sanitize = getSanitizerArgs(); + const SanitizerArgs &Sanitize = getSanitizerArgs(Args); if (Sanitize.needsAsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); if (Sanitize.needsLsanRt()) @@ -1379,6 +1431,8 @@ struct DarwinPlatform { enum SourceKind { /// The OS was specified using the -target argument. TargetArg, + /// The OS was specified using the -mtargetos= argument. + MTargetOSArg, /// The OS was specified using the -m-version-min argument. OSVersionArg, /// The OS was specified using the OS_DEPLOYMENT_TARGET environment. @@ -1430,7 +1484,8 @@ struct DarwinPlatform { void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { if (Argument) return; - assert(Kind != TargetArg && Kind != OSVersionArg && "Invalid kind"); + assert(Kind != TargetArg && Kind != MTargetOSArg && Kind != OSVersionArg && + "Invalid kind"); options::ID Opt; switch (Platform) { case DarwinPlatformKind::MacOS: @@ -1455,6 +1510,7 @@ struct DarwinPlatform { std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { switch (Kind) { case TargetArg: + case MTargetOSArg: case OSVersionArg: case InferredFromSDK: case InferredFromArch: @@ -1466,6 +1522,33 @@ struct DarwinPlatform { llvm_unreachable("Unsupported Darwin Source Kind"); } + void setEnvironment(llvm::Triple::EnvironmentType EnvType, + const VersionTuple &OSVersion, + const Optional &SDKInfo) { + switch (EnvType) { + case llvm::Triple::Simulator: + Environment = DarwinEnvironmentKind::Simulator; + break; + case llvm::Triple::MacABI: { + Environment = DarwinEnvironmentKind::MacCatalyst; + // The minimum native macOS target for MacCatalyst is macOS 10.15. + NativeTargetVersion = VersionTuple(10, 15); + if (HasOSVersion && SDKInfo) { + if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping( + DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) { + if (auto MacOSVersion = MacCatalystToMacOSMapping->map( + OSVersion, NativeTargetVersion, None)) { + NativeTargetVersion = *MacOSVersion; + } + } + } + break; + } + default: + break; + } + } + static DarwinPlatform createFromTarget(const llvm::Triple &TT, StringRef OSVersion, Arg *A, const Optional &SDKInfo) { @@ -1475,31 +1558,18 @@ struct DarwinPlatform { TT.getOSVersion(Major, Minor, Micro); if (Major == 0) Result.HasOSVersion = false; - - switch (TT.getEnvironment()) { - case llvm::Triple::Simulator: - Result.Environment = DarwinEnvironmentKind::Simulator; - break; - case llvm::Triple::MacABI: { - // The minimum native macOS target for MacCatalyst is macOS 10.15. - auto NativeTargetVersion = VersionTuple(10, 15); - if (Result.HasOSVersion && SDKInfo) { - if (const auto *MacCatalystToMacOSMapping = SDKInfo->getVersionMapping( - DarwinSDKInfo::OSEnvPair::macCatalystToMacOSPair())) { - if (auto MacOSVersion = MacCatalystToMacOSMapping->map( - VersionTuple(Major, Minor, Micro), NativeTargetVersion, - None)) { - NativeTargetVersion = *MacOSVersion; - } - } - } - Result.Environment = DarwinEnvironmentKind::MacCatalyst; - Result.NativeTargetVersion = NativeTargetVersion; - break; - } - default: - break; - } + Result.setEnvironment(TT.getEnvironment(), + VersionTuple(Major, Minor, Micro), SDKInfo); + return Result; + } + static DarwinPlatform + createFromMTargetOS(llvm::Triple::OSType OS, VersionTuple OSVersion, + llvm::Triple::EnvironmentType Environment, Arg *A, + const Optional &SDKInfo) { + DarwinPlatform Result(MTargetOSArg, getPlatformFromOS(OS), + OSVersion.getAsString(), A); + Result.InferSimulatorFromArch = false; + Result.setEnvironment(Environment, OSVersion, SDKInfo); return Result; } static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, @@ -1750,7 +1820,12 @@ std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, << Triple.getOSName(); break; case llvm::Triple::IOS: - Triple.getiOSVersion(Major, Minor, Micro); + if (Triple.isMacCatalystEnvironment() && !Triple.getOSMajorVersion()) { + Major = 13; + Minor = 1; + Micro = 0; + } else + Triple.getiOSVersion(Major, Minor, Micro); break; case llvm::Triple::TvOS: Triple.getOSVersion(Major, Minor, Micro); @@ -1813,6 +1888,39 @@ Optional getDeploymentTargetFromTargetArg( Triple, OSVersion, Args.getLastArg(options::OPT_target), SDKInfo); } +/// Returns the deployment target that's specified using the -mtargetos option. +Optional +getDeploymentTargetFromMTargetOSArg(DerivedArgList &Args, + const Driver &TheDriver, + const Optional &SDKInfo) { + auto *A = Args.getLastArg(options::OPT_mtargetos_EQ); + if (!A) + return None; + llvm::Triple TT(llvm::Twine("unknown-apple-") + A->getValue()); + switch (TT.getOS()) { + case llvm::Triple::MacOSX: + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + case llvm::Triple::WatchOS: + break; + default: + TheDriver.Diag(diag::err_drv_invalid_os_in_arg) + << TT.getOSName() << A->getAsString(Args); + return None; + } + + unsigned Major, Minor, Micro; + TT.getOSVersion(Major, Minor, Micro); + if (!Major) { + TheDriver.Diag(diag::err_drv_invalid_version_number) + << A->getAsString(Args); + return None; + } + return DarwinPlatform::createFromMTargetOS(TT.getOS(), + VersionTuple(Major, Minor, Micro), + TT.getEnvironment(), A, SDKInfo); +} + Optional parseSDKSettings(llvm::vfs::FileSystem &VFS, const ArgList &Args, const Driver &TheDriver) { @@ -1861,6 +1969,13 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Optional OSTarget = getDeploymentTargetFromTargetArg(Args, getTriple(), getDriver(), SDKInfo); if (OSTarget) { + // Disallow mixing -target and -mtargetos=. + if (const auto *MTargetOSArg = Args.getLastArg(options::OPT_mtargetos_EQ)) { + std::string TargetArgStr = OSTarget->getAsString(Args, Opts); + std::string MTargetOSArgStr = MTargetOSArg->getAsString(Args); + getDriver().Diag(diag::err_drv_cannot_mix_options) + << TargetArgStr << MTargetOSArgStr; + } Optional OSVersionArgTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); if (OSVersionArgTarget) { @@ -1892,6 +2007,18 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } } + } else if ((OSTarget = getDeploymentTargetFromMTargetOSArg(Args, getDriver(), + SDKInfo))) { + // The OS target can be specified using the -mtargetos= argument. + // Disallow mixing -mtargetos= and -mversion-min=. + Optional OSVersionArgTarget = + getDeploymentTargetFromOSVersionArg(Args, getDriver()); + if (OSVersionArgTarget) { + std::string MTargetOSArgStr = OSTarget->getAsString(Args, Opts); + std::string OSVersionArgStr = OSVersionArgTarget->getAsString(Args, Opts); + getDriver().Diag(diag::err_drv_cannot_mix_options) + << MTargetOSArgStr << OSVersionArgStr; + } } else { // The OS target can be specified using the -mversion-min argument. OSTarget = getDeploymentTargetFromOSVersionArg(Args, getDriver()); @@ -2656,7 +2783,7 @@ bool Darwin::SupportsEmbeddedBitcode() const { bool MachO::isPICDefault() const { return true; } -bool MachO::isPIEDefault() const { return false; } +bool MachO::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } bool MachO::isPICDefaultForced() const { return (getArch() == llvm::Triple::x86_64 || diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 4de122c8d51..a307cd317ac 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -78,6 +78,20 @@ public: const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY StaticLibTool : public MachOTool { +public: + StaticLibTool(const ToolChain &TC) + : MachOTool("darwin::StaticLibTool", "static-lib-linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { public: Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", TC) {} @@ -125,6 +139,7 @@ class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + Tool *buildStaticLibTool() const override; Tool *getTool(Action::ActionClass AC) const override; private: @@ -239,7 +254,7 @@ public: } bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 1bfad6115d5..b82c5d7600d 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -37,8 +37,9 @@ void Flang::AddFortranDialectOptions(const ArgList &Args, void Flang::AddPreprocessingOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I, - options::OPT_cpp, options::OPT_nocpp}); + Args.AddAllArgs(CmdArgs, + {options::OPT_P, options::OPT_D, options::OPT_U, + options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); } void Flang::AddOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 5dcf74dabf4..dc05f989346 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -99,7 +99,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: { - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); @@ -110,7 +110,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { @@ -145,7 +145,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const llvm::Triple::ArchType Arch = ToolChain.getArch(); const bool IsPIE = !Args.hasArg(options::OPT_shared) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault(Args)); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -467,7 +467,9 @@ bool FreeBSD::HasNativeLLVMSupport() const { return true; } bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } -bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +bool FreeBSD::isPIEDefault(const llvm::opt::ArgList &Args) const { + return getSanitizerArgs(Args).requiresPIE(); +} SanitizerMask FreeBSD::getSupportedSanitizers() const { const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64; diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index abc0876cef2..2a721c750a6 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -74,7 +74,7 @@ public: llvm::ExceptionHandling GetExceptionModel(const llvm::opt::ArgList &Args) const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override; // Until dtrace (via CTF) and LLDB can deal with distributed debug info, diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index fd9804a7f35..a7afec6963a 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -60,6 +60,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("rodynamic"); CmdArgs.push_back("-z"); CmdArgs.push_back("separate-loadable-segments"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("rel"); CmdArgs.push_back("--pack-dyn-relocs=relr"); } @@ -89,7 +91,7 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, else if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); + const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); if (!Args.hasArg(options::OPT_shared)) { std::string Dyld = D.DyldPrefix; @@ -247,17 +249,16 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, Multilibs.FilterOut([&](const Multilib &M) { std::vector RD = FilePaths(M); - return std::all_of(RD.begin(), RD.end(), [&](std::string P) { - return !getVFS().exists(P); - }); + return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); }); }); Multilib::flags_list Flags; addMultilibFlag( Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), "fexceptions", Flags); - addMultilibFlag(getSanitizerArgs().needsAsanRt(), "fsanitize=address", Flags); - addMultilibFlag(getSanitizerArgs().needsHwasanRt(), "fsanitize=hwaddress", + addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address", + Flags); + addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress", Flags); addMultilibFlag( @@ -437,13 +438,3 @@ SanitizerMask Fuchsia::getDefaultSanitizers() const { } return Res; } - -void Fuchsia::addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { - // Add linker option -u__llvm_profile_runtime to cause runtime - // initialization module to be linked in. - if (needsProfileRT(Args)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); - ToolChain::addProfileRTLibs(Args, CmdArgs); -} diff --git a/clang/lib/Driver/ToolChains/Fuchsia.h b/clang/lib/Driver/ToolChains/Fuchsia.h index 07adf9b7101..c0e69df2282 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.h +++ b/clang/lib/Driver/ToolChains/Fuchsia.h @@ -54,7 +54,9 @@ public: return true; } bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return true; + } bool isPICDefaultForced() const override { return false; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::GDB; @@ -71,9 +73,6 @@ public: SanitizerMask getSupportedSanitizers() const override; SanitizerMask getDefaultSanitizers() const override; - void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; CXXStdlibType diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index da39f29e461..7aeadd84dfe 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -312,7 +312,7 @@ static bool getPIE(const ArgList &Args, const ToolChain &TC) { Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, options::OPT_nopie); if (!A) - return TC.isPIEDefault(); + return TC.isPIEDefault(Args); return A->getOption().matches(options::OPT_pie); } @@ -429,11 +429,6 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("text"); } - if (ToolChain.isNoExecStackDefault()) { - CmdArgs.push_back("-z"); - CmdArgs.push_back("noexecstack"); - } - if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); @@ -451,7 +446,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Most Android ARM64 targets should enable the linker fix for erratum // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. if (Arch == llvm::Triple::aarch64 && isAndroid) { - std::string CPU = getCPUName(Args, Triple); + std::string CPU = getCPUName(D, Args, Triple); if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") CmdArgs.push_back("--fix-cortex-a53-843419"); } @@ -473,17 +468,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, return; } - if (IsStatic) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || - Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) - CmdArgs.push_back("-Bstatic"); - else - CmdArgs.push_back("-static"); - } else if (Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_shared)) CmdArgs.push_back("-shared"); - } - if (!IsStatic) { + if (IsStatic) { + CmdArgs.push_back("-static"); + } else { if (Args.hasArg(options::OPT_rdynamic)) CmdArgs.push_back("-export-dynamic"); @@ -534,10 +524,10 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (P.empty()) { const char *crtbegin; - if (IsStatic) - crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared)) + if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (IsStatic) + crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; else if (IsPIE || IsStaticPIE) crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else @@ -712,10 +702,6 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } } - if (getToolChain().isNoExecStackDefault()) { - CmdArgs.push_back("--noexecstack"); - } - switch (getToolChain().getArch()) { default: break; @@ -734,32 +720,32 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back("-mbig-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppcle: { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); CmdArgs.push_back("-mlittle-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-mbig-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::ppc64le: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); CmdArgs.push_back("-mlittle-endian"); - CmdArgs.push_back( - ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); + CmdArgs.push_back(ppc::getPPCAsmModeForCPU( + getCPUName(D, Args, getToolChain().getTriple()))); break; } case llvm::Triple::riscv32: @@ -775,7 +761,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); @@ -783,7 +769,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); + std::string CPU = getCPUName(D, Args, getToolChain().getTriple()); CmdArgs.push_back( sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); AddAssemblerKPIC(getToolChain(), Args, CmdArgs); @@ -931,7 +917,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) + if (!Map.contains('=')) D.Diag(diag::err_drv_invalid_argument_to_option) << Map << A->getOption().getName(); else { @@ -1086,7 +1072,8 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, .flag("-m32") .flag("-mabi=n32"); - Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + Multilib M32 = + Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32"); DebianMipsMultilibs = MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); @@ -1473,7 +1460,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); - addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", + addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "mnan=2008", Flags); addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); @@ -2052,7 +2039,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // Non-Solaris is much simpler - most systems just go with "/usr". if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { - // Yet, still look for RHEL devtoolsets. + // Yet, still look for RHEL/CentOS devtoolsets and gcc-toolsets. + Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-10/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); @@ -2074,24 +2062,28 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( // Declare a bunch of static data sets that we'll select between below. These // are specifically designed to always refer to string literals to avoid any // lifetime or initialization issues. + // + // The *Triples variables hard code some triples so that, for example, + // --target=aarch64 (incomplete triple) can detect lib/aarch64-linux-gnu. + // They are not needed when the user has correct LLVM_DEFAULT_TARGET_TRIPLE + // and always uses the full --target (e.g. --target=aarch64-linux-gnu). The + // lists should shrink over time. Please don't add more elements to *Triples. static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; static const char *const AArch64Triples[] = { "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux", - "aarch64-suse-linux", "aarch64-linux-android"}; + "aarch64-suse-linux"}; static const char *const AArch64beLibDirs[] = {"/lib"}; static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", "aarch64_be-linux-gnu"}; static const char *const ARMLibDirs[] = {"/lib"}; - static const char *const ARMTriples[] = {"arm-linux-gnueabi", - "arm-linux-androideabi"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi"}; static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", "armv7hl-redhat-linux-gnueabi", "armv6hl-suse-linux-gnueabi", "armv7hl-suse-linux-gnueabi"}; static const char *const ARMebLibDirs[] = {"/lib"}; - static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", - "armeb-linux-androideabi"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi"}; static const char *const ARMebHFTriples[] = { "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; @@ -2105,31 +2097,28 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( "x86_64-redhat-linux", "x86_64-suse-linux", "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", "x86_64-slackware-linux", "x86_64-unknown-linux", - "x86_64-amazon-linux", "x86_64-linux-android"}; + "x86_64-amazon-linux"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; static const char *const X32LibDirs[] = {"/libx32", "/lib"}; static const char *const X86LibDirs[] = {"/lib32", "/lib"}; static const char *const X86Triples[] = { - "i586-linux-gnu", "i686-linux-gnu", - "i686-pc-linux-gnu", "i386-redhat-linux6E", - "i686-redhat-linux", "i386-redhat-linux", - "i586-suse-linux", "i686-montavista-linux", - "i686-linux-android", "i686-gnu", + "i586-linux-gnu", "i686-linux-gnu", "i686-pc-linux-gnu", + "i386-redhat-linux6E", "i686-redhat-linux", "i386-redhat-linux", + "i586-suse-linux", "i686-montavista-linux", "i686-gnu", }; static const char *const M68kLibDirs[] = {"/lib"}; static const char *const M68kTriples[] = { "m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"}; - static const char *const MIPSLibDirs[] = {"/lib"}; + static const char *const MIPSLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSTriples[] = { "mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6-linux-gnu"}; - static const char *const MIPSELLibDirs[] = {"/lib"}; + static const char *const MIPSELLibDirs[] = {"/libo32", "/lib"}; static const char *const MIPSELTriples[] = { - "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu", - "mipsel-linux-android"}; + "mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu"}; static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; static const char *const MIPS64Triples[] = { @@ -2140,8 +2129,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const MIPS64ELTriples[] = { "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", "mips64el-linux-gnuabi64", - "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64", - "mips64el-linux-android"}; + "mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64"}; static const char *const MIPSN32LibDirs[] = {"/lib32"}; static const char *const MIPSN32Triples[] = {"mips64-linux-gnuabin32", @@ -2181,9 +2169,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"}; static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu", "riscv64-linux-gnu", - "riscv64-unknown-elf", - "riscv64-redhat-linux", - "riscv64-suse-linux"}; + "riscv64-unknown-elf"}; static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", @@ -2708,6 +2694,7 @@ bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const { case llvm::Triple::ppcle: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: + case llvm::Triple::x86: case llvm::Triple::x86_64: return true; default: @@ -2727,7 +2714,9 @@ bool Generic_GCC::isPICDefault() const { } } -bool Generic_GCC::isPIEDefault() const { return false; } +bool Generic_GCC::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool Generic_GCC::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 40fd756a565..4eb7ab0215a 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -298,7 +298,7 @@ public: bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; llvm::opt::DerivedArgList * diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index 59d58aadb68..07af1a0457c 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -16,6 +16,7 @@ #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/InputInfo.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -37,6 +38,43 @@ namespace { const unsigned HIPCodeObjectAlign = 4096; } // namespace +static bool shouldSkipSanitizeOption(const ToolChain &TC, + const llvm::opt::ArgList &DriverArgs, + StringRef TargetID, + const llvm::opt::Arg *A) { + // For actions without targetID, do nothing. + if (TargetID.empty()) + return false; + Option O = A->getOption(); + if (!O.matches(options::OPT_fsanitize_EQ)) + return false; + + if (!DriverArgs.hasFlag(options::OPT_fgpu_sanitize, + -options::OPT_fno_gpu_sanitize)) + return true; + + auto &Diags = TC.getDriver().getDiags(); + + // For simplicity, we only allow -fsanitize=address + SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); + if (K != SanitizerKind::Address) + return true; + + llvm::StringMap FeatureMap; + auto OptionalGpuArch = parseTargetID(TC.getTriple(), TargetID, &FeatureMap); + + assert(OptionalGpuArch && "Invalid Target ID"); + (void)OptionalGpuArch; + auto Loc = FeatureMap.find("xnack"); + if (Loc == FeatureMap.end() || !Loc->second) { + Diags.Report( + clang::diag::warn_drv_unsupported_option_for_offload_arch_req_feature) + << A->getAsString(DriverArgs) << TargetID << "xnack+"; + return true; + } + return false; +} + void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const InputInfo &Output, @@ -86,12 +124,6 @@ void AMDGCN::Linker::constructLldCommand(Compilation &C, const JobAction &JA, for (auto Input : Inputs) LldArgs.push_back(Input.getFilename()); - if (Args.hasFlag(options::OPT_fgpu_sanitize, options::OPT_fno_gpu_sanitize, - false)) - llvm::for_each(TC.getHIPDeviceLibs(Args), [&](StringRef BCFile) { - LldArgs.push_back(Args.MakeArgString(BCFile)); - }); - const char *Lld = Args.MakeArgString(getToolChain().GetProgramPath("lld")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), Lld, LldArgs, Inputs, Output)); @@ -237,6 +269,14 @@ HIPToolChain::HIPToolChain(const Driver &D, const llvm::Triple &Triple, // Lookup binaries into the driver directory, this is used to // discover the clang-offload-bundler executable. getProgramPaths().push_back(getDriver().Dir); + + // Diagnose unsupported sanitizer options only once. + for (auto A : Args.filtered(options::OPT_fsanitize_EQ)) { + SanitizerMask K = parseSanitizerValue(A->getValue(), /*AllowGroups=*/false); + if (K != SanitizerKind::Address) + D.getDiags().Report(clang::diag::warn_drv_unsupported_option_for_target) + << A->getAsString(Args) << getTriple().str(); + } } void HIPToolChain::addClangTargetOptions( @@ -276,9 +316,10 @@ void HIPToolChain::addClangTargetOptions( CC1Args.push_back("-fapply-global-visibility-to-externs"); } - llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](StringRef BCFile) { - CC1Args.push_back("-mlink-builtin-bitcode"); - CC1Args.push_back(DriverArgs.MakeArgString(BCFile)); + llvm::for_each(getHIPDeviceLibs(DriverArgs), [&](auto BCFile) { + CC1Args.push_back(BCFile.ShouldInternalize ? "-mlink-builtin-bitcode" + : "-mlink-bitcode-file"); + CC1Args.push_back(DriverArgs.MakeArgString(BCFile.Path)); }); } @@ -294,7 +335,8 @@ HIPToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); for (Arg *A : Args) { - if (!shouldSkipArgument(A)) + if (!shouldSkipArgument(A) && + !shouldSkipSanitizeOption(*this, Args, BoundArch, A)) DAL->append(A); } @@ -359,9 +401,9 @@ VersionTuple HIPToolChain::computeMSVCVersion(const Driver *D, return HostTC.computeMSVCVersion(D, Args); } -llvm::SmallVector +llvm::SmallVector HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { - llvm::SmallVector BCLibs; + llvm::SmallVector BCLibs; if (DriverArgs.hasArg(options::OPT_nogpulib)) return {}; ArgStringList LibraryPaths; @@ -382,7 +424,7 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { llvm::sys::path::append(Path, BCName); FullName = Path; if (llvm::sys::fs::exists(FullName)) { - BCLibs.push_back(FullName.str()); + BCLibs.push_back(FullName); return; } } @@ -395,37 +437,11 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { } StringRef GpuArch = getGPUArch(DriverArgs); assert(!GpuArch.empty() && "Must have an explicit GPU arch."); - (void)GpuArch; - auto Kind = llvm::AMDGPU::parseArchAMDGCN(GpuArch); - const StringRef CanonArch = llvm::AMDGPU::getArchNameAMDGCN(Kind); - - std::string LibDeviceFile = RocmInstallation.getLibDeviceFile(CanonArch); - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_rocm_device_lib) << 1 << GpuArch; - return {}; - } // If --hip-device-lib is not set, add the default bitcode libraries. - // TODO: There are way too many flags that change this. Do we need to check - // them all? - bool DAZ = DriverArgs.hasFlag(options::OPT_fgpu_flush_denormals_to_zero, - options::OPT_fno_gpu_flush_denormals_to_zero, - getDefaultDenormsAreZeroForTarget(Kind)); - bool FiniteOnly = - DriverArgs.hasFlag(options::OPT_ffinite_math_only, - options::OPT_fno_finite_math_only, false); - bool UnsafeMathOpt = - DriverArgs.hasFlag(options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, false); - bool FastRelaxedMath = DriverArgs.hasFlag( - options::OPT_ffast_math, options::OPT_fno_fast_math, false); - bool CorrectSqrt = DriverArgs.hasFlag( - options::OPT_fhip_fp32_correctly_rounded_divide_sqrt, - options::OPT_fno_hip_fp32_correctly_rounded_divide_sqrt); - bool Wave64 = isWave64(DriverArgs, Kind); - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false)) { + options::OPT_fno_gpu_sanitize) && + getSanitizerArgs(DriverArgs).needsAsanRt()) { auto AsanRTL = RocmInstallation.getAsanRTLPath(); if (AsanRTL.empty()) { unsigned DiagID = getDriver().getDiags().getCustomDiagID( @@ -436,16 +452,15 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { getDriver().Diag(DiagID); return {}; } else - BCLibs.push_back(AsanRTL.str()); + BCLibs.push_back({AsanRTL.str(), /*ShouldInternalize=*/false}); } // Add the HIP specific bitcode library. - BCLibs.push_back(RocmInstallation.getHIPPath().str()); + BCLibs.push_back(RocmInstallation.getHIPPath()); - // Add the generic set of libraries. - BCLibs.append(RocmInstallation.getCommonBitcodeLibs( - DriverArgs, LibDeviceFile, Wave64, DAZ, FiniteOnly, UnsafeMathOpt, - FastRelaxedMath, CorrectSqrt)); + // Add common device libraries like ocml etc. + for (auto N : getCommonDeviceLibNames(DriverArgs, GpuArch.str())) + BCLibs.push_back(StringRef(N)); // Add instrument lib. auto InstLib = @@ -453,7 +468,7 @@ HIPToolChain::getHIPDeviceLibs(const llvm::opt::ArgList &DriverArgs) const { if (InstLib.empty()) return BCLibs; if (llvm::sys::fs::exists(InstLib)) - BCLibs.push_back(InstLib.str()); + BCLibs.push_back(InstLib); else getDriver().Diag(diag::err_drv_no_such_file) << InstLib; } @@ -466,22 +481,6 @@ void HIPToolChain::checkTargetID(const llvm::opt::ArgList &DriverArgs) const { if (PTID.OptionalTargetID && !PTID.OptionalGPUArch) { getDriver().Diag(clang::diag::err_drv_bad_target_id) << PTID.OptionalTargetID.getValue(); - return; - } - - assert(PTID.OptionalFeatures && "Invalid return from getParsedTargetID"); - auto &FeatureMap = PTID.OptionalFeatures.getValue(); - // Sanitizer is not supported with xnack-. - if (DriverArgs.hasFlag(options::OPT_fgpu_sanitize, - options::OPT_fno_gpu_sanitize, false)) { - auto Loc = FeatureMap.find("xnack"); - if (Loc != FeatureMap.end() && !Loc->second) { - auto &Diags = getDriver().getDiags(); - auto DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, - "'-fgpu-sanitize' is not compatible with offload arch '%0'. " - "Use an offload arch without 'xnack-' instead"); - Diags.Report(DiagID) << PTID.OptionalTargetID.getValue(); - } } + return; } diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index 3cced0a320d..60b3d69b3f5 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -83,7 +83,7 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddHIPIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - llvm::SmallVector + llvm::SmallVector getHIPDeviceLibs(const llvm::opt::ArgList &Args) const override; SanitizerMask getSupportedSanitizers() const override; @@ -92,7 +92,7 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 4; } + unsigned GetDefaultDwarfVersion() const override { return 5; } const ToolChain &HostTC; void checkTargetID(const llvm::opt::ArgList &DriverArgs) const override; diff --git a/clang/lib/Driver/ToolChains/Haiku.h b/clang/lib/Driver/ToolChains/Haiku.h index 2bc98322beb..669379a2160 100644 --- a/clang/lib/Driver/ToolChains/Haiku.h +++ b/clang/lib/Driver/ToolChains/Haiku.h @@ -22,7 +22,7 @@ public: Haiku(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { return getTriple().getArch() == llvm::Triple::x86_64; } diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 828bfdbb05a..18270818d15 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -146,6 +146,8 @@ void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, "-mcpu=hexagon" + toolchains::HexagonToolChain::GetTargetCPUVersion(Args))); + addSanitizerRuntimes(HTC, Args, CmdArgs); + if (Output.isFilename()) { CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -223,6 +225,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool UseShared = IsShared && !IsStatic; StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); + bool NeedsSanitizerDeps = addSanitizerRuntimes(HTC, Args, CmdArgs); + //---------------------------------------------------------------------------- // Silence warnings for various options //---------------------------------------------------------------------------- @@ -288,6 +292,12 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (NeedsSanitizerDeps) { + linkSanitizerRuntimeDeps(HTC, CmdArgs); + + CmdArgs.push_back("-lunwind"); + } + CmdArgs.push_back("-lclang_rt.builtins-hexagon"); CmdArgs.push_back("-lc"); } @@ -450,6 +460,13 @@ Optional HexagonToolChain::getSmallDataThreshold( return None; } +std::string HexagonToolChain::getCompilerRTPath() const { + SmallString<128> Dir(getDriver().SysRoot); + llvm::sys::path::append(Dir, "usr", "lib"); + Dir += SelectedMultilib.gccSuffix(); + return std::string(Dir.str()); +} + void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, ToolChain::path_list &LibPaths) const { const Driver &D = getDriver(); @@ -470,7 +487,7 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); - if (llvm::find(RootDirs, TargetDir) == RootDirs.end()) + if (!llvm::is_contained(RootDirs, TargetDir)) RootDirs.push_back(TargetDir); bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); @@ -588,21 +605,43 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc)) + if (DriverArgs.hasArg(options::OPT_nostdinc)) return; + const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux(); + const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux(); + const Driver &D = getDriver(); - if (!D.SysRoot.empty()) { + SmallString<128> ResourceDirInclude(D.ResourceDir); + if (!IsELF) { + llvm::sys::path::append(ResourceDirInclude, "include"); + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && + (!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc))) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + } + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const bool HasSysRoot = !D.SysRoot.empty(); + if (HasSysRoot) { SmallString<128> P(D.SysRoot); - if (getTriple().isMusl()) + if (IsLinuxMusl) llvm::sys::path::append(P, "usr/include"); else llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); - return; + // LOCAL_INCLUDE_DIR + addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include"); + // TOOL_INCLUDE_DIR + AddMultilibIncludeArgs(DriverArgs, CC1Args); } + if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl) + addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); + + if (HasSysRoot) + return; std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), D.PrefixDirs); addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); @@ -665,11 +704,11 @@ bool HexagonToolChain::isAutoHVXEnabled(const llvm::opt::ArgList &Args) { // Returns the default CPU for Hexagon. This is the default compilation target // if no Hexagon processor is selected at the command-line. // -const StringRef HexagonToolChain::GetDefaultCPU() { +StringRef HexagonToolChain::GetDefaultCPU() { return "hexagonv60"; } -const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { +StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { Arg *CpuArg = nullptr; if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) CpuArg = A; diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h index c32cb7f0959..89963055535 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.h +++ b/clang/lib/Driver/ToolChains/Hexagon.h @@ -104,9 +104,11 @@ public: void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, ToolChain::path_list &LibPaths) const; + std::string getCompilerRTPath() const override; + static bool isAutoHVXEnabled(const llvm::opt::ArgList &Args); - static const StringRef GetDefaultCPU(); - static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); + static StringRef GetDefaultCPU(); + static StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); static Optional getSmallDataThreshold( const llvm::opt::ArgList &Args); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index c9360fc6716..0224383e63a 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -206,8 +206,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("max-page-size=4096"); } - if (GCCInstallation.getParentLibPath().find("opt/rh/devtoolset") != - StringRef::npos) + if (GCCInstallation.getParentLibPath().contains("opt/rh/")) // With devtoolset on RHEL, we want to add a bin directory that is relative // to the detected gcc install, because if we are using devtoolset gcc then // we want to use other tools from devtoolset (e.g. ld) instead of the @@ -262,6 +261,13 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const std::string OSLibDir = std::string(getOSLibDir(Triple, Args)); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + // mips32: Debian multilib, we use /libo32, while in other case, /lib is + // used. We need add both libo32 and /lib. + if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel) { + Generic_GCC::AddMultilibPaths(D, SysRoot, "libo32", MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/libo32", Paths); + addPathIfExists(D, SysRoot + "/usr/libo32", Paths); + } Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths); addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); @@ -303,8 +309,13 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // searched. // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) + if (StringRef(D.Dir).startswith(SysRoot)) { + // Even if OSLibDir != "lib", this is needed for Clang in the build + // directory (not installed) to find libc++. addPathIfExists(D, D.Dir + "/../lib", Paths); + if (OSLibDir != "lib") + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); + } addPathIfExists(D, SysRoot + "/lib", Paths); addPathIfExists(D, SysRoot + "/usr/lib", Paths); @@ -449,7 +460,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: { - bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple); + bool IsNaN2008 = tools::mips::isNaN2008(getDriver(), Args, Triple); LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple); @@ -651,9 +662,9 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } -bool Linux::isPIEDefault() const { - return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || - getTriple().isMusl() || getSanitizerArgs().requiresPIE(); +bool Linux::isPIEDefault(const llvm::opt::ArgList &Args) const { + return getTriple().isAndroid() || getTriple().isMusl() || + getSanitizerArgs(Args).requiresPIE(); } bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { @@ -669,10 +680,6 @@ bool Linux::IsAArch64OutlineAtomicsDefault(const ArgList &Args) const { return true; } -bool Linux::isNoExecStackDefault() const { - return getTriple().isAndroid(); -} - bool Linux::IsMathErrnoDefault() const { if (getTriple().isAndroid()) return false; @@ -694,6 +701,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { getTriple().getArch() == llvm::Triple::thumbeb; const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64; const bool IsSystemZ = getTriple().getArch() == llvm::Triple::systemz; + const bool IsHexagon = getTriple().getArch() == llvm::Triple::hexagon; SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::PointerCompare; @@ -707,7 +715,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 || - IsRISCV64 || IsSystemZ) + IsRISCV64 || IsSystemZ || IsHexagon) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64 || IsSystemZ) Res |= SanitizerKind::Thread; @@ -716,7 +724,7 @@ SanitizerMask Linux::getSupportedSanitizers() const { if (IsX86 || IsX86_64) Res |= SanitizerKind::Function; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsMIPS || IsArmArch || - IsPowerPC64) + IsPowerPC64 || IsHexagon) Res |= SanitizerKind::Scudo; if (IsX86_64 || IsAArch64) { Res |= SanitizerKind::HWAddress; diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 169a37c4407..a5ec33bd44f 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -43,8 +43,7 @@ public: CXXStdlibType GetDefaultCXXStdlibType() const override; bool IsAArch64OutlineAtomicsDefault(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; - bool isNoExecStackDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool IsMathErrnoDefault() const override; SanitizerMask getSupportedSanitizers() const override; void addProfileRTLibs(const llvm::opt::ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/MSP430.h b/clang/lib/Driver/ToolChains/MSP430.h index 9d247ca3a89..2e838c027e0 100644 --- a/clang/lib/Driver/ToolChains/MSP430.h +++ b/clang/lib/Driver/ToolChains/MSP430.h @@ -37,7 +37,9 @@ public: Action::OffloadKind) const override; bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return true; } UnwindLibType diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 0dc94a4c6c7..792b0a51fea 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -63,6 +63,61 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +// Windows SDKs and VC Toolchains group their contents into subdirectories based +// on the target architecture. This function converts an llvm::Triple::ArchType +// to the corresponding subdirectory name. +static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + return "x86"; + case ArchType::x86_64: + return "x64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + +// Similar to the above function, but for Visual Studios before VS2017. +static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + // x86 is default in legacy VC toolchains. + // e.g. x86 libs are directly in /lib as opposed to /lib/x86. + return ""; + case ArchType::x86_64: + return "amd64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + +// Similar to the above function, but for DevDiv internal builds. +static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { + using ArchType = llvm::Triple::ArchType; + switch (Arch) { + case ArchType::x86: + return "i386"; + case ArchType::x86_64: + return "amd64"; + case ArchType::arm: + return "arm"; + case ArchType::aarch64: + return "arm64"; + default: + return ""; + } +} + static bool canExecute(llvm::vfs::FileSystem &VFS, StringRef Path) { auto Status = VFS.status(Path); if (!Status) @@ -396,6 +451,20 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, // the environment variable is set however, assume the user knows what // they're doing. If the user passes /vctoolsdir or /winsdkdir, trust that // over env vars. + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diasdkdir, + options::OPT__SLASH_winsysroot)) { + // cl.exe doesn't find the DIA SDK automatically, so this too requires + // explicit flags and doesn't automatically look in "DIA SDK" relative + // to the path we found for VCToolChainPath. + llvm::SmallString<128> DIAPath(A->getValue()); + if (A->getOption().getID() == options::OPT__SLASH_winsysroot) + llvm::sys::path::append(DIAPath, "DIA SDK"); + + // The DIA SDK always uses the legacy vc arch, even in new MSVC versions. + llvm::sys::path::append(DIAPath, "lib", + llvmArchToLegacyVCArch(TC.getArch())); + CmdArgs.push_back(Args.MakeArgString(Twine("-libpath:") + DIAPath)); + } if (!llvm::sys::Process::GetEnv("LIB") || Args.getLastArg(options::OPT__SLASH_vctoolsdir, options::OPT__SLASH_winsysroot)) { @@ -461,7 +530,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); } - if (TC.getSanitizerArgs().needsFuzzer()) { + if (TC.getSanitizerArgs(Args).needsFuzzer()) { if (!Args.hasArg(options::OPT_shared)) CmdArgs.push_back( Args.MakeArgString(std::string("-wholearchive:") + @@ -472,10 +541,10 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString("-incremental:no")); } - if (TC.getSanitizerArgs().needsAsanRt()) { + if (TC.getSanitizerArgs(Args).needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs().needsSharedRt() || + if (TC.getSanitizerArgs(Args).needsSharedRt() || Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); @@ -726,15 +795,17 @@ bool MSVCToolChain::IsUnwindTablesDefault(const ArgList &Args) const { } bool MSVCToolChain::isPICDefault() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } -bool MSVCToolChain::isPIEDefault() const { +bool MSVCToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { return false; } bool MSVCToolChain::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } void MSVCToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, @@ -752,61 +823,6 @@ void MSVCToolChain::printVerboseInfo(raw_ostream &OS) const { RocmInstallation.print(OS); } -// Windows SDKs and VC Toolchains group their contents into subdirectories based -// on the target architecture. This function converts an llvm::Triple::ArchType -// to the corresponding subdirectory name. -static const char *llvmArchToWindowsSDKArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "x86"; - case ArchType::x86_64: - return "x64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for Visual Studios before VS2017. -static const char *llvmArchToLegacyVCArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - // x86 is default in legacy VC toolchains. - // e.g. x86 libs are directly in /lib as opposed to /lib/x86. - return ""; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - -// Similar to the above function, but for DevDiv internal builds. -static const char *llvmArchToDevDivInternalArch(llvm::Triple::ArchType Arch) { - using ArchType = llvm::Triple::ArchType; - switch (Arch) { - case ArchType::x86: - return "i386"; - case ArchType::x86_64: - return "amd64"; - case ArchType::arm: - return "arm"; - case ArchType::aarch64: - return "arm64"; - default: - return ""; - } -} - // Get the path to a specific subdirectory in the current toolchain for // a given target architecture. // VS2017 changed the VC toolchain layout, so this should be used instead @@ -1263,6 +1279,19 @@ void MSVCToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, AddSystemIncludesFromEnv(Var); } + // Add DIA SDK include if requested. + if (const Arg *A = DriverArgs.getLastArg(options::OPT__SLASH_diasdkdir, + options::OPT__SLASH_winsysroot)) { + // cl.exe doesn't find the DIA SDK automatically, so this too requires + // explicit flags and doesn't automatically look in "DIA SDK" relative + // to the path we found for VCToolChainPath. + llvm::SmallString<128> DIASDKPath(A->getValue()); + if (A->getOption().getID() == options::OPT__SLASH_winsysroot) + llvm::sys::path::append(DIASDKPath, "DIA SDK"); + AddSystemIncludeWithSubfolder(DriverArgs, CC1Args, std::string(DIASDKPath), + "include"); + } + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) return; diff --git a/clang/lib/Driver/ToolChains/MSVC.h b/clang/lib/Driver/ToolChains/MSVC.h index 19d94c5c606..8f033de09bf 100644 --- a/clang/lib/Driver/ToolChains/MSVC.h +++ b/clang/lib/Driver/ToolChains/MSVC.h @@ -52,7 +52,7 @@ public: bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; /// Set CodeView as the default debug info format for non-MachO binary diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 20efbdc237a..ecce2f062bd 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -98,7 +98,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const ToolChain &TC = getToolChain(); const Driver &D = TC.getDriver(); - const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); + const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args); ArgStringList CmdArgs; @@ -136,10 +136,13 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, llvm_unreachable("Unsupported target architecture."); } - if (Args.hasArg(options::OPT_mwindows)) { + Arg *SubsysArg = + Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole); + if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("windows"); - } else if (Args.hasArg(options::OPT_mconsole)) { + } else if (SubsysArg && + SubsysArg->getOption().matches(options::OPT_mconsole)) { CmdArgs.push_back("--subsystem"); CmdArgs.push_back("console"); } @@ -346,29 +349,29 @@ static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, } void toolchains::MinGW::findGccLibDir() { - llvm::SmallVector, 2> Archs; - Archs.emplace_back(getTriple().getArchName()); - Archs[0] += "-w64-mingw32"; - Archs.emplace_back("mingw32"); - if (Arch.empty()) - Arch = std::string(Archs[0].str()); + llvm::SmallVector, 2> SubdirNames; + SubdirNames.emplace_back(getTriple().getArchName()); + SubdirNames[0] += "-w64-mingw32"; + SubdirNames.emplace_back("mingw32"); + if (SubdirName.empty()) + SubdirName = std::string(SubdirNames[0].str()); // lib: Arch Linux, Ubuntu, Windows // lib64: openSUSE Linux for (StringRef CandidateLib : {"lib", "lib64"}) { - for (StringRef CandidateArch : Archs) { + for (StringRef CandidateSysroot : SubdirNames) { llvm::SmallString<1024> LibDir(Base); - llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); + llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateSysroot); if (findGccVersion(LibDir, GccLibDir, Ver)) { - Arch = std::string(CandidateArch); + SubdirName = std::string(CandidateSysroot); return; } } } } -llvm::ErrorOr toolchains::MinGW::findGcc() { +static llvm::ErrorOr findGcc(const llvm::Triple &T) { llvm::SmallVector, 2> Gccs; - Gccs.emplace_back(getTriple().getArchName()); + Gccs.emplace_back(T.getArchName()); Gccs[0] += "-w64-mingw32-gcc"; Gccs.emplace_back("mingw32-gcc"); // Please do not add "gcc" here @@ -378,17 +381,18 @@ llvm::ErrorOr toolchains::MinGW::findGcc() { return make_error_code(std::errc::no_such_file_or_directory); } -llvm::ErrorOr toolchains::MinGW::findClangRelativeSysroot() { +static llvm::ErrorOr +findClangRelativeSysroot(const Driver &D, const llvm::Triple &T, + std::string &SubdirName) { llvm::SmallVector, 2> Subdirs; - Subdirs.emplace_back(getTriple().str()); - Subdirs.emplace_back(getTriple().getArchName()); + Subdirs.emplace_back(T.str()); + Subdirs.emplace_back(T.getArchName()); Subdirs[1] += "-w64-mingw32"; - StringRef ClangRoot = - llvm::sys::path::parent_path(getDriver().getInstalledDir()); + StringRef ClangRoot = llvm::sys::path::parent_path(D.getInstalledDir()); StringRef Sep = llvm::sys::path::get_separator(); for (StringRef CandidateSubdir : Subdirs) { if (llvm::sys::fs::is_directory(ClangRoot + Sep + CandidateSubdir)) { - Arch = std::string(CandidateSubdir); + SubdirName = std::string(CandidateSubdir); return (ClangRoot + Sep + CandidateSubdir).str(); } } @@ -401,13 +405,16 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, RocmInstallation(D, Triple, Args) { getProgramPaths().push_back(getDriver().getInstalledDir()); + // The sequence for detecting a sysroot here should be kept in sync with + // the testTriple function below. if (getDriver().SysRoot.size()) Base = getDriver().SysRoot; // Look for /../; if found, use /.. as the // base as it could still be a base for a gcc setup with libgcc. - else if (llvm::ErrorOr TargetSubdir = findClangRelativeSysroot()) + else if (llvm::ErrorOr TargetSubdir = + findClangRelativeSysroot(getDriver(), getTriple(), SubdirName)) Base = std::string(llvm::sys::path::parent_path(TargetSubdir.get())); - else if (llvm::ErrorOr GPPName = findGcc()) + else if (llvm::ErrorOr GPPName = findGcc(getTriple())) Base = std::string(llvm::sys::path::parent_path( llvm::sys::path::parent_path(GPPName.get()))); else @@ -420,10 +427,10 @@ toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, // correct crtbegin.o ,cetend.o would be found. getFilePaths().push_back(GccLibDir); getFilePaths().push_back( - (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); + (Base + SubdirName + llvm::sys::path::get_separator() + "lib").str()); getFilePaths().push_back(Base + "lib"); // openSUSE - getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); + getFilePaths().push_back(Base + SubdirName + "/sys-root/mingw/lib"); NativeLLVMSupport = Args.getLastArgValue(options::OPT_fuse_ld_EQ, CLANG_DEFAULT_LINKER) @@ -471,13 +478,17 @@ bool toolchains::MinGW::IsUnwindTablesDefault(const ArgList &Args) const { } bool toolchains::MinGW::isPICDefault() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } -bool toolchains::MinGW::isPIEDefault() const { return false; } +bool toolchains::MinGW::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool toolchains::MinGW::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; + return getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64; } llvm::ExceptionHandling @@ -568,11 +579,12 @@ void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { // openSUSE addSystemInclude(DriverArgs, CC1Args, - Base + Arch + "/sys-root/mingw/include"); + Base + SubdirName + "/sys-root/mingw/include"); } addSystemInclude(DriverArgs, CC1Args, - Base + Arch + llvm::sys::path::get_separator() + "include"); + Base + SubdirName + llvm::sys::path::get_separator() + + "include"); addSystemInclude(DriverArgs, CC1Args, Base + "include"); } @@ -585,19 +597,27 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( StringRef Slash = llvm::sys::path::get_separator(); switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, Base + Arch + Slash + "include" + - Slash + "c++" + Slash + "v1"); + case ToolChain::CST_Libcxx: { + std::string TargetDir = (Base + "include" + Slash + getTripleString() + + Slash + "c++" + Slash + "v1") + .str(); + if (getDriver().getVFS().exists(TargetDir)) + addSystemInclude(DriverArgs, CC1Args, TargetDir); + addSystemInclude(DriverArgs, CC1Args, + Base + SubdirName + Slash + "include" + Slash + "c++" + + Slash + "v1"); addSystemInclude(DriverArgs, CC1Args, Base + "include" + Slash + "c++" + Slash + "v1"); break; + } case ToolChain::CST_Libstdcxx: llvm::SmallVector, 4> CppIncludeBases; CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); + llvm::sys::path::append(CppIncludeBases[0], SubdirName, "include", "c++"); CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); + llvm::sys::path::append(CppIncludeBases[1], SubdirName, "include", "c++", + Ver); CppIncludeBases.emplace_back(Base); llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); CppIncludeBases.emplace_back(GccLibDir); @@ -605,9 +625,61 @@ void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( for (auto &CppIncludeBase : CppIncludeBases) { addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); CppIncludeBase += Slash; - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + SubdirName); addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); } break; } } + +static bool testTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // If an explicit sysroot is set, that will be used and we shouldn't try to + // detect anything else. + std::string SubdirName; + if (D.SysRoot.size()) + return true; + if (llvm::ErrorOr TargetSubdir = + findClangRelativeSysroot(D, Triple, SubdirName)) + return true; + if (llvm::ErrorOr GPPName = findGcc(Triple)) + return true; + // If we neither found a colocated sysroot or a matching gcc executable, + // conclude that we can't know if this is the correct spelling of the triple. + return false; +} + +static llvm::Triple adjustTriple(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) { + // First test if the original triple can find a sysroot with the triple + // name. + if (testTriple(D, Triple, Args)) + return Triple; + llvm::SmallVector Archs; + // If not, test a couple other possible arch names that might be what was + // intended. + if (Triple.getArch() == llvm::Triple::x86) { + Archs.emplace_back("i386"); + Archs.emplace_back("i586"); + Archs.emplace_back("i686"); + } else if (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) { + Archs.emplace_back("armv7"); + } + for (auto A : Archs) { + llvm::Triple TestTriple(Triple); + TestTriple.setArchName(A); + if (testTriple(D, TestTriple, Args)) + return TestTriple; + } + // If none was found, just proceed with the original value. + return Triple; +} + +void toolchains::MinGW::fixTripleArch(const Driver &D, llvm::Triple &Triple, + const ArgList &Args) { + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb) + Triple = adjustTriple(D, Triple, Args); +} diff --git a/clang/lib/Driver/ToolChains/MinGW.h b/clang/lib/Driver/ToolChains/MinGW.h index 2f1559fcf34..c3de19b9772 100644 --- a/clang/lib/Driver/ToolChains/MinGW.h +++ b/clang/lib/Driver/ToolChains/MinGW.h @@ -60,12 +60,15 @@ public: MinGW(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); + static void fixTripleArch(const Driver &D, llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool HasNativeLLVMSupport() const override; bool IsIntegratedAssemblerDefault() const override; bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; SanitizerMask getSupportedSanitizers() const override; @@ -99,12 +102,10 @@ private: std::string Base; std::string GccLibDir; std::string Ver; - std::string Arch; + std::string SubdirName; mutable std::unique_ptr Preprocessor; mutable std::unique_ptr Compiler; void findGccLibDir(); - llvm::ErrorOr findGcc(); - llvm::ErrorOr findClangRelativeSysroot(); bool NativeLLVMSupport; }; diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 1ce5a2a203c..7571398b7cc 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -29,12 +29,17 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::NetBSD &ToolChain = + static_cast(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + claimNoWarnArgs(Args); ArgStringList CmdArgs; // GNU as needs different flags for creating the correct output format // on architectures with different ABIs or optional feature sets. - switch (getToolChain().getArch()) { + switch (ToolChain.getArch()) { case llvm::Triple::x86: CmdArgs.push_back("--32"); break; @@ -44,8 +49,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::thumbeb: { StringRef MArch, MCPU; arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); - std::string Arch = - arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); + std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); break; } @@ -56,7 +60,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); CmdArgs.push_back("-march"); CmdArgs.push_back(CPUName.data()); @@ -64,29 +68,29 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -102,7 +106,7 @@ void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString((getToolChain().GetProgramPath("as"))); + const char *Exec = Args.MakeArgString((ToolChain.GetProgramPath("as"))); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -116,6 +120,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const toolchains::NetBSD &ToolChain = static_cast(getToolChain()); const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + ArgStringList CmdArgs; if (!D.SysRoot.empty()) @@ -150,7 +156,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::arm: case llvm::Triple::thumb: CmdArgs.push_back("-m"); - switch (ToolChain.getTriple().getEnvironment()) { + switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelf_nbsd_eabi"); @@ -168,7 +174,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::thumbeb: arm::appendBE8LinkFlag(Args, CmdArgs, ToolChain.getEffectiveTriple()); CmdArgs.push_back("-m"); - switch (ToolChain.getTriple().getEnvironment()) { + switch (Triple.getEnvironment()) { case llvm::Triple::EABI: case llvm::Triple::GNUEABI: CmdArgs.push_back("armelfb_nbsd_eabi"); @@ -254,19 +260,18 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(); + const SanitizerArgs &SanArgs = ToolChain.getSanitizerArgs(Args); if (SanArgs.needsSharedRt()) { CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString( - ToolChain.getCompilerRTPath().c_str())); + CmdArgs.push_back(Args.MakeArgString(ToolChain.getCompilerRTPath())); } unsigned Major, Minor, Micro; - ToolChain.getTriple().getOSVersion(Major, Minor, Micro); + Triple.getOSVersion(Major, Minor, Micro); bool useLibgcc = true; if (Major >= 7 || Major == 0) { switch (ToolChain.getArch()) { @@ -294,7 +299,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, getToolChain(), Args, StaticOpenMP); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) @@ -302,7 +307,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); if (NeedsXRayDeps) linkXRayRuntimeDeps(ToolChain, CmdArgs); if (Args.hasArg(options::OPT_pthread)) @@ -496,7 +501,7 @@ SanitizerMask NetBSD::getSupportedSanitizers() const { void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - const SanitizerArgs &SanArgs = getSanitizerArgs(); + const SanitizerArgs &SanArgs = getSanitizerArgs(DriverArgs); if (SanArgs.hasAnySanitizer()) CC1Args.push_back("-D_REENTRANT"); diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index e162165b256..96abac57764 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "OpenBSD.h" +#include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/Sparc.h" #include "CommonArgs.h" @@ -28,16 +29,30 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const toolchains::OpenBSD &ToolChain = + static_cast(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple &Triple = ToolChain.getTriple(); + claimNoWarnArgs(Args); ArgStringList CmdArgs; - switch (getToolChain().getArch()) { + switch (ToolChain.getArch()) { case llvm::Triple::x86: // When building 32-bit code on OpenBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. CmdArgs.push_back("--32"); break; + case llvm::Triple::arm: + case llvm::Triple::armeb: { + StringRef MArch, MCPU; + arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); + std::string Arch = arm::getARMTargetCPU(MCPU, MArch, Triple); + CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); + break; + } + case llvm::Triple::ppc: CmdArgs.push_back("-mppc"); CmdArgs.push_back("-many"); @@ -45,9 +60,9 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::sparcv9: { CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + std::string CPU = getCPUName(D, Args, Triple); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, Triple)); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -55,17 +70,20 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, case llvm::Triple::mips64el: { StringRef CPUName; StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - if (getToolChain().getTriple().isLittleEndian()) + if (Triple.isLittleEndian()) CmdArgs.push_back("-EL"); else CmdArgs.push_back("-EB"); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + AddAssemblerKPIC(ToolChain, Args, CmdArgs); break; } @@ -81,7 +99,7 @@ void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, for (const auto &II : Inputs) CmdArgs.push_back(II.getFilename()); - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("as")); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); @@ -94,7 +112,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const toolchains::OpenBSD &ToolChain = static_cast(getToolChain()); - const Driver &D = getToolChain().getDriver(); + const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -174,6 +192,11 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // Use the static OpenMP runtime with -static-openmp + bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && + !Args.hasArg(options::OPT_static); + addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); @@ -221,6 +244,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); } + ToolChain.addProfileRTLibs(Args, CmdArgs); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index 4932ed5c609..95c10cc6231 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -59,7 +59,9 @@ public: bool IsMathErrnoDefault() const override { return false; } bool IsObjCNonFragileABIDefault() const override { return true; } - bool isPIEDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return true; + } RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index 383b0c50d41..5783a733983 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -71,8 +71,9 @@ void tools::PS4cpu::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Exec, CmdArgs, Inputs, Output)); } -static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); +static void AddPS4SanitizerArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) { CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); } @@ -81,9 +82,9 @@ static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { } } -void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, +void tools::PS4cpu::addSanitizerArgs(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args); if (SanArgs.needsUbsanRt()) CmdArgs.push_back("--dependent-lib=libSceDbgUBSanitizer_stub_weak.a"); if (SanArgs.needsAsanRt()) @@ -127,7 +128,7 @@ void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, } if(!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - AddPS4SanitizerArgs(ToolChain, CmdArgs); + AddPS4SanitizerArgs(ToolChain, Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 5f5d0e57d4e..82f9523f84f 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -23,7 +23,8 @@ namespace PS4cpu { void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -void addSanitizerArgs(const ToolChain &TC, llvm::opt::ArgStringList &CmdArgs); +void addSanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { public: diff --git a/clang/lib/Driver/ToolChains/SPIRV.cpp b/clang/lib/Driver/ToolChains/SPIRV.cpp new file mode 100644 index 00000000000..16e72d3c733 --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRV.cpp @@ -0,0 +1,49 @@ +//===--- SPIRV.cpp - SPIR-V Tool Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "SPIRV.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/InputInfo.h" +#include "clang/Driver/Options.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace llvm::opt; + +void SPIRV::constructTranslateCommand(Compilation &C, const Tool &T, + const JobAction &JA, + const InputInfo &Output, + const InputInfo &Input, + const llvm::opt::ArgStringList &Args) { + llvm::opt::ArgStringList CmdArgs(Args); + CmdArgs.push_back(Input.getFilename()); + + if (Input.getType() == types::TY_PP_Asm) + CmdArgs.push_back("-to-binary"); + if (Output.getType() == types::TY_PP_Asm) + CmdArgs.push_back("-spirv-text"); + + CmdArgs.append({"-o", Output.getFilename()}); + + const char *Exec = + C.getArgs().MakeArgString(T.getToolChain().GetProgramPath("llvm-spirv")); + C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), + Exec, CmdArgs, Input, Output)); +} + +void SPIRV::Translator::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + constructTranslateCommand(C, *this, JA, Output, Inputs[0], {}); +} diff --git a/clang/lib/Driver/ToolChains/SPIRV.h b/clang/lib/Driver/ToolChains/SPIRV.h new file mode 100644 index 00000000000..35d0446bd8b --- /dev/null +++ b/clang/lib/Driver/ToolChains/SPIRV.h @@ -0,0 +1,46 @@ +//===--- SPIRV.h - SPIR-V Tool Implementations ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SPIRV_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace SPIRV { + +void addTranslatorArgs(const llvm::opt::ArgList &InArgs, + llvm::opt::ArgStringList &OutArgs); + +void constructTranslateCommand(Compilation &C, const Tool &T, + const JobAction &JA, const InputInfo &Output, + const InputInfo &Input, + const llvm::opt::ArgStringList &Args); + +class LLVM_LIBRARY_VISIBILITY Translator : public Tool { +public: + Translator(const ToolChain &TC) + : Tool("SPIR-V::Translator", "llvm-spirv", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool hasIntegratedAssembler() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // namespace SPIRV +} // namespace tools +} // namespace driver +} // namespace clang +#endif diff --git a/clang/lib/Driver/ToolChains/TCE.cpp b/clang/lib/Driver/ToolChains/TCE.cpp index 33a81c54bd4..5f4051d3116 100644 --- a/clang/lib/Driver/ToolChains/TCE.cpp +++ b/clang/lib/Driver/ToolChains/TCE.cpp @@ -34,7 +34,9 @@ bool TCEToolChain::IsMathErrnoDefault() const { return true; } bool TCEToolChain::isPICDefault() const { return false; } -bool TCEToolChain::isPIEDefault() const { return false; } +bool TCEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool TCEToolChain::isPICDefaultForced() const { return false; } diff --git a/clang/lib/Driver/ToolChains/TCE.h b/clang/lib/Driver/ToolChains/TCE.h index 72933dae965..31a64cfe878 100644 --- a/clang/lib/Driver/ToolChains/TCE.h +++ b/clang/lib/Driver/ToolChains/TCE.h @@ -27,7 +27,7 @@ public: bool IsMathErrnoDefault() const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; }; diff --git a/clang/lib/Driver/ToolChains/VEToolchain.cpp b/clang/lib/Driver/ToolChains/VEToolchain.cpp index e28f340f9aa..1fcc52684ba 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.cpp +++ b/clang/lib/Driver/ToolChains/VEToolchain.cpp @@ -53,7 +53,9 @@ Tool *VEToolChain::buildLinker() const { bool VEToolChain::isPICDefault() const { return false; } -bool VEToolChain::isPIEDefault() const { return false; } +bool VEToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool VEToolChain::isPICDefaultForced() const { return false; } diff --git a/clang/lib/Driver/ToolChains/VEToolchain.h b/clang/lib/Driver/ToolChains/VEToolchain.h index b330331ca84..964b0d0dd8d 100644 --- a/clang/lib/Driver/ToolChains/VEToolchain.h +++ b/clang/lib/Driver/ToolChains/VEToolchain.h @@ -28,7 +28,7 @@ protected: public: bool IsIntegratedAssemblerDefault() const override { return true; } bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool hasBlocksRuntime() const override; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 19f3571e6b3..a7298a9a71b 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -63,7 +63,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, ArgStringList CmdArgs; CmdArgs.push_back("-m"); - if (getToolChain().getTriple().isArch64Bit()) + if (ToolChain.getTriple().isArch64Bit()) CmdArgs.push_back("wasm64"); else CmdArgs.push_back("wasm32"); @@ -130,7 +130,7 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, // When optimizing, if wasm-opt is available, run it. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt"); + auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt"); if (WasmOptPath != "wasm-opt") { StringRef OOpt = "s"; if (A->getOption().matches(options::OPT_O4) || @@ -201,7 +201,9 @@ bool WebAssembly::UseObjCMixedDispatch() const { return true; } bool WebAssembly::isPICDefault() const { return false; } -bool WebAssembly::isPIEDefault() const { return false; } +bool WebAssembly::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool WebAssembly::isPICDefaultForced() const { return false; } @@ -293,6 +295,9 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, // '-fwasm-exceptions' implies exception-handling feature CC1Args.push_back("-target-feature"); CC1Args.push_back("+exception-handling"); + // Backend needs -wasm-enable-eh to enable Wasm EH + CC1Args.push_back("-mllvm"); + CC1Args.push_back("-wasm-enable-eh"); } for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { @@ -300,14 +305,14 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, if (Opt.startswith("-emscripten-cxx-exceptions-allowed")) { // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with // '-mllvm -enable-emscripten-cxx-exceptions' - bool EmExceptionArgExists = false; + bool EmEHArgExists = false; for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") { - EmExceptionArgExists = true; + EmEHArgExists = true; break; } } - if (!EmExceptionArgExists) + if (!EmEHArgExists) getDriver().Diag(diag::err_drv_argument_only_allowed_with) << "-mllvm -emscripten-cxx-exceptions-allowed" << "-mllvm -enable-emscripten-cxx-exceptions"; @@ -323,6 +328,38 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, ":noinline")); } } + + if (Opt.startswith("-wasm-enable-sjlj")) { + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mno-exception-handling' + if (DriverArgs.hasFlag(options::OPT_mno_exception_handing, + options::OPT_mexception_handing, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mno-exception-handling"; + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mllvm -enable-emscripten-cxx-exceptions' + // because we don't allow Emscripten EH + Wasm SjLj + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { + if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mllvm -enable-emscripten-cxx-exceptions"; + } + // '-mllvm -wasm-enable-sjlj' is not compatible with + // '-mllvm -enable-emscripten-sjlj' + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { + if (StringRef(A->getValue(0)) == "-enable-emscripten-sjlj") + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-mllvm -wasm-enable-sjlj" + << "-mllvm -enable-emscripten-sjlj"; + } + // '-mllvm -wasm-enable-sjlj' implies exception-handling feature + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+exception-handling"); + // Backend needs '-exception-model=wasm' to use Wasm EH instructions + CC1Args.push_back("-exception-model=wasm"); + } } } diff --git a/clang/lib/Driver/ToolChains/WebAssembly.h b/clang/lib/Driver/ToolChains/WebAssembly.h index 8a3f82d9efd..c84e5967594 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.h +++ b/clang/lib/Driver/ToolChains/WebAssembly.h @@ -45,7 +45,7 @@ private: bool IsObjCNonFragileABIDefault() const override; bool UseObjCMixedDispatch() const override; bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; diff --git a/clang/lib/Driver/ToolChains/XCore.cpp b/clang/lib/Driver/ToolChains/XCore.cpp index 5f94f83d369..7e74f637405 100644 --- a/clang/lib/Driver/ToolChains/XCore.cpp +++ b/clang/lib/Driver/ToolChains/XCore.cpp @@ -102,7 +102,9 @@ Tool *XCoreToolChain::buildLinker() const { bool XCoreToolChain::isPICDefault() const { return false; } -bool XCoreToolChain::isPIEDefault() const { return false; } +bool XCoreToolChain::isPIEDefault(const llvm::opt::ArgList &Args) const { + return false; +} bool XCoreToolChain::isPICDefaultForced() const { return false; } diff --git a/clang/lib/Driver/ToolChains/XCore.h b/clang/lib/Driver/ToolChains/XCore.h index 41dce08454c..d9a05da3c67 100644 --- a/clang/lib/Driver/ToolChains/XCore.h +++ b/clang/lib/Driver/ToolChains/XCore.h @@ -58,7 +58,7 @@ protected: public: bool isPICDefault() const override; - bool isPIEDefault() const override; + bool isPIEDefault(const llvm::opt::ArgList &Args) const override; bool isPICDefaultForced() const override; bool SupportsProfiling() const override; bool hasBlocksRuntime() const override; diff --git a/clang/lib/Driver/ToolChains/ZOS.h b/clang/lib/Driver/ToolChains/ZOS.h index cace85d6da7..50bff099356 100644 --- a/clang/lib/Driver/ToolChains/ZOS.h +++ b/clang/lib/Driver/ToolChains/ZOS.h @@ -23,7 +23,9 @@ public: ~ZOS() override; bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } + bool isPIEDefault(const llvm::opt::ArgList &Args) const override { + return false; + } bool isPICDefaultForced() const override { return false; } bool IsIntegratedAssemblerDefault() const override { return true; } diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 3cb2d6e8f6f..1bd187ad2fc 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -362,46 +362,7 @@ types::getCompilationPhases(ID Id, phases::ID LastPhase) { llvm::SmallVector types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::opt::DerivedArgList &DAL, ID Id) { - phases::ID LastPhase; - - // Filter to compiler mode. When the compiler is run as a preprocessor then - // compilation is not an option. - // -S runs the compiler in Assembly listing mode. - if (Driver.CCCIsCPP() || DAL.getLastArg(options::OPT_E) || - DAL.getLastArg(options::OPT__SLASH_EP) || - DAL.getLastArg(options::OPT_M, options::OPT_MM) || - DAL.getLastArg(options::OPT__SLASH_P)) - LastPhase = phases::Preprocess; - - // --precompile only runs up to precompilation. - // This is a clang extension and is not compatible with GCC. - else if (DAL.getLastArg(options::OPT__precompile)) - LastPhase = phases::Precompile; - - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. - else if (DAL.getLastArg(options::OPT_fsyntax_only) || - DAL.getLastArg(options::OPT_print_supported_cpus) || - DAL.getLastArg(options::OPT_module_file_info) || - DAL.getLastArg(options::OPT_verify_pch) || - DAL.getLastArg(options::OPT_rewrite_objc) || - DAL.getLastArg(options::OPT_rewrite_legacy_objc) || - DAL.getLastArg(options::OPT__migrate) || - DAL.getLastArg(options::OPT__analyze) || - DAL.getLastArg(options::OPT_emit_ast)) - LastPhase = phases::Compile; - - else if (DAL.getLastArg(options::OPT_S) || - DAL.getLastArg(options::OPT_emit_llvm)) - LastPhase = phases::Backend; - - else if (DAL.getLastArg(options::OPT_c)) - LastPhase = phases::Assemble; - - // Generally means, do every phase until Link. - else - LastPhase = phases::LastPhase; - - return types::getCompilationPhases(Id, LastPhase); + return types::getCompilationPhases(Id, Driver.getFinalPhase(DAL)); } ID types::lookupCXXTypeForCType(ID Id) { diff --git a/clang/lib/Edit/EditedSource.cpp b/clang/lib/Edit/EditedSource.cpp index 74e6005faeb..ee57660b8c7 100644 --- a/clang/lib/Edit/EditedSource.cpp +++ b/clang/lib/Edit/EditedSource.cpp @@ -60,7 +60,7 @@ void EditedSource::finishedCommit() { MacroArgUse ArgUse; std::tie(ExpLoc, ArgUse) = ExpArg; auto &ArgUses = ExpansionToArgMap[ExpLoc]; - if (llvm::find(ArgUses, ArgUse) == ArgUses.end()) + if (!llvm::is_contained(ArgUses, ArgUse)) ArgUses.push_back(ArgUse); } CurrCommitMacroArgExps.clear(); @@ -314,8 +314,8 @@ bool EditedSource::commit(const Commit &commit) { static bool canBeJoined(char left, char right, const LangOptions &LangOpts) { // FIXME: Should use TokenConcatenation to make sure we don't allow stuff like // making two '<' adjacent. - return !(Lexer::isIdentifierBodyChar(left, LangOpts) && - Lexer::isIdentifierBodyChar(right, LangOpts)); + return !(Lexer::isAsciiIdentifierContinueChar(left, LangOpts) && + Lexer::isAsciiIdentifierContinueChar(right, LangOpts)); } /// Returns true if it is ok to eliminate the trailing whitespace between diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 45590489584..968b35bfda2 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -779,8 +779,7 @@ BreakableLineCommentSection::BreakableLineCommentSection( Lines[i] = Lines[i].ltrim(Blanks); StringRef IndentPrefix = getLineCommentIndentPrefix(Lines[i], Style); OriginalPrefix[i] = IndentPrefix; - const unsigned SpacesInPrefix = - std::count(IndentPrefix.begin(), IndentPrefix.end(), ' '); + const unsigned SpacesInPrefix = llvm::count(IndentPrefix, ' '); // On the first line of the comment section we calculate how many spaces // are to be added or removed, all lines after that just get only the diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 8fbc15f2792..1e4f5690ef2 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -14,10 +14,12 @@ #include "ContinuationIndenter.h" #include "BreakableToken.h" #include "FormatInternal.h" +#include "FormatToken.h" #include "WhitespaceManager.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "format-indenter" @@ -491,11 +493,24 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; } + // Break after the closing parenthesis of TypeScript decorators before + // functions, getters and setters. + static const llvm::StringSet<> BreakBeforeDecoratedTokens = {"get", "set", + "function"}; + if (Style.Language == FormatStyle::LK_JavaScript && + BreakBeforeDecoratedTokens.contains(Current.TokenText) && + Previous.is(tok::r_paren) && Previous.is(TT_JavaAnnotation)) { + return true; + } + // If the return type spans multiple lines, wrap before the function name. if (((Current.is(TT_FunctionDeclarationName) && // Don't break before a C# function when no break after return type (!Style.isCSharp() || - Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None)) || + Style.AlwaysBreakAfterReturnType != FormatStyle::RTBS_None) && + // Don't always break between a JavaScript `function` and the function + // name. + Style.Language != FormatStyle::LK_JavaScript) || (Current.is(tok::kw_operator) && !Previous.is(tok::coloncolon))) && !Previous.is(tok::kw_template) && State.Stack.back().BreakBeforeParameter) return true; @@ -943,7 +958,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, State.Line->MustBeDeclaration) || (!Style.AllowAllArgumentsOnNextLine && !State.Line->MustBeDeclaration) || - (!Style.AllowAllConstructorInitializersOnNextLine && + (Style.PackConstructorInitializers != FormatStyle::PCIS_NextLine && PreviousIsBreakingCtorInitializerColon) || Previous.is(TT_DictLiteral)) State.Stack.back().BreakBeforeParameter = true; @@ -952,7 +967,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // and we allow all arguments on the next line, we should not break // before the next parameter. if (PreviousIsBreakingCtorInitializerColon && - Style.AllowAllConstructorInitializersOnNextLine) + Style.PackConstructorInitializers == FormatStyle::PCIS_NextLine) State.Stack.back().BreakBeforeParameter = false; } @@ -1232,10 +1247,10 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, ? 0 : 2); State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; - if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) { + if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack) { State.Stack.back().AvoidBinPacking = true; State.Stack.back().BreakBeforeParameter = - !Style.AllowAllConstructorInitializersOnNextLine; + Style.PackConstructorInitializers != FormatStyle::PCIS_NextLine; } else { State.Stack.back().BreakBeforeParameter = false; } @@ -1245,7 +1260,7 @@ unsigned ContinuationIndenter::moveStateToNextToken(LineState &State, State.Stack.back().Indent = State.FirstIndent + Style.ConstructorInitializerIndentWidth; State.Stack.back().NestedBlockIndent = State.Stack.back().Indent; - if (Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + if (Style.PackConstructorInitializers > FormatStyle::PCIS_BinPack) State.Stack.back().AvoidBinPacking = true; } if (Current.is(TT_InheritanceColon)) @@ -1592,7 +1607,7 @@ void ContinuationIndenter::moveStatePastScopeCloser(LineState &State) { // BreakBeforeParameter is calculated based on an incorrect assumption // (it is checked whether the whole expression fits into one line without // considering a line break inside a message receiver). - // We check whether arguements fit after receiver scope closer (into the same + // We check whether arguments fit after receiver scope closer (into the same // line). if (State.Stack.back().BreakBeforeParameter && Current.MatchingParen && Current.MatchingParen->Previous) { diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2b860d2a25f..085cca8853e 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -19,6 +19,7 @@ #include "FormatInternal.h" #include "FormatTokenLexer.h" #include "NamespaceEndCommentsFixer.h" +#include "QualifierAlignmentFixer.h" #include "SortJavaScriptImports.h" #include "TokenAnalyzer.h" #include "TokenAnnotator.h" @@ -126,6 +127,16 @@ template <> struct ScalarEnumerationTraits { } }; +template <> +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::QualifierAlignmentStyle &Value) { + IO.enumCase(Value, "Leave", FormatStyle::QAS_Leave); + IO.enumCase(Value, "Left", FormatStyle::QAS_Left); + IO.enumCase(Value, "Right", FormatStyle::QAS_Right); + IO.enumCase(Value, "Custom", FormatStyle::QAS_Custom); + } +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, FormatStyle::ShortFunctionStyle &Value) { IO.enumCase(Value, "None", FormatStyle::SFS_None); @@ -147,7 +158,7 @@ template <> struct ScalarEnumerationTraits { IO.enumCase(Value, "AcrossEmptyLinesAndComments", FormatStyle::ACS_AcrossEmptyLinesAndComments); - // For backward compability. + // For backward compatibility. IO.enumCase(Value, "true", FormatStyle::ACS_Consecutive); IO.enumCase(Value, "false", FormatStyle::ACS_None); } @@ -264,6 +275,17 @@ struct ScalarEnumerationTraits { } }; +template <> +struct ScalarEnumerationTraits { + static void + enumeration(IO &IO, FormatStyle::PackConstructorInitializersStyle &Value) { + IO.enumCase(Value, "Never", FormatStyle::PCIS_Never); + IO.enumCase(Value, "BinPack", FormatStyle::PCIS_BinPack); + IO.enumCase(Value, "CurrentLine", FormatStyle::PCIS_CurrentLine); + IO.enumCase(Value, "NextLine", FormatStyle::PCIS_NextLine); + } +}; + template <> struct ScalarEnumerationTraits { static void @@ -429,9 +451,8 @@ struct ScalarEnumerationTraits { }; template <> -struct ScalarEnumerationTraits { - static void enumeration(IO &IO, - FormatStyle::SpaceBeforeParensOptions &Value) { +struct ScalarEnumerationTraits { + static void enumeration(IO &IO, FormatStyle::SpaceBeforeParensStyle &Value) { IO.enumCase(Value, "Never", FormatStyle::SBPO_Never); IO.enumCase(Value, "ControlStatements", FormatStyle::SBPO_ControlStatements); @@ -440,6 +461,7 @@ struct ScalarEnumerationTraits { IO.enumCase(Value, "NonEmptyParentheses", FormatStyle::SBPO_NonEmptyParentheses); IO.enumCase(Value, "Always", FormatStyle::SBPO_Always); + IO.enumCase(Value, "Custom", FormatStyle::SBPO_Custom); // For backward compatibility. IO.enumCase(Value, "false", FormatStyle::SBPO_Never); @@ -552,8 +574,6 @@ template <> struct MappingTraits { IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments); IO.mapOptional("AllowAllArgumentsOnNextLine", Style.AllowAllArgumentsOnNextLine); - IO.mapOptional("AllowAllConstructorInitializersOnNextLine", - Style.AllowAllConstructorInitializersOnNextLine); IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine", Style.AllowAllParametersOfDeclarationOnNextLine); IO.mapOptional("AllowShortEnumsOnASingleLine", @@ -632,9 +652,18 @@ template <> struct MappingTraits { IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("ColumnLimit", Style.ColumnLimit); IO.mapOptional("CommentPragmas", Style.CommentPragmas); + IO.mapOptional("QualifierAlignment", Style.QualifierAlignment); + + // Default Order for Left/Right based Qualifier alignment. + if (Style.QualifierAlignment == FormatStyle::QAS_Right) { + Style.QualifierOrder = {"type", "const", "volatile"}; + } else if (Style.QualifierAlignment == FormatStyle::QAS_Left) { + Style.QualifierOrder = {"const", "volatile", "type"}; + } else if (Style.QualifierAlignment == FormatStyle::QAS_Custom) { + IO.mapOptional("QualifierOrder", Style.QualifierOrder); + } + IO.mapOptional("CompactNamespaces", Style.CompactNamespaces); - IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", - Style.ConstructorInitializerAllOnOneLineOrOnePerLine); IO.mapOptional("ConstructorInitializerIndentWidth", Style.ConstructorInitializerIndentWidth); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); @@ -648,6 +677,41 @@ template <> struct MappingTraits { Style.EmptyLineBeforeAccessModifier); IO.mapOptional("ExperimentalAutoDetectBinPacking", Style.ExperimentalAutoDetectBinPacking); + + IO.mapOptional("PackConstructorInitializers", + Style.PackConstructorInitializers); + // For backward compatibility: + // The default value of ConstructorInitializerAllOnOneLineOrOnePerLine was + // false unless BasedOnStyle was Google or Chromium whereas that of + // AllowAllConstructorInitializersOnNextLine was always true, so the + // equivalent default value of PackConstructorInitializers is PCIS_NextLine + // for Google/Chromium or PCIS_BinPack otherwise. If the deprecated options + // had a non-default value while PackConstructorInitializers has a default + // value, set the latter to an equivalent non-default value if needed. + StringRef BasedOn; + IO.mapOptional("BasedOnStyle", BasedOn); + const bool IsGoogleOrChromium = BasedOn.equals_insensitive("google") || + BasedOn.equals_insensitive("chromium"); + bool OnCurrentLine = IsGoogleOrChromium; + bool OnNextLine = true; + IO.mapOptional("ConstructorInitializerAllOnOneLineOrOnePerLine", + OnCurrentLine); + IO.mapOptional("AllowAllConstructorInitializersOnNextLine", OnNextLine); + if (!IsGoogleOrChromium) { + if (Style.PackConstructorInitializers == FormatStyle::PCIS_BinPack && + OnCurrentLine) { + Style.PackConstructorInitializers = OnNextLine + ? FormatStyle::PCIS_NextLine + : FormatStyle::PCIS_CurrentLine; + } + } else if (Style.PackConstructorInitializers == + FormatStyle::PCIS_NextLine) { + if (!OnCurrentLine) + Style.PackConstructorInitializers = FormatStyle::PCIS_BinPack; + else if (!OnNextLine) + Style.PackConstructorInitializers = FormatStyle::PCIS_CurrentLine; + } + IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); IO.mapOptional("IfMacros", Style.IfMacros); @@ -723,6 +787,7 @@ template <> struct MappingTraits { IO.mapOptional("SpaceBeforeInheritanceColon", Style.SpaceBeforeInheritanceColon); IO.mapOptional("SpaceBeforeParens", Style.SpaceBeforeParens); + IO.mapOptional("SpaceBeforeParensOptions", Style.SpaceBeforeParensOptions); IO.mapOptional("SpaceAroundPointerQualifiers", Style.SpaceAroundPointerQualifiers); IO.mapOptional("SpaceBeforeRangeBasedForLoopColon", @@ -781,6 +846,20 @@ template <> struct MappingTraits { } }; +template <> struct MappingTraits { + static void mapping(IO &IO, FormatStyle::SpaceBeforeParensCustom &Spacing) { + IO.mapOptional("AfterControlStatements", Spacing.AfterControlStatements); + IO.mapOptional("AfterForeachMacros", Spacing.AfterForeachMacros); + IO.mapOptional("AfterFunctionDefinitionName", + Spacing.AfterFunctionDefinitionName); + IO.mapOptional("AfterFunctionDeclarationName", + Spacing.AfterFunctionDeclarationName); + IO.mapOptional("AfterIfMacros", Spacing.AfterIfMacros); + IO.mapOptional("BeforeNonEmptyParentheses", + Spacing.BeforeNonEmptyParentheses); + } +}; + template <> struct MappingTraits { static void mapping(IO &IO, FormatStyle::RawStringFormat &Format) { IO.mapOptional("Language", Format.Language); @@ -863,14 +942,21 @@ std::string ParseErrorCategory::message(int EV) const { return "Unsuitable"; case ParseError::BinPackTrailingCommaConflict: return "trailing comma insertion cannot be used with bin packing"; + case ParseError::InvalidQualifierSpecified: + return "Invalid qualifier specified in QualifierOrder"; + case ParseError::DuplicateQualifierSpecified: + return "Duplicate qualifier specified in QualfierOrder"; + case ParseError::MissingQualifierType: + return "Missing type in QualfierOrder"; + case ParseError::MissingQualifierOrder: + return "Missing QualfierOrder"; } llvm_unreachable("unexpected parse error"); } -static FormatStyle expandPresets(const FormatStyle &Style) { - if (Style.BreakBeforeBraces == FormatStyle::BS_Custom) - return Style; - FormatStyle Expanded = Style; +static void expandPresetsBraceWrapping(FormatStyle &Expanded) { + if (Expanded.BreakBeforeBraces == FormatStyle::BS_Custom) + return; Expanded.BraceWrapping = {/*AfterCaseLabel=*/false, /*AfterClass=*/false, /*AfterControlStatement=*/FormatStyle::BWACS_Never, @@ -889,7 +975,7 @@ static FormatStyle expandPresets(const FormatStyle &Style) { /*SplitEmptyFunction=*/true, /*SplitEmptyRecord=*/true, /*SplitEmptyNamespace=*/true}; - switch (Style.BreakBeforeBraces) { + switch (Expanded.BreakBeforeBraces) { case FormatStyle::BS_Linux: Expanded.BraceWrapping.AfterClass = true; Expanded.BraceWrapping.AfterFunction = true; @@ -970,7 +1056,33 @@ static FormatStyle expandPresets(const FormatStyle &Style) { default: break; } - return Expanded; +} + +static void expandPresetsSpaceBeforeParens(FormatStyle &Expanded) { + if (Expanded.SpaceBeforeParens == FormatStyle::SBPO_Custom) + return; + // Reset all flags + Expanded.SpaceBeforeParensOptions = {}; + + switch (Expanded.SpaceBeforeParens) { + case FormatStyle::SBPO_Never: + break; + case FormatStyle::SBPO_ControlStatements: + Expanded.SpaceBeforeParensOptions.AfterControlStatements = true; + Expanded.SpaceBeforeParensOptions.AfterForeachMacros = true; + Expanded.SpaceBeforeParensOptions.AfterIfMacros = true; + break; + case FormatStyle::SBPO_ControlStatementsExceptControlMacros: + Expanded.SpaceBeforeParensOptions.AfterControlStatements = true; + break; + case FormatStyle::SBPO_NonEmptyParentheses: + Expanded.SpaceBeforeParensOptions.BeforeNonEmptyParentheses = true; + break; + case FormatStyle::SBPO_Always: + break; + default: + break; + } } FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { @@ -988,7 +1100,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignConsecutiveDeclarations = FormatStyle::ACS_None; LLVMStyle.AlignConsecutiveMacros = FormatStyle::ACS_None; LLVMStyle.AllowAllArgumentsOnNextLine = true; - LLVMStyle.AllowAllConstructorInitializersOnNextLine = true; LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true; LLVMStyle.AllowShortEnumsOnASingleLine = true; LLVMStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; @@ -1034,15 +1145,19 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ColumnLimit = 80; LLVMStyle.CommentPragmas = "^ IWYU pragma:"; LLVMStyle.CompactNamespaces = false; - LLVMStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = false; LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.Cpp11BracedListStyle = true; + + // Off by default Qualifier ordering + LLVMStyle.QualifierAlignment = FormatStyle::QAS_Leave; + LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never; LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock; LLVMStyle.ExperimentalAutoDetectBinPacking = false; + LLVMStyle.PackConstructorInitializers = FormatStyle::PCIS_BinPack; LLVMStyle.FixNamespaceComments = true; LLVMStyle.ForEachMacros.push_back("foreach"); LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); @@ -1099,6 +1214,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeCtorInitializerColon = true; LLVMStyle.SpaceBeforeInheritanceColon = true; LLVMStyle.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements; + LLVMStyle.SpaceBeforeParensOptions.AfterControlStatements = true; + LLVMStyle.SpaceBeforeParensOptions.AfterForeachMacros = true; + LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true; LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; @@ -1158,7 +1276,6 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.AllowShortLoopsOnASingleLine = true; GoogleStyle.AlwaysBreakBeforeMultilineStrings = true; GoogleStyle.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; - GoogleStyle.ConstructorInitializerAllOnOneLineOrOnePerLine = true; GoogleStyle.DerivePointerAlignment = true; GoogleStyle.IncludeStyle.IncludeCategories = {{"^", 2, 0, false}, {"^<.*\\.h>", 1, 0, false}, @@ -1171,6 +1288,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { GoogleStyle.ObjCBinPackProtocolList = FormatStyle::BPS_Never; GoogleStyle.ObjCSpaceAfterProperty = false; GoogleStyle.ObjCSpaceBeforeProtocolList = true; + GoogleStyle.PackConstructorInitializers = FormatStyle::PCIS_NextLine; GoogleStyle.PointerAlignment = FormatStyle::PAS_Left; GoogleStyle.RawStringFormats = { { @@ -1311,7 +1429,7 @@ FormatStyle getChromiumStyle(FormatStyle::LanguageKind Language) { ChromiumStyle.ContinuationIndentWidth = 8; ChromiumStyle.IndentWidth = 4; // See styleguide for import groups: - // https://chromium.googlesource.com/chromium/src/+/master/styleguide/java/java.md#Import-Order + // https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/java/java.md#Import-Order ChromiumStyle.JavaImportGroups = { "android", "androidx", @@ -1471,6 +1589,37 @@ bool getPredefinedStyle(StringRef Name, FormatStyle::LanguageKind Language, return true; } +ParseError validateQualifierOrder(FormatStyle *Style) { + // If its empty then it means don't do anything. + if (Style->QualifierOrder.empty()) + return ParseError::MissingQualifierOrder; + + // Ensure the list contains only currently valid qualifiers. + for (const auto &Qualifier : Style->QualifierOrder) { + if (Qualifier == "type") + continue; + auto token = + LeftRightQualifierAlignmentFixer::getTokenFromQualifier(Qualifier); + if (token == tok::identifier) + return ParseError::InvalidQualifierSpecified; + } + // Ensure the list is unqiue (no duplicates). + std::set UniqueQualifiers(Style->QualifierOrder.begin(), + Style->QualifierOrder.end()); + if (Style->QualifierOrder.size() != UniqueQualifiers.size()) { + LLVM_DEBUG(llvm::dbgs() + << "Duplicate Qualifiers " << Style->QualifierOrder.size() + << " vs " << UniqueQualifiers.size() << "\n"); + return ParseError::DuplicateQualifierSpecified; + } + + auto type = std::find(Style->QualifierOrder.begin(), + Style->QualifierOrder.end(), "type"); + if (type == Style->QualifierOrder.end()) + return ParseError::MissingQualifierType; + return ParseError::Success; +} + std::error_code parseConfiguration(llvm::MemoryBufferRef Config, FormatStyle *Style, bool AllowUnknownOptions, llvm::SourceMgr::DiagHandlerTy DiagHandler, @@ -1532,6 +1681,8 @@ std::error_code parseConfiguration(llvm::MemoryBufferRef Config, // See comment on FormatStyle::TSC_Wrapped. return make_error_code(ParseError::BinPackTrailingCommaConflict); } + if (Style->QualifierAlignment != FormatStyle::QAS_Leave) + return make_error_code(validateQualifierOrder(Style)); return make_error_code(ParseError::Success); } @@ -1541,8 +1692,11 @@ std::string configurationAsText(const FormatStyle &Style) { llvm::yaml::Output Output(Stream); // We use the same mapping method for input and output, so we need a non-const // reference here. - FormatStyle NonConstStyle = expandPresets(Style); + FormatStyle NonConstStyle = Style; + expandPresetsBraceWrapping(NonConstStyle); + expandPresetsSpaceBeforeParens(NonConstStyle); Output << NonConstStyle; + return Stream.str(); } @@ -2821,7 +2975,9 @@ reformat(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, unsigned FirstStartColumn, unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName, FormattingAttemptStatus *Status) { - FormatStyle Expanded = expandPresets(Style); + FormatStyle Expanded = Style; + expandPresetsBraceWrapping(Expanded); + expandPresetsSpaceBeforeParens(Expanded); if (Expanded.DisableFormat) return {tooling::Replacements(), 0}; if (isLikelyXml(Code)) @@ -2833,8 +2989,10 @@ reformat(const FormatStyle &Style, StringRef Code, if (Style.isJson()) { std::vector Ranges(1, tooling::Range(0, Code.size())); auto Env = - std::make_unique(Code, FileName, Ranges, FirstStartColumn, + Environment::make(Code, FileName, Ranges, FirstStartColumn, NextStartColumn, LastStartColumn); + if (!Env) + return {}; // Perform the actual formatting pass. tooling::Replacements Replaces = Formatter(*Env, Style, Status).process().first; @@ -2853,6 +3011,15 @@ reformat(const FormatStyle &Style, StringRef Code, AnalyzerPass; SmallVector Passes; + if (Style.isCpp() && Style.QualifierAlignment != FormatStyle::QAS_Leave) { + Passes.emplace_back([&](const Environment &Env) { + return QualifierAlignmentFixer(Env, Expanded, Code, Ranges, + FirstStartColumn, NextStartColumn, + LastStartColumn, FileName) + .process(); + }); + } + if (Style.Language == FormatStyle::LK_Cpp) { if (Style.FixNamespaceComments) Passes.emplace_back([&](const Environment &Env) { @@ -2881,9 +3048,10 @@ reformat(const FormatStyle &Style, StringRef Code, return TrailingCommaInserter(Env, Expanded).process(); }); - auto Env = - std::make_unique(Code, FileName, Ranges, FirstStartColumn, - NextStartColumn, LastStartColumn); + auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, + NextStartColumn, LastStartColumn); + if (!Env) + return {}; llvm::Optional CurrentCode = None; tooling::Replacements Fixes; unsigned Penalty = 0; @@ -2896,10 +3064,12 @@ reformat(const FormatStyle &Style, StringRef Code, Penalty += PassFixes.second; if (I + 1 < E) { CurrentCode = std::move(*NewCode); - Env = std::make_unique( + Env = Environment::make( *CurrentCode, FileName, tooling::calculateRangesAfterReplacements(Fixes, Ranges), FirstStartColumn, NextStartColumn, LastStartColumn); + if (!Env) + return {}; } } } @@ -2925,7 +3095,10 @@ tooling::Replacements cleanup(const FormatStyle &Style, StringRef Code, // cleanups only apply to C++ (they mostly concern ctor commas etc.) if (Style.Language != FormatStyle::LK_Cpp) return tooling::Replacements(); - return Cleaner(Environment(Code, FileName, Ranges), Style).process().first; + auto Env = Environment::make(Code, FileName, Ranges); + if (!Env) + return {}; + return Cleaner(*Env, Style).process().first; } tooling::Replacements reformat(const FormatStyle &Style, StringRef Code, @@ -2942,7 +3115,10 @@ tooling::Replacements fixNamespaceEndComments(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName) { - return NamespaceEndCommentsFixer(Environment(Code, FileName, Ranges), Style) + auto Env = Environment::make(Code, FileName, Ranges); + if (!Env) + return {}; + return NamespaceEndCommentsFixer(*Env, Style) .process() .first; } @@ -2951,7 +3127,10 @@ tooling::Replacements sortUsingDeclarations(const FormatStyle &Style, StringRef Code, ArrayRef Ranges, StringRef FileName) { - return UsingDeclarationsSorter(Environment(Code, FileName, Ranges), Style) + auto Env = Environment::make(Code, FileName, Ranges); + if (!Env) + return {}; + return UsingDeclarationsSorter(*Env, Style) .process() .first; } diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp index 8e4994f4c0d..6768f041135 100644 --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -53,6 +53,7 @@ bool FormatToken::isSimpleTypeSpecifier() const { case tok::kw___bf16: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 0506cd554bc..06d51dd95f5 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -934,8 +934,8 @@ struct AdditionalKeywords { // already initialized. JsExtraKeywords = std::unordered_set( {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, - kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, - kw_set, kw_type, kw_typeof, kw_var, kw_yield, + kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_override, + kw_readonly, kw_set, kw_type, kw_typeof, kw_var, kw_yield, // Keywords from the Java section. kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); @@ -1060,7 +1060,7 @@ struct AdditionalKeywords { bool IsJavaScriptIdentifier(const FormatToken &Tok, bool AcceptIdentifierName = true) const { // Based on the list of JavaScript & TypeScript keywords here: - // https://github.com/microsoft/TypeScript/blob/master/src/compiler/scanner.ts#L74 + // https://github.com/microsoft/TypeScript/blob/main/src/compiler/scanner.ts#L74 switch (Tok.Tok.getKind()) { case tok::kw_break: case tok::kw_case: diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index a9cfb4a247f..8075756cca0 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -506,11 +506,11 @@ void FormatTokenLexer::tryParseJSRegexLiteral() { return; FormatToken *Prev = nullptr; - for (auto I = Tokens.rbegin() + 1, E = Tokens.rend(); I != E; ++I) { + for (FormatToken *FT : llvm::drop_begin(llvm::reverse(Tokens))) { // NB: Because previous pointers are not initialized yet, this cannot use // Token.getPreviousNonComment. - if ((*I)->isNot(tok::comment)) { - Prev = *I; + if (FT->isNot(tok::comment)) { + Prev = FT; break; } } diff --git a/clang/lib/Format/MacroExpander.cpp b/clang/lib/Format/MacroExpander.cpp index e50c8044696..de96cb24ba1 100644 --- a/clang/lib/Format/MacroExpander.cpp +++ b/clang/lib/Format/MacroExpander.cpp @@ -1,9 +1,8 @@ //===--- MacroExpander.cpp - Format C++ code --------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// @@ -53,7 +52,7 @@ public: Current = Tokens[0]; } - // Parse the token stream and return the corresonding Definition object. + // Parse the token stream and return the corresponding Definition object. // Returns an empty definition object with a null-Name on error. MacroExpander::Definition parse() { if (!Current->is(tok::identifier)) diff --git a/clang/lib/Format/Macros.h b/clang/lib/Format/Macros.h index 591ef8b5be3..da03beb0914 100644 --- a/clang/lib/Format/Macros.h +++ b/clang/lib/Format/Macros.h @@ -1,9 +1,8 @@ //===--- MacroExpander.h - Format C++ code ----------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// /// diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp new file mode 100644 index 00000000000..5a89225c7fc --- /dev/null +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -0,0 +1,468 @@ +//===--- LeftRightQualifierAlignmentFixer.cpp -------------------*- C++--*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements LeftRightQualifierAlignmentFixer, a TokenAnalyzer that +/// enforces either left or right const depending on the style. +/// +//===----------------------------------------------------------------------===// + +#include "QualifierAlignmentFixer.h" +#include "FormatToken.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Regex.h" + +#include + +#define DEBUG_TYPE "format-qualifier-alignment-fixer" + +namespace clang { +namespace format { + +QualifierAlignmentFixer::QualifierAlignmentFixer( + const Environment &Env, const FormatStyle &Style, StringRef &Code, + ArrayRef Ranges, unsigned FirstStartColumn, + unsigned NextStartColumn, unsigned LastStartColumn, StringRef FileName) + : TokenAnalyzer(Env, Style), Code(Code), Ranges(Ranges), + FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn), + LastStartColumn(LastStartColumn), FileName(FileName) { + std::vector LeftOrder; + std::vector RightOrder; + std::vector ConfiguredQualifierTokens; + PrepareLeftRightOrdering(Style.QualifierOrder, LeftOrder, RightOrder, + ConfiguredQualifierTokens); + + // Handle the left and right Alignment Seperately + for (const auto &Qualifier : LeftOrder) { + Passes.emplace_back( + [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { + return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, + ConfiguredQualifierTokens, + /*RightAlign=*/false) + .process(); + }); + } + for (const auto &Qualifier : RightOrder) { + Passes.emplace_back( + [&, Qualifier, ConfiguredQualifierTokens](const Environment &Env) { + return LeftRightQualifierAlignmentFixer(Env, Style, Qualifier, + ConfiguredQualifierTokens, + /*RightAlign=*/true) + .process(); + }); + } +} + +std::pair QualifierAlignmentFixer::analyze( + TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) { + auto Env = Environment::make(Code, FileName, Ranges, FirstStartColumn, + NextStartColumn, LastStartColumn); + if (!Env) + return {}; + llvm::Optional CurrentCode = None; + tooling::Replacements Fixes; + for (size_t I = 0, E = Passes.size(); I < E; ++I) { + std::pair PassFixes = Passes[I](*Env); + auto NewCode = applyAllReplacements( + CurrentCode ? StringRef(*CurrentCode) : Code, PassFixes.first); + if (NewCode) { + Fixes = Fixes.merge(PassFixes.first); + if (I + 1 < E) { + CurrentCode = std::move(*NewCode); + Env = Environment::make( + *CurrentCode, FileName, + tooling::calculateRangesAfterReplacements(Fixes, Ranges), + FirstStartColumn, NextStartColumn, LastStartColumn); + if (!Env) + return {}; + } + } + } + + // Don't make replacements that replace nothing. + tooling::Replacements NonNoOpFixes; + + for (auto I = Fixes.begin(), E = Fixes.end(); I != E; ++I) { + StringRef OriginalCode = Code.substr(I->getOffset(), I->getLength()); + + if (!OriginalCode.equals(I->getReplacementText())) { + auto Err = NonNoOpFixes.add(*I); + if (Err) + llvm::errs() << "Error adding replacements : " + << llvm::toString(std::move(Err)) << "\n"; + } + } + return {NonNoOpFixes, 0}; +} + +static void replaceToken(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const CharSourceRange &Range, std::string NewText) { + auto Replacement = tooling::Replacement(SourceMgr, Range, NewText); + auto Err = Fixes.add(Replacement); + + if (Err) + llvm::errs() << "Error while rearranging Qualifier : " + << llvm::toString(std::move(Err)) << "\n"; +} + +static void removeToken(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First) { + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + First->Tok.getEndLoc()); + replaceToken(SourceMgr, Fixes, Range, ""); +} + +static void insertQualifierAfter(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First, + const std::string &Qualifier) { + FormatToken *Next = First->Next; + if (!Next) + return; + auto Range = CharSourceRange::getCharRange(Next->getStartOfNonWhitespace(), + Next->Tok.getEndLoc()); + + std::string NewText = " " + Qualifier + " "; + NewText += Next->TokenText; + replaceToken(SourceMgr, Fixes, Range, NewText); +} + +static void insertQualifierBefore(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, + const FormatToken *First, + const std::string &Qualifier) { + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + First->Tok.getEndLoc()); + + std::string NewText = " " + Qualifier + " "; + NewText += First->TokenText; + + replaceToken(SourceMgr, Fixes, Range, NewText); +} + +static bool endsWithSpace(const std::string &s) { + if (s.empty()) { + return false; + } + return isspace(s.back()); +} + +static bool startsWithSpace(const std::string &s) { + if (s.empty()) { + return false; + } + return isspace(s.front()); +} + +static void rotateTokens(const SourceManager &SourceMgr, + tooling::Replacements &Fixes, const FormatToken *First, + const FormatToken *Last, bool Left) { + auto *End = Last; + auto *Begin = First; + if (!Left) { + End = Last->Next; + Begin = First->Next; + } + + std::string NewText; + // If we are rotating to the left we move the Last token to the front. + if (Left) { + NewText += Last->TokenText; + NewText += " "; + } + + // Then move through the other tokens. + auto *Tok = Begin; + while (Tok != End) { + if (!NewText.empty() && !endsWithSpace(NewText)) { + NewText += " "; + } + + NewText += Tok->TokenText; + Tok = Tok->Next; + } + + // If we are rotating to the right we move the first token to the back. + if (!Left) { + if (!NewText.empty() && !startsWithSpace(NewText)) { + NewText += " "; + } + NewText += First->TokenText; + } + + auto Range = CharSourceRange::getCharRange(First->getStartOfNonWhitespace(), + Last->Tok.getEndLoc()); + + replaceToken(SourceMgr, Fixes, Range, NewText); +} + +FormatToken *LeftRightQualifierAlignmentFixer::analyzeRight( + const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, FormatToken *Tok, + const std::string &Qualifier, tok::TokenKind QualifierType) { + // We only need to think about streams that begin with a qualifier. + if (!Tok->is(QualifierType)) + return Tok; + // Don't concern yourself if nothing follows the qualifier. + if (!Tok->Next) + return Tok; + if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok->Next)) + return Tok; + + FormatToken *Qual = Tok->Next; + FormatToken *LastQual = Qual; + while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { + LastQual = Qual; + Qual = Qual->Next; + } + if (LastQual && Qual != LastQual) { + rotateTokens(SourceMgr, Fixes, Tok, LastQual, /*Left=*/false); + Tok = LastQual; + } else if (Tok->startsSequence(QualifierType, tok::identifier, + TT_TemplateOpener)) { + // Read from the TemplateOpener to + // TemplateCloser as in const ArrayRef a; const ArrayRef &a; + FormatToken *EndTemplate = Tok->Next->Next->MatchingParen; + if (EndTemplate) { + // Move to the end of any template class members e.g. + // `Foo::iterator`. + if (EndTemplate->startsSequence(TT_TemplateCloser, tok::coloncolon, + tok::identifier)) + EndTemplate = EndTemplate->Next->Next; + } + if (EndTemplate && EndTemplate->Next && + !EndTemplate->Next->isOneOf(tok::equal, tok::l_paren)) { + insertQualifierAfter(SourceMgr, Fixes, EndTemplate, Qualifier); + // Remove the qualifier. + removeToken(SourceMgr, Fixes, Tok); + return Tok; + } + } else if (Tok->startsSequence(QualifierType, tok::identifier)) { + FormatToken *Next = Tok->Next; + // The case `const Foo` -> `Foo const` + // The case `const Foo *` -> `Foo const *` + // The case `const Foo &` -> `Foo const &` + // The case `const Foo &&` -> `Foo const &&` + // The case `const std::Foo &&` -> `std::Foo const &&` + // The case `const std::Foo &&` -> `std::Foo const &&` + while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) { + Next = Next->Next; + } + if (Next && Next->is(TT_TemplateOpener)) { + Next = Next->MatchingParen; + // Move to the end of any template class members e.g. + // `Foo::iterator`. + if (Next && Next->startsSequence(TT_TemplateCloser, tok::coloncolon, + tok::identifier)) { + Next = Next->Next->Next; + return Tok; + } + assert(Next && "Missing template opener"); + Next = Next->Next; + } + if (Next && Next->isOneOf(tok::star, tok::amp, tok::ampamp) && + !Tok->Next->isOneOf(Keywords.kw_override, Keywords.kw_final)) { + if (Next->Previous && !Next->Previous->is(QualifierType)) { + insertQualifierAfter(SourceMgr, Fixes, Next->Previous, Qualifier); + removeToken(SourceMgr, Fixes, Tok); + } + return Next; + } + } + + return Tok; +} + +FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( + const SourceManager &SourceMgr, const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, FormatToken *Tok, + const std::string &Qualifier, tok::TokenKind QualifierType) { + // if Tok is an identifier and possibly a macro then don't convert. + if (LeftRightQualifierAlignmentFixer::isPossibleMacro(Tok)) + return Tok; + + FormatToken *Qual = Tok; + FormatToken *LastQual = Qual; + while (Qual && isQualifierOrType(Qual, ConfiguredQualifierTokens)) { + LastQual = Qual; + Qual = Qual->Next; + if (Qual && Qual->is(QualifierType)) + break; + } + + if (!Qual) { + return Tok; + } + + if (LastQual && Qual != LastQual && Qual->is(QualifierType)) { + rotateTokens(SourceMgr, Fixes, Tok, Qual, /*Left=*/true); + Tok = Qual->Next; + } else if (Tok->startsSequence(tok::identifier, QualifierType)) { + if (Tok->Next->Next && Tok->Next->Next->isOneOf(tok::identifier, tok::star, + tok::amp, tok::ampamp)) { + // Don't swap `::iterator const` to `::const iterator`. + if (!Tok->Previous || + (Tok->Previous && !Tok->Previous->is(tok::coloncolon))) { + rotateTokens(SourceMgr, Fixes, Tok, Tok->Next, /*Left=*/true); + Tok = Tok->Next; + } + } + } + if (Tok->is(TT_TemplateOpener) && Tok->Next && + (Tok->Next->is(tok::identifier) || Tok->Next->isSimpleTypeSpecifier()) && + Tok->Next->Next && Tok->Next->Next->is(QualifierType)) { + rotateTokens(SourceMgr, Fixes, Tok->Next, Tok->Next->Next, /*Left=*/true); + } + if (Tok->startsSequence(tok::identifier) && Tok->Next) { + if (Tok->Previous && + Tok->Previous->isOneOf(tok::star, tok::ampamp, tok::amp)) { + return Tok; + } + FormatToken *Next = Tok->Next; + // The case `std::Foo const` -> `const std::Foo &&` + while (Next && Next->isOneOf(tok::identifier, tok::coloncolon)) + Next = Next->Next; + if (Next && Next->Previous && + Next->Previous->startsSequence(tok::identifier, TT_TemplateOpener)) { + // Read from to the end of the TemplateOpener to + // TemplateCloser const ArrayRef a; const ArrayRef &a; + assert(Next->MatchingParen && "Missing template closer"); + Next = Next->MatchingParen->Next; + + // Move to the end of any template class members e.g. + // `Foo::iterator`. + if (Next && Next->startsSequence(tok::coloncolon, tok::identifier)) + Next = Next->Next->Next; + if (Next && Next->is(QualifierType)) { + // Remove the const. + insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); + removeToken(SourceMgr, Fixes, Next); + return Next; + } + } + if (Next && Next->Next && + Next->Next->isOneOf(tok::amp, tok::ampamp, tok::star)) { + if (Next->is(QualifierType)) { + // Remove the qualifier. + insertQualifierBefore(SourceMgr, Fixes, Tok, Qualifier); + removeToken(SourceMgr, Fixes, Next); + return Next; + } + } + } + return Tok; +} + +tok::TokenKind LeftRightQualifierAlignmentFixer::getTokenFromQualifier( + const std::string &Qualifier) { + // Don't let 'type' be an identifier, but steal typeof token. + return llvm::StringSwitch(Qualifier) + .Case("type", tok::kw_typeof) + .Case("const", tok::kw_const) + .Case("volatile", tok::kw_volatile) + .Case("static", tok::kw_static) + .Case("inline", tok::kw_inline) + .Case("constexpr", tok::kw_constexpr) + .Case("restrict", tok::kw_restrict) + .Default(tok::identifier); +} + +LeftRightQualifierAlignmentFixer::LeftRightQualifierAlignmentFixer( + const Environment &Env, const FormatStyle &Style, + const std::string &Qualifier, + const std::vector &QualifierTokens, bool RightAlign) + : TokenAnalyzer(Env, Style), Qualifier(Qualifier), RightAlign(RightAlign), + ConfiguredQualifierTokens(QualifierTokens) {} + +std::pair +LeftRightQualifierAlignmentFixer::analyze( + TokenAnnotator &Annotator, SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) { + tooling::Replacements Fixes; + const AdditionalKeywords &Keywords = Tokens.getKeywords(); + const SourceManager &SourceMgr = Env.getSourceManager(); + AffectedRangeMgr.computeAffectedLines(AnnotatedLines); + + tok::TokenKind QualifierToken = getTokenFromQualifier(Qualifier); + assert(QualifierToken != tok::identifier && "Unrecognised Qualifier"); + + for (size_t I = 0, E = AnnotatedLines.size(); I != E; ++I) { + FormatToken *First = AnnotatedLines[I]->First; + const auto *Last = AnnotatedLines[I]->Last; + + for (auto *Tok = First; Tok && Tok != Last && Tok->Next; Tok = Tok->Next) { + if (Tok->is(tok::comment)) + continue; + if (RightAlign) + Tok = analyzeRight(SourceMgr, Keywords, Fixes, Tok, Qualifier, + QualifierToken); + else + Tok = analyzeLeft(SourceMgr, Keywords, Fixes, Tok, Qualifier, + QualifierToken); + } + } + return {Fixes, 0}; +} + +void QualifierAlignmentFixer::PrepareLeftRightOrdering( + const std::vector &Order, std::vector &LeftOrder, + std::vector &RightOrder, + std::vector &Qualifiers) { + + // Depending on the position of type in the order you need + // To iterate forward or backward through the order list as qualifier + // can push through each other. + // The Order list must define the position of "type" to signify + assert(llvm::is_contained(Order, "type") && + "QualifierOrder must contain type"); + // Split the Order list by type and reverse the left side. + + bool left = true; + for (const auto &s : Order) { + if (s == "type") { + left = false; + continue; + } + + tok::TokenKind QualifierToken = + LeftRightQualifierAlignmentFixer::getTokenFromQualifier(s); + if (QualifierToken != tok::kw_typeof && QualifierToken != tok::identifier) { + Qualifiers.push_back(QualifierToken); + } + + if (left) + // Reverse the order for left aligned items. + LeftOrder.insert(LeftOrder.begin(), s); + else + RightOrder.push_back(s); + } +} + +bool LeftRightQualifierAlignmentFixer::isQualifierOrType( + const FormatToken *Tok, const std::vector &specifiedTypes) { + return Tok && (Tok->isSimpleTypeSpecifier() || Tok->is(tok::kw_auto) || + llvm::is_contained(specifiedTypes, Tok->Tok.getKind())); +} + +// If a token is an identifier and it's upper case, it could +// be a macro and hence we need to be able to ignore it. +bool LeftRightQualifierAlignmentFixer::isPossibleMacro(const FormatToken *Tok) { + if (!Tok) + return false; + if (!Tok->is(tok::identifier)) + return false; + if (Tok->TokenText.upper() == Tok->TokenText.str()) + return true; + return false; +} + +} // namespace format +} // namespace clang diff --git a/clang/lib/Format/QualifierAlignmentFixer.h b/clang/lib/Format/QualifierAlignmentFixer.h new file mode 100644 index 00000000000..7abd2568756 --- /dev/null +++ b/clang/lib/Format/QualifierAlignmentFixer.h @@ -0,0 +1,98 @@ +//===--- LeftRightQualifierAlignmentFixer.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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file declares LeftRightQualifierAlignmentFixer, a TokenAnalyzer that +/// enforces either east or west const depending on the style. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_FORMAT_QUALIFIERALIGNMENTFIXER_H +#define LLVM_CLANG_LIB_FORMAT_QUALIFIERALIGNMENTFIXER_H + +#include "TokenAnalyzer.h" + +namespace clang { +namespace format { + +typedef std::function( + const Environment &)> + AnalyzerPass; + +class QualifierAlignmentFixer : public TokenAnalyzer { + // Left to Right ordering requires multiple passes + SmallVector Passes; + StringRef &Code; + ArrayRef Ranges; + unsigned FirstStartColumn; + unsigned NextStartColumn; + unsigned LastStartColumn; + StringRef FileName; + +public: + QualifierAlignmentFixer(const Environment &Env, const FormatStyle &Style, + StringRef &Code, ArrayRef Ranges, + unsigned FirstStartColumn, unsigned NextStartColumn, + unsigned LastStartColumn, StringRef FileName); + + std::pair + analyze(TokenAnnotator &Annotator, + SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) override; + + static void PrepareLeftRightOrdering(const std::vector &Order, + std::vector &LeftOrder, + std::vector &RightOrder, + std::vector &Qualifiers); +}; + +class LeftRightQualifierAlignmentFixer : public TokenAnalyzer { + std::string Qualifier; + bool RightAlign; + SmallVector QualifierTokens; + std::vector ConfiguredQualifierTokens; + +public: + LeftRightQualifierAlignmentFixer( + const Environment &Env, const FormatStyle &Style, + const std::string &Qualifier, + const std::vector &ConfiguredQualifierTokens, + bool RightAlign); + + std::pair + analyze(TokenAnnotator &Annotator, + SmallVectorImpl &AnnotatedLines, + FormatTokenLexer &Tokens) override; + + static tok::TokenKind getTokenFromQualifier(const std::string &Qualifier); + + FormatToken *analyzeRight(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); + + FormatToken *analyzeLeft(const SourceManager &SourceMgr, + const AdditionalKeywords &Keywords, + tooling::Replacements &Fixes, FormatToken *Tok, + const std::string &Qualifier, + tok::TokenKind QualifierType); + + // is the Token a simple or qualifier type + static bool isQualifierOrType(const FormatToken *Tok, + const std::vector &Qualifiers); + + // is the Token likely a Macro + static bool isPossibleMacro(const FormatToken *Tok); +}; + +} // end namespace format +} // end namespace clang + +#endif diff --git a/clang/lib/Format/SortJavaScriptImports.cpp b/clang/lib/Format/SortJavaScriptImports.cpp index a5e3ce69207..515cfce725a 100644 --- a/clang/lib/Format/SortJavaScriptImports.cpp +++ b/clang/lib/Format/SortJavaScriptImports.cpp @@ -550,7 +550,10 @@ tooling::Replacements sortJavaScriptImports(const FormatStyle &Style, ArrayRef Ranges, StringRef FileName) { // FIXME: Cursor support. - return JavaScriptImportSorter(Environment(Code, FileName, Ranges), Style) + auto Env = Environment::make(Code, FileName, Ranges); + if (!Env) + return {}; + return JavaScriptImportSorter(*Env, Style) .process() .first; } diff --git a/clang/lib/Format/TokenAnalyzer.cpp b/clang/lib/Format/TokenAnalyzer.cpp index f1459a808ff..a619c6d939e 100644 --- a/clang/lib/Format/TokenAnalyzer.cpp +++ b/clang/lib/Format/TokenAnalyzer.cpp @@ -26,26 +26,61 @@ #include "clang/Basic/SourceManager.h" #include "clang/Format/Format.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Debug.h" +#include #define DEBUG_TYPE "format-formatter" namespace clang { namespace format { +// FIXME: Instead of printing the diagnostic we should store it and have a +// better way to return errors through the format APIs. +class FatalDiagnosticConsumer: public DiagnosticConsumer { +public: + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + if (DiagLevel == DiagnosticsEngine::Fatal) { + Fatal = true; + llvm::SmallVector Message; + Info.FormatDiagnostic(Message); + llvm::errs() << Message << "\n"; + } + } + + bool fatalError() const { return Fatal; } + +private: + bool Fatal = false; +}; + +std::unique_ptr +Environment::make(StringRef Code, StringRef FileName, + ArrayRef Ranges, unsigned FirstStartColumn, + unsigned NextStartColumn, unsigned LastStartColumn) { + auto Env = std::make_unique(Code, FileName, FirstStartColumn, + NextStartColumn, LastStartColumn); + FatalDiagnosticConsumer Diags; + Env->SM.getDiagnostics().setClient(&Diags, /*ShouldOwnClient=*/false); + SourceLocation StartOfFile = Env->SM.getLocForStartOfFile(Env->ID); + for (const tooling::Range &Range : Ranges) { + SourceLocation Start = StartOfFile.getLocWithOffset(Range.getOffset()); + SourceLocation End = Start.getLocWithOffset(Range.getLength()); + Env->CharRanges.push_back(CharSourceRange::getCharRange(Start, End)); + } + // Validate that we can get the buffer data without a fatal error. + Env->SM.getBufferData(Env->ID); + if (Diags.fatalError()) return nullptr; + return Env; +} + Environment::Environment(StringRef Code, StringRef FileName, - ArrayRef Ranges, unsigned FirstStartColumn, unsigned NextStartColumn, unsigned LastStartColumn) : VirtualSM(new SourceManagerForFile(FileName, Code)), SM(VirtualSM->get()), ID(VirtualSM->get().getMainFileID()), FirstStartColumn(FirstStartColumn), NextStartColumn(NextStartColumn), LastStartColumn(LastStartColumn) { - SourceLocation StartOfFile = SM.getLocForStartOfFile(ID); - for (const tooling::Range &Range : Ranges) { - SourceLocation Start = StartOfFile.getLocWithOffset(Range.getOffset()); - SourceLocation End = Start.getLocWithOffset(Range.getLength()); - CharRanges.push_back(CharSourceRange::getCharRange(Start, End)); - } } TokenAnalyzer::TokenAnalyzer(const Environment &Env, const FormatStyle &Style) diff --git a/clang/lib/Format/TokenAnalyzer.h b/clang/lib/Format/TokenAnalyzer.h index 5ce44a0f3ea..aaca518df41 100644 --- a/clang/lib/Format/TokenAnalyzer.h +++ b/clang/lib/Format/TokenAnalyzer.h @@ -29,6 +29,7 @@ #include "clang/Format/Format.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" +#include namespace clang { namespace format { @@ -40,8 +41,7 @@ public: // that the next lines of \p Code should start at \p NextStartColumn, and // that \p Code should end at \p LastStartColumn if it ends in newline. // See also the documentation of clang::format::internal::reformat. - Environment(StringRef Code, StringRef FileName, - ArrayRef Ranges, unsigned FirstStartColumn = 0, + Environment(StringRef Code, StringRef FileName, unsigned FirstStartColumn = 0, unsigned NextStartColumn = 0, unsigned LastStartColumn = 0); FileID getFileID() const { return ID; } @@ -62,6 +62,14 @@ public: // environment should end if it ends in a newline. unsigned getLastStartColumn() const { return LastStartColumn; } + // Returns nullptr and prints a diagnostic to stderr if the environment + // can't be created. + static std::unique_ptr make(StringRef Code, StringRef FileName, + ArrayRef Ranges, + unsigned FirstStartColumn = 0, + unsigned NextStartColumn = 0, + unsigned LastStartColumn = 0); + private: // This is only set if constructed from string. std::unique_ptr VirtualSM; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 54e6c7d38e7..3897241cb85 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1671,7 +1671,7 @@ private: Current.setType(TT_TrailingReturnArrow); } else if (Current.is(tok::arrow) && Current.Previous && Current.Previous->is(tok::r_brace)) { - // Concept implicit conversion contraint needs to be treated like + // Concept implicit conversion constraint needs to be treated like // a trailing return type ... } -> . Current.setType(TT_TrailingReturnArrow); } else if (isDeductionGuide(Current)) { @@ -2322,11 +2322,9 @@ private: void TokenAnnotator::setCommentLineLevels( SmallVectorImpl &Lines) { const AnnotatedLine *NextNonCommentLine = nullptr; - for (SmallVectorImpl::reverse_iterator I = Lines.rbegin(), - E = Lines.rend(); - I != E; ++I) { + for (AnnotatedLine *AL : llvm::reverse(Lines)) { bool CommentLine = true; - for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { + for (const FormatToken *Tok = AL->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; @@ -2338,21 +2336,21 @@ void TokenAnnotator::setCommentLineLevels( if (NextNonCommentLine && CommentLine && NextNonCommentLine->First->NewlinesBefore <= 1 && NextNonCommentLine->First->OriginalColumn == - (*I)->First->OriginalColumn) { + AL->First->OriginalColumn) { // Align comments for preprocessor lines with the # in column 0 if // preprocessor lines are not indented. Otherwise, align with the next // line. - (*I)->Level = + AL->Level = (Style.IndentPPDirectives != FormatStyle::PPDIS_BeforeHash && (NextNonCommentLine->Type == LT_PreprocessorDirective || NextNonCommentLine->Type == LT_ImportStatement)) ? 0 : NextNonCommentLine->Level; } else { - NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; + NextNonCommentLine = AL->First->isNot(tok::r_brace) ? AL : nullptr; } - setCommentLineLevels((*I)->Children); + setCommentLineLevels(AL->Children); } } @@ -2398,7 +2396,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { // This function heuristically determines whether 'Current' starts the name of a // function declaration. -static bool isFunctionDeclarationName(const FormatToken &Current, +static bool isFunctionDeclarationName(bool IsCpp, const FormatToken &Current, const AnnotatedLine &Line) { auto skipOperatorName = [](const FormatToken *Next) -> const FormatToken * { for (; Next; Next = Next->Next) { @@ -2467,7 +2465,7 @@ static bool isFunctionDeclarationName(const FormatToken &Current, // Check whether parameter list can belong to a function declaration. if (!Next || !Next->is(tok::l_paren) || !Next->MatchingParen) return false; - // If the lines ends with "{", this is likely an function definition. + // If the lines ends with "{", this is likely a function definition. if (Line.Last->is(tok::l_brace)) return true; if (Next->Next == Next->MatchingParen) @@ -2476,14 +2474,21 @@ static bool isFunctionDeclarationName(const FormatToken &Current, if (Next->MatchingParen->Next && Next->MatchingParen->Next->is(TT_PointerOrReference)) return true; - // Check for K&R C function definitions, e.g.: + + // Check for K&R C function definitions (and C++ function definitions with + // unnamed parameters), e.g.: // int f(i) // { // return i + 1; // } - if (Next->Next && Next->Next->is(tok::identifier) && - !(Next->MatchingParen->Next && Next->MatchingParen->Next->is(tok::semi))) + // bool g(size_t = 0, bool b = false) + // { + // return !b; + // } + if (IsCpp && Next->Next && Next->Next->is(tok::identifier) && + !Line.endsWith(tok::semi)) return true; + for (const FormatToken *Tok = Next->Next; Tok && Tok != Next->MatchingParen; Tok = Tok->Next) { if (Tok->is(TT_TypeDeclarationParen)) @@ -2544,7 +2549,7 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) { calculateArrayInitializerColumnList(Line); while (Current) { - if (isFunctionDeclarationName(*Current, Line)) + if (isFunctionDeclarationName(Style.isCpp(), *Current, Line)) Current->setType(TT_FunctionDeclarationName); if (Current->is(TT_LineComment)) { if (Current->Previous->is(BK_BracedInit) && @@ -2899,7 +2904,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line, bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { return Style.SpaceBeforeParens == FormatStyle::SBPO_Always || - (Style.SpaceBeforeParens == FormatStyle::SBPO_NonEmptyParentheses && + (Style.SpaceBeforeParensOptions.BeforeNonEmptyParentheses && Right.ParameterCount > 0); } @@ -2933,9 +2938,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return true; } - // requires ( or requires( - if (Right.is(tok::l_paren) && Left.is(tok::kw_requires)) - return spaceRequiredBeforeParens(Right); + // auto{x} auto(x) + if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) + return false; + // requires clause Concept1 && Concept2 if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier)) return true; @@ -2991,7 +2997,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (!TokenBeforeMatchingParen || !Left.is(TT_TypeDeclarationParen)) return true; } - // Add a space if the previous token is a pointer qualifer or the closing + // Add a space if the previous token is a pointer qualifier or the closing // parenthesis of __attribute__(()) expression and the style requires spaces // after pointer qualifiers. if ((Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_After || @@ -3012,7 +3018,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Line.IsMultiVariableDeclStmt))) return true; if (Left.is(TT_PointerOrReference)) { - // Add a space if the next token is a pointer qualifer and the style + // Add a space if the next token is a pointer qualifier and the style // requires spaces before pointer qualifiers. if ((Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Before || Style.SpaceAroundPointerQualifiers == FormatStyle::SAPQ_Both) && @@ -3031,7 +3037,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Left.Previous->isOneOf(tok::l_paren, tok::coloncolon, tok::l_square)); } - // Ensure right pointer alignement with ellipsis e.g. int *...P + // Ensure right pointer alignment with ellipsis e.g. int *...P if (Left.is(tok::ellipsis) && Left.Previous && Left.Previous->isOneOf(tok::star, tok::amp, tok::ampamp)) return Style.PointerAlignment != FormatStyle::PAS_Right; @@ -3127,33 +3133,60 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // e.g. template [[nodiscard]] ... if (Left.is(TT_TemplateCloser) && Right.is(TT_AttributeSquare)) return true; + // Space before parentheses common for all languages if (Right.is(tok::l_paren)) { + if (Left.is(TT_TemplateCloser) && Right.isNot(TT_FunctionTypeLParen)) + return spaceRequiredBeforeParens(Right); + if (Left.is(tok::kw_requires)) + return spaceRequiredBeforeParens(Right); if ((Left.is(tok::r_paren) && Left.is(TT_AttributeParen)) || (Left.is(tok::r_square) && Left.is(TT_AttributeSquare))) return true; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && - Left.is(TT_ForEachMacro)) - return false; - if (Style.SpaceBeforeParens == - FormatStyle::SBPO_ControlStatementsExceptControlMacros && - Left.is(TT_IfMacro)) - return false; - return Line.Type == LT_ObjCDecl || Left.is(tok::semi) || - (Style.SpaceBeforeParens != FormatStyle::SBPO_Never && - (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, - tok::kw_switch, tok::kw_case, TT_ForEachMacro, - TT_ObjCForIn) || - Left.isIf(Line.Type != LT_PreprocessorDirective) || - (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch, - tok::kw_new, tok::kw_delete) && - (!Left.Previous || Left.Previous->isNot(tok::period))))) || - (spaceRequiredBeforeParens(Right) && - (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || - Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier() || - (Left.is(tok::r_square) && Left.MatchingParen && - Left.MatchingParen->is(TT_LambdaLSquare))) && - Line.Type != LT_PreprocessorDirective); + if (Left.is(TT_ForEachMacro)) + return (Style.SpaceBeforeParensOptions.AfterForeachMacros || + spaceRequiredBeforeParens(Right)); + if (Left.is(TT_IfMacro)) + return (Style.SpaceBeforeParensOptions.AfterIfMacros || + spaceRequiredBeforeParens(Right)); + if (Line.Type == LT_ObjCDecl) + return true; + if (Left.is(tok::semi)) + return true; + if (Left.isOneOf(tok::pp_elif, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_case, TT_ForEachMacro, TT_ObjCForIn)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + if (Left.isIf(Line.Type != LT_PreprocessorDirective)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + // Function declaration or definition + if (Line.MightBeFunctionDecl && (Left.is(TT_FunctionDeclarationName) || + Right.is(TT_OverloadedOperatorLParen))) { + if (Line.mightBeFunctionDefinition()) + return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || + spaceRequiredBeforeParens(Right); + else + return Style.SpaceBeforeParensOptions.AfterFunctionDeclarationName || + spaceRequiredBeforeParens(Right); + } + // Lambda + if (Line.Type != LT_PreprocessorDirective && Left.is(tok::r_square) && + Left.MatchingParen && Left.MatchingParen->is(TT_LambdaLSquare)) + return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || + spaceRequiredBeforeParens(Right); + if (!Left.Previous || Left.Previous->isNot(tok::period)) { + if (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch)) + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); + if (Left.isOneOf(tok::kw_new, tok::kw_delete)) + return Style.SpaceBeforeParens != FormatStyle::SBPO_Never || + spaceRequiredBeforeParens(Right); + } + if (Line.Type != LT_PreprocessorDirective && + (Left.is(tok::identifier) || Left.isFunctionLikeKeyword() || + Left.is(tok::r_paren) || Left.isSimpleTypeSpecifier())) + return spaceRequiredBeforeParens(Right); + return false; } if (Left.is(tok::at) && Right.Tok.getObjCKeywordID() != tok::objc_not_keyword) return false; @@ -3195,6 +3228,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // qualifiers such as // void Fn() const &; return getTokenReferenceAlignment(Right) != FormatStyle::PAS_Left; + return true; } @@ -3300,7 +3334,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(tok::l_paren)) if (Left.isOneOf(tok::kw_using, Keywords.kw_async, Keywords.kw_when, Keywords.kw_lock)) - return Style.SpaceBeforeParens == FormatStyle::SBPO_ControlStatements || + return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); // space between method modifier and opening parenthesis of a tuple return @@ -3407,7 +3441,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.is(tok::r_square) && Right.is(tok::l_brace)) return true; if (Left.is(Keywords.kw_synchronized) && Right.is(tok::l_paren)) - return Style.SpaceBeforeParens != FormatStyle::SBPO_Never; + return Style.SpaceBeforeParensOptions.AfterControlStatements || + spaceRequiredBeforeParens(Right); if ((Left.isOneOf(tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected) || Left.isOneOf(Keywords.kw_final, Keywords.kw_abstract, @@ -3433,9 +3468,7 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) || Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) return true; - if (Right.is(TT_OverloadedOperatorLParen)) - return spaceRequiredBeforeParens(Right); - if (Left.is(tok::comma)) + if (Left.is(tok::comma) && !Right.is(TT_OverloadedOperatorLParen)) return true; if (Right.is(tok::comma)) return false; @@ -3558,9 +3591,6 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, (Left.isOneOf(TT_BinaryOperator, TT_ConditionalExpr) && !Right.is(tok::r_paren))) return true; - if (Left.is(TT_TemplateCloser) && Right.is(tok::l_paren) && - Right.isNot(TT_FunctionTypeLParen)) - return spaceRequiredBeforeParens(Right); if (Right.is(TT_TemplateOpener) && Left.is(tok::r_paren) && Left.MatchingParen && Left.MatchingParen->is(TT_OverloadedOperatorLParen)) return false; @@ -3580,7 +3610,7 @@ static bool isAllmanBrace(const FormatToken &Tok) { !Tok.isOneOf(TT_ObjCBlockLBrace, TT_LambdaLBrace, TT_DictLiteral); } -// Returns 'true' if 'Tok' is an function argument. +// Returns 'true' if 'Tok' is a function argument. static bool IsFunctionArgument(const FormatToken &Tok) { return Tok.MatchingParen && Tok.MatchingParen->Next && Tok.MatchingParen->Next->isOneOf(tok::comma, tok::r_paren); @@ -3597,6 +3627,16 @@ static bool isAllmanLambdaBrace(const FormatToken &Tok) { !Tok.isOneOf(TT_ObjCBlockLBrace, TT_DictLiteral)); } +// Returns the first token on the line that is not a comment. +static const FormatToken *getFirstNonComment(const AnnotatedLine &Line) { + const FormatToken *Next = Line.First; + if (!Next) + return Next; + if (Next->is(tok::comment)) + Next = Next->getNextNonComment(); + return Next; +} + bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right) { const FormatToken &Left = *Right.Previous; @@ -3696,7 +3736,7 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Left.is(TT_ArrayInitializerLSquare) && Left.is(tok::l_square) && !Right.is(tok::r_square)) return true; - // Always break afer successive entries. + // Always break after successive entries. // 1, // 2 if (Left.is(tok::comma)) @@ -3747,13 +3787,18 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, return Style.BreakBeforeConceptDeclarations; return (Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes); } - if (Right.is(TT_CtorInitializerComma) && + if (Style.PackConstructorInitializers == FormatStyle::PCIS_Never) { + if (Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeColon && + (Left.is(TT_CtorInitializerComma) || Right.is(TT_CtorInitializerColon))) + return true; + + if (Style.BreakConstructorInitializers == FormatStyle::BCIS_AfterColon && + Left.isOneOf(TT_CtorInitializerColon, TT_CtorInitializerComma)) + return true; + } + if (Style.PackConstructorInitializers < FormatStyle::PCIS_CurrentLine && Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && - !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) - return true; - if (Right.is(TT_CtorInitializerColon) && - Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma && - !Style.ConstructorInitializerAllOnOneLineOrOnePerLine) + Right.isOneOf(TT_CtorInitializerComma, TT_CtorInitializerColon)) return true; // Break only if we have multiple inheritance. if (Style.BreakInheritanceList == FormatStyle::BILS_BeforeComma && @@ -3778,16 +3823,42 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Right.is(TT_InlineASMBrace)) return Right.HasUnescapedNewline; - if (isAllmanBrace(Left) || isAllmanBrace(Right)) - return (Line.startsWith(tok::kw_enum) && Style.BraceWrapping.AfterEnum) || - (Line.startsWith(tok::kw_typedef, tok::kw_enum) && - Style.BraceWrapping.AfterEnum) || - (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || + if (isAllmanBrace(Left) || isAllmanBrace(Right)) { + auto FirstNonComment = getFirstNonComment(Line); + bool AccessSpecifier = + FirstNonComment && + FirstNonComment->isOneOf(Keywords.kw_internal, tok::kw_public, + tok::kw_private, tok::kw_protected); + + if (Style.BraceWrapping.AfterEnum) { + if (Line.startsWith(tok::kw_enum) || + Line.startsWith(tok::kw_typedef, tok::kw_enum)) + return true; + // Ensure BraceWrapping for `public enum A {`. + if (AccessSpecifier && FirstNonComment->Next && + FirstNonComment->Next->is(tok::kw_enum)) + return true; + } + + // Ensure BraceWrapping for `public interface A {`. + if (Style.BraceWrapping.AfterClass && + ((AccessSpecifier && FirstNonComment->Next && + FirstNonComment->Next->is(Keywords.kw_interface)) || + Line.startsWith(Keywords.kw_interface))) + return true; + + return (Line.startsWith(tok::kw_class) && Style.BraceWrapping.AfterClass) || (Line.startsWith(tok::kw_struct) && Style.BraceWrapping.AfterStruct); + } + if (Left.is(TT_ObjCBlockLBrace) && Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never) return true; + // Ensure wrapping after __attribute__((XX)) and @interface etc. + if (Left.is(TT_AttributeParen) && Right.is(TT_ObjCDecl)) + return true; + if (Left.is(TT_LambdaLBrace)) { if (IsFunctionArgument(Left) && Style.AllowShortLambdasOnASingleLine == FormatStyle::SLS_Inline) @@ -3957,8 +4028,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, tok::kw_return, Keywords.kw_yield, tok::kw_continue, tok::kw_break, tok::kw_throw, Keywords.kw_interface, Keywords.kw_type, tok::kw_static, tok::kw_public, tok::kw_private, tok::kw_protected, - Keywords.kw_readonly, Keywords.kw_abstract, Keywords.kw_get, - Keywords.kw_set, Keywords.kw_async, Keywords.kw_await)) + Keywords.kw_readonly, Keywords.kw_override, Keywords.kw_abstract, + Keywords.kw_get, Keywords.kw_set, Keywords.kw_async, + Keywords.kw_await)) return false; // Otherwise automatic semicolon insertion would trigger. if (Right.NestingLevel == 0 && (Left.Tok.getIdentifierInfo() || @@ -4012,7 +4084,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, Keywords.kw_interface, Keywords.kw_type, Keywords.kw_var, Keywords.kw_let, tok::kw_const)) // See grammar for 'declare' statements at: - // https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#A.10 + // https://github.com/Microsoft/TypeScript/blob/main/doc/spec-ARCHIVED.md#A.10 return false; if (Left.isOneOf(Keywords.kw_module, tok::kw_namespace) && Right.isOneOf(tok::identifier, tok::string_literal)) diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index 0f9c02dbeb3..6e5e62cd4d8 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -53,9 +53,7 @@ public: // left them in a different state. First->Previous = nullptr; FormatToken *Current = First; - for (std::list::const_iterator I = ++Line.Tokens.begin(), - E = Line.Tokens.end(); - I != E; ++I) { + for (auto I = ++Line.Tokens.begin(), E = Line.Tokens.end(); I != E; ++I) { const UnwrappedLineNode &Node = *I; Current->Next = I->Tok; I->Tok->Previous = Current; diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index cca85c1074d..299536cd806 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -104,7 +104,7 @@ private: RootToken.isObjCAccessSpecifier() || (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) && RootToken.Next && RootToken.Next->is(tok::colon))) { - // The AccessModifierOffset may be overriden by IndentAccessModifiers, + // The AccessModifierOffset may be overridden by IndentAccessModifiers, // in which case we take a negative value of the IndentWidth to simulate // the upper indent level. return Style.IndentAccessModifiers ? -Style.IndentWidth @@ -632,10 +632,11 @@ private: FormatToken *RecordTok = Line.First; // Skip record modifiers. while (RecordTok->Next && - RecordTok->isOneOf( - tok::kw_typedef, tok::kw_export, Keywords.kw_declare, - Keywords.kw_abstract, tok::kw_default, tok::kw_public, - tok::kw_private, tok::kw_protected, Keywords.kw_internal)) + RecordTok->isOneOf(tok::kw_typedef, tok::kw_export, + Keywords.kw_declare, Keywords.kw_abstract, + tok::kw_default, Keywords.kw_override, + tok::kw_public, tok::kw_private, + tok::kw_protected, Keywords.kw_internal)) RecordTok = RecordTok->Next; if (RecordTok && RecordTok->isOneOf(tok::kw_class, tok::kw_union, tok::kw_struct, diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 103e3559b12..28d925858f7 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -385,7 +385,7 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { // be in a non-declaration context. if (!FormatTok->is(TT_MacroBlockBegin) && tryToParseBracedList()) continue; - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); break; case tok::r_brace: @@ -431,7 +431,7 @@ void UnwrappedLineParser::parseLevel(bool HasOpeningBrace) { } LLVM_FALLTHROUGH; default: - parseStructuralElement(/*IsTopLevel=*/true); + parseStructuralElement(!HasOpeningBrace); break; } } while (!eof()); @@ -489,6 +489,17 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); } else { + // Skip NextTok over preprocessor lines, otherwise we may not + // properly diagnose the block as a braced intializer + // if the comma separator appears after the pp directive. + while (NextTok->is(tok::hash)) { + ScopedMacroState MacroState(*Line, Tokens, NextTok); + do { + NextTok = Tokens->getNextToken(); + ++ReadTokens; + } while (NextTok->isNot(tok::eof)); + } + // Using OriginalColumn to distinguish between ObjC methods and // binary operators is a bit hacky. bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && @@ -962,8 +973,8 @@ static bool mustBeJSIdent(const AdditionalKeywords &Keywords, Keywords.kw_function, Keywords.kw_import, Keywords.kw_is, Keywords.kw_let, Keywords.kw_var, tok::kw_const, Keywords.kw_abstract, Keywords.kw_extends, Keywords.kw_implements, - Keywords.kw_instanceof, Keywords.kw_interface, Keywords.kw_throws, - Keywords.kw_from)); + Keywords.kw_instanceof, Keywords.kw_interface, + Keywords.kw_override, Keywords.kw_throws, Keywords.kw_from)); } static bool mustBeJSIdentOrValue(const AdditionalKeywords &Keywords, @@ -994,6 +1005,13 @@ static bool isJSDeclOrStmt(const AdditionalKeywords &Keywords, Keywords.kw_import, tok::kw_export); } +// Checks whether a token is a type in K&R C (aka C78). +static bool isC78Type(const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_char, tok::kw_short, tok::kw_int, tok::kw_long, + tok::kw_unsigned, tok::kw_float, tok::kw_double, + tok::identifier); +} + // This function checks whether a token starts the first parameter declaration // in a K&R C (aka C78) function definition, e.g.: // int f(a, b) @@ -1001,13 +1019,24 @@ static bool isJSDeclOrStmt(const AdditionalKeywords &Keywords, // { // return a + b; // } -static bool isC78ParameterDecl(const FormatToken *Tok) { - if (!Tok) +static bool isC78ParameterDecl(const FormatToken *Tok, const FormatToken *Next, + const FormatToken *FuncName) { + assert(Tok); + assert(Next); + assert(FuncName); + + if (FuncName->isNot(tok::identifier)) return false; - if (!Tok->isOneOf(tok::kw_int, tok::kw_char, tok::kw_float, tok::kw_double, - tok::kw_struct, tok::kw_union, tok::kw_long, tok::kw_short, - tok::kw_unsigned, tok::kw_register, tok::identifier)) + const FormatToken *Prev = FuncName->Previous; + if (!Prev || (Prev->isNot(tok::star) && !isC78Type(*Prev))) + return false; + + if (!isC78Type(*Tok) && + !Tok->isOneOf(tok::kw_register, tok::kw_struct, tok::kw_union)) + return false; + + if (Next->isNot(tok::star) && !Next->Tok.getIdentifierInfo()) return false; Tok = Tok->Previous; @@ -1046,10 +1075,9 @@ void UnwrappedLineParser::readTokenWithJavaScriptASI() { if (PreviousMustBeValue || Previous->is(tok::r_paren)) { // If the line contains an '@' sign, the previous token might be an // annotation, which can precede another identifier/value. - bool HasAt = std::find_if(Line->Tokens.begin(), Line->Tokens.end(), - [](UnwrappedLineNode &LineNode) { - return LineNode.Tok->is(tok::at); - }) != Line->Tokens.end(); + bool HasAt = llvm::any_of(Line->Tokens, [](UnwrappedLineNode &LineNode) { + return LineNode.Tok->is(tok::at); + }); if (HasAt) return; } @@ -1285,7 +1313,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { if (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); } addUnwrappedLine(); return; @@ -1298,7 +1326,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { if (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); } addUnwrappedLine(); return; @@ -1368,21 +1396,20 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { case tok::r_brace: addUnwrappedLine(); return; - case tok::l_paren: + case tok::l_paren: { parseParens(); // Break the unwrapped line if a K&R C function definition has a parameter // declaration. - if (!IsTopLevel || !Style.isCpp()) + if (!IsTopLevel || !Style.isCpp() || !Previous || FormatTok->is(tok::eof)) break; - if (!Previous || Previous->isNot(tok::identifier)) - break; - if (Previous->Previous && Previous->Previous->is(tok::at)) - break; - if (isC78ParameterDecl(FormatTok)) { + const unsigned Position = Tokens->getPosition() + 1; + assert(Position < AllTokens.size()); + if (isC78ParameterDecl(FormatTok, AllTokens[Position], Previous)) { addUnwrappedLine(); return; } break; + } case tok::kw_operator: nextToken(); if (FormatTok->isBinaryOperator()) @@ -1407,7 +1434,7 @@ void UnwrappedLineParser::parseStructuralElement(bool IsTopLevel) { if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); FormatTok->setType(TT_FunctionLBrace); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); return; } @@ -2051,7 +2078,7 @@ void UnwrappedLineParser::parseIfThenElse() { bool NeedsUnwrappedLine = false; if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); if (Style.BraceWrapping.BeforeElse) addUnwrappedLine(); else @@ -2069,7 +2096,7 @@ void UnwrappedLineParser::parseIfThenElse() { parseSquare(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); } else if (FormatTok->Tok.is(tok::kw_if)) { FormatToken *Previous = AllTokens[Tokens->getPosition() - 1]; @@ -2131,7 +2158,7 @@ void UnwrappedLineParser::parseTryCatch() { } if (FormatTok->is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); if (Style.BraceWrapping.BeforeCatch) { addUnwrappedLine(); } else { @@ -2169,7 +2196,7 @@ void UnwrappedLineParser::parseTryCatch() { } NeedsUnwrappedLine = false; CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); if (Style.BraceWrapping.BeforeCatch) addUnwrappedLine(); else @@ -2189,7 +2216,7 @@ void UnwrappedLineParser::parseNamespace() { parseParens(); } else { while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw_inline, - tok::l_square)) { + tok::l_square, tok::period)) { if (FormatTok->is(tok::l_square)) parseSquare(); else @@ -2282,7 +2309,7 @@ void UnwrappedLineParser::parseForOrWhileLoop() { parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); } else { addUnwrappedLine(); @@ -2297,7 +2324,7 @@ void UnwrappedLineParser::parseDoWhile() { nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); if (Style.BraceWrapping.BeforeWhile) addUnwrappedLine(); } else { @@ -2336,7 +2363,7 @@ void UnwrappedLineParser::parseLabel(bool LeftAlignLabel) { CompoundStatementIndenter Indenter(this, Line->Level, Style.BraceWrapping.AfterCaseLabel, Style.BraceWrapping.IndentBraces); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); if (FormatTok->Tok.is(tok::kw_break)) { if (Style.BraceWrapping.AfterControlStatement == FormatStyle::BWACS_Always) { @@ -2378,7 +2405,7 @@ void UnwrappedLineParser::parseSwitch() { parseParens(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); } else { addUnwrappedLine(); @@ -2430,7 +2457,7 @@ void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) { if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); FormatTok->setType(TT_FunctionLBrace); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); } else { parseConstraintExpression(OriginalLevel); @@ -2467,7 +2494,7 @@ void UnwrappedLineParser::parseConstraintExpression( if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); FormatTok->setType(TT_FunctionLBrace); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); } if (FormatTok->Tok.is(tok::semi)) { // Eat any trailing semi. @@ -2515,6 +2542,8 @@ bool UnwrappedLineParser::parseEnum() { if (FormatTok->Tok.is(tok::kw_enum)) nextToken(); + const FormatToken &InitialToken = *FormatTok; + // In TypeScript, "enum" can also be used as property name, e.g. in interface // declarations. An "enum" keyword followed by a colon would be a syntax // error and thus assume it is just an identifier. @@ -2561,7 +2590,8 @@ bool UnwrappedLineParser::parseEnum() { return true; } - if (!Style.AllowShortEnumsOnASingleLine) + if (!Style.AllowShortEnumsOnASingleLine && + ShouldBreakBeforeBrace(Style, InitialToken)) addUnwrappedLine(); // Parse enum body. nextToken(); @@ -2804,7 +2834,7 @@ void UnwrappedLineParser::parseObjCMethod() { } else if (FormatTok->Tok.is(tok::l_brace)) { if (Style.BraceWrapping.AfterFunction) addUnwrappedLine(); - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); addUnwrappedLine(); return; } else { @@ -2833,7 +2863,7 @@ void UnwrappedLineParser::parseObjCUntilAtEnd() { break; } if (FormatTok->is(tok::l_brace)) { - parseBlock(/*MustBeDeclaration=*/false); + parseBlock(); // In ObjC interfaces, nothing should be following the "}". addUnwrappedLine(); } else if (FormatTok->is(tok::r_brace)) { @@ -3004,24 +3034,15 @@ LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line, llvm::dbgs() << Prefix << "Line(" << Line.Level << ", FSC=" << Line.FirstStartColumn << ")" << (Line.InPPDirective ? " MACRO" : "") << ": "; - for (std::list::const_iterator I = Line.Tokens.begin(), - E = Line.Tokens.end(); - I != E; ++I) { - llvm::dbgs() << I->Tok->Tok.getName() << "[" - << "T=" << (unsigned)I->Tok->getType() - << ", OC=" << I->Tok->OriginalColumn << "] "; - } - for (std::list::const_iterator I = Line.Tokens.begin(), - E = Line.Tokens.end(); - I != E; ++I) { - const UnwrappedLineNode &Node = *I; - for (SmallVectorImpl::const_iterator - I = Node.Children.begin(), - E = Node.Children.end(); - I != E; ++I) { - printDebugInfo(*I, "\nChild: "); - } + for (const auto &Node : Line.Tokens) { + llvm::dbgs() << Node.Tok->Tok.getName() << "[" + << "T=" << static_cast(Node.Tok->getType()) + << ", OC=" << Node.Tok->OriginalColumn << "] "; } + for (const auto &Node : Line.Tokens) + for (const auto &ChildNode : Node.Children) + printDebugInfo(ChildNode, "\nChild: "); + llvm::dbgs() << "\n"; } diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index f22bb6323e3..bcae0f3ad25 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -19,8 +19,8 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Format/Format.h" #include "llvm/Support/Regex.h" -#include #include +#include namespace clang { namespace format { @@ -36,9 +36,8 @@ struct UnwrappedLineNode; struct UnwrappedLine { UnwrappedLine(); - // FIXME: Don't use std::list here. /// The \c Tokens comprising this \c UnwrappedLine. - std::list Tokens; + std::vector Tokens; /// The indent level of the \c UnwrappedLine. unsigned Level; @@ -85,7 +84,7 @@ private: void reset(); void parseFile(); void parseLevel(bool HasOpeningBrace); - void parseBlock(bool MustBeDeclaration, unsigned AddLevels = 1u, + void parseBlock(bool MustBeDeclaration = false, unsigned AddLevels = 1u, bool MunchSemi = true, bool UnindentWhitesmithsBraces = false); void parseChildBlock(); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index ca2222d1fef..74136d2f5ca 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -347,7 +347,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ScopeStart > Start + 1 && Changes[ScopeStart - 2].Tok->is(tok::identifier) && Changes[ScopeStart - 1].Tok->is(tok::l_paren)) - return true; + return Style.BinPackArguments; // Ternary operator if (Changes[i].Tok->is(TT_ConditionalExpr)) @@ -1146,14 +1146,15 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, } else if (C.Tok->is(tok::comma)) { if (!Cells.empty()) Cells.back().EndIndex = i; - Cell++; + if (C.Tok->getNextNonComment()->isNot(tok::r_brace)) // dangling comma + ++Cell; } } else if (Depth == 1) { if (C.Tok == MatchingParen) { if (!Cells.empty()) Cells.back().EndIndex = i; Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr}); - CellCount = Cell + 1; + CellCount = C.Tok->Previous->isNot(tok::comma) ? Cell + 1 : Cell; // Go to the next non-comment and ensure there is a break in front const auto *NextNonComment = C.Tok->getNextNonComment(); while (NextNonComment->is(tok::comma)) @@ -1190,6 +1191,17 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, // So if we split a line previously and the tail line + this token is // less then the column limit we remove the split here and just put // the column start at a space past the comma + // + // FIXME This if branch covers the cases where the column is not + // the first column. This leads to weird pathologies like the formatting + // auto foo = Items{ + // Section{ + // 0, bar(), + // } + // }; + // Well if it doesn't lead to that it's indicative that the line + // breaking should be revisited. Unfortunately alot of other options + // interact with this auto j = i - 1; if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) && Changes[j - 1].NewlinesBefore > 0) { diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 4f8f95040af..029f4159b74 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -257,7 +257,7 @@ private: /// Does this \p Cell contain a split element? static bool isSplitCell(const CellDescription &Cell); - /// Get the width of the preceeding cells from \p Start to \p End. + /// Get the width of the preceding cells from \p Start to \p End. template auto getNetWidth(const I &Start, const I &End, unsigned InitialSpaces) const { auto NetWidth = InitialSpaces; diff --git a/clang/lib/Frontend/ASTConsumers.cpp b/clang/lib/Frontend/ASTConsumers.cpp index a73cc8876d5..96f5926c0d7 100644 --- a/clang/lib/Frontend/ASTConsumers.cpp +++ b/clang/lib/Frontend/ASTConsumers.cpp @@ -57,8 +57,11 @@ namespace { bool ShowColors = Out.has_colors(); if (ShowColors) Out.changeColor(raw_ostream::BLUE); - Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D) - << ":\n"; + + if (OutputFormat == ADOF_Default) + Out << (OutputKind != Print ? "Dumping " : "Printing ") << getName(D) + << ":\n"; + if (ShowColors) Out.resetColor(); print(D); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 996783aa9cf..52589677ca2 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1069,9 +1069,7 @@ static void checkAndRemoveNonDriverDiags(SmallVectorImpl &StoredDiags) { // Get rid of stored diagnostics except the ones from the driver which do not // have a source location. - StoredDiags.erase( - std::remove_if(StoredDiags.begin(), StoredDiags.end(), isNonDriverDiag), - StoredDiags.end()); + llvm::erase_if(StoredDiags, isNonDriverDiag); } static void checkAndSanitizeDiags(SmallVectorImpl & @@ -1989,6 +1987,7 @@ static void CalculateHiddenNames(const CodeCompletionContext &Context, case CodeCompletionContext::CCC_ObjCClassMessage: case CodeCompletionContext::CCC_ObjCCategoryName: case CodeCompletionContext::CCC_IncludedFile: + case CodeCompletionContext::CCC_Attribute: case CodeCompletionContext::CCC_NewName: // We're looking for nothing, or we're looking for names that cannot // be hidden. diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c642af1849b..1432607204b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -23,6 +23,7 @@ #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/LogDiagnosticPrinter.h" #include "clang/Frontend/SerializedDiagnosticPrinter.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -558,6 +559,54 @@ void CompilerInstance::createASTContext() { // ExternalASTSource +namespace { +// Helper to recursively read the module names for all modules we're adding. +// We mark these as known and redirect any attempt to load that module to +// the files we were handed. +struct ReadModuleNames : ASTReaderListener { + Preprocessor &PP; + llvm::SmallVector LoadedModules; + + ReadModuleNames(Preprocessor &PP) : PP(PP) {} + + void ReadModuleName(StringRef ModuleName) override { + // Keep the module name as a string for now. It's not safe to create a new + // IdentifierInfo from an ASTReader callback. + LoadedModules.push_back(ModuleName.str()); + } + + void registerAll() { + ModuleMap &MM = PP.getHeaderSearchInfo().getModuleMap(); + for (const std::string &LoadedModule : LoadedModules) + MM.cacheModuleLoad(*PP.getIdentifierInfo(LoadedModule), + MM.findModule(LoadedModule)); + LoadedModules.clear(); + } + + void markAllUnavailable() { + for (const std::string &LoadedModule : LoadedModules) { + if (Module *M = PP.getHeaderSearchInfo().getModuleMap().findModule( + LoadedModule)) { + M->HasIncompatibleModuleFile = true; + + // Mark module as available if the only reason it was unavailable + // was missing headers. + SmallVector Stack; + Stack.push_back(M); + while (!Stack.empty()) { + Module *Current = Stack.pop_back_val(); + if (Current->IsUnimportable) continue; + Current->IsAvailable = true; + Stack.insert(Stack.end(), + Current->submodule_begin(), Current->submodule_end()); + } + } + } + LoadedModules.clear(); + } +}; +} // namespace + void CompilerInstance::createPCHExternalASTSource( StringRef Path, DisableValidationForModuleKind DisableValidation, bool AllowPCHWithCompilerErrors, void *DeserializationListener, @@ -602,6 +651,11 @@ IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( for (auto &Listener : DependencyCollectors) Listener->attachToASTReader(*Reader); + auto Listener = std::make_unique(PP); + auto &ListenerRef = *Listener; + ASTReader::ListenerScope ReadModuleNamesListener(*Reader, + std::move(Listener)); + switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH, @@ -611,6 +665,7 @@ IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. PP.setPredefines(Reader->getSuggestedPredefines()); + ListenerRef.registerAll(); return Reader; case ASTReader::Failure: @@ -626,6 +681,7 @@ IntrusiveRefCntPtr CompilerInstance::createPCHExternalASTSource( break; } + ListenerRef.markAllUnavailable(); Context.setExternalSource(nullptr); return nullptr; } @@ -1029,6 +1085,27 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { return !getDiagnostics().getClient()->getNumErrors(); } +void CompilerInstance::LoadRequestedPlugins() { + // Load any requested plugins. + for (const std::string &Path : getFrontendOpts().Plugins) { + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) + getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) + << Path << Error; + } + + // Check if any of the loaded plugins replaces the main AST action + for (const FrontendPluginRegistry::entry &Plugin : + FrontendPluginRegistry::entries()) { + std::unique_ptr P(Plugin.instantiate()); + if (P->getActionType() == PluginASTAction::ReplaceAction) { + getFrontendOpts().ProgramAction = clang::frontend::PluginAction; + getFrontendOpts().ActionName = Plugin.getName().str(); + break; + } + } +} + /// Determine the appropriate source input kind based on language /// options. static Language getLanguageFromOptions(const LangOptions &LangOpts) { @@ -1077,14 +1154,12 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // Remove any macro definitions that are explicitly ignored by the module. // They aren't supposed to affect how the module is built anyway. HeaderSearchOptions &HSOpts = Invocation->getHeaderSearchOpts(); - PPOpts.Macros.erase( - std::remove_if(PPOpts.Macros.begin(), PPOpts.Macros.end(), - [&HSOpts](const std::pair &def) { + llvm::erase_if( + PPOpts.Macros, [&HSOpts](const std::pair &def) { StringRef MacroDef = def.first; return HSOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first)) > 0; - }), - PPOpts.Macros.end()); + }); // If the original compiler invocation had -fmodule-name, pass it through. Invocation->getLangOpts()->ModuleName = @@ -1264,23 +1339,75 @@ static bool compileModule(CompilerInstance &ImportingInstance, return Result; } +/// Read the AST right after compiling the module. +static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, StringRef ModuleFileName, + bool *OutOfDate) { + DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics(); + + unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing; + if (OutOfDate) + ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; + + // Try to read the module file, now that we've compiled it. + ASTReader::ASTReadResult ReadResult = + ImportingInstance.getASTReader()->ReadAST( + ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, + ModuleLoadCapabilities); + if (ReadResult == ASTReader::Success) + return true; + + // The caller wants to handle out-of-date failures. + if (OutOfDate && ReadResult == ASTReader::OutOfDate) { + *OutOfDate = true; + return false; + } + + // The ASTReader didn't diagnose the error, so conservatively report it. + if (ReadResult == ASTReader::Missing || !Diags.hasErrorOccurred()) + Diags.Report(ModuleNameLoc, diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + + return false; +} + /// Compile a module in a separate compiler instance and read the AST, /// returning true if the module compiles without errors. +static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, + StringRef ModuleFileName) { + if (!compileModule(ImportingInstance, ModuleNameLoc, Module, + ModuleFileName)) { + ImportingInstance.getDiagnostics().Report(ModuleNameLoc, + diag::err_module_not_built) + << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); + return false; + } + + return readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc, + Module, ModuleFileName, + /*OutOfDate=*/nullptr); +} + +/// Compile a module in a separate compiler instance and read the AST, +/// returning true if the module compiles without errors, using a lock manager +/// to avoid building the same module in multiple compiler instances. /// /// Uses a lock file manager and exponential backoff to reduce the chances that /// multiple instances will compete to create the same module. On timeout, /// deletes the lock file in order to avoid deadlock from crashing processes or /// bugs in the lock file manager. -static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - SourceLocation ModuleNameLoc, - Module *Module, StringRef ModuleFileName) { +static bool compileModuleAndReadASTBehindLock( + CompilerInstance &ImportingInstance, SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, Module *Module, StringRef ModuleFileName) { DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics(); - auto diagnoseBuildFailure = [&] { - Diags.Report(ModuleNameLoc, diag::err_module_not_built) - << Module->Name << SourceRange(ImportLoc, ModuleNameLoc); - }; + Diags.Report(ModuleNameLoc, diag::remark_module_lock) + << ModuleFileName << Module->Name; // FIXME: have LockFileManager return an error_code so that we can // avoid the mkdir when the directory already exists. @@ -1288,7 +1415,6 @@ static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, llvm::sys::fs::create_directories(Dir); while (1) { - unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing; llvm::LockFileManager Locked(ModuleFileName); switch (Locked) { case llvm::LockFileManager::LFS_Error: @@ -1302,58 +1428,64 @@ static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, LLVM_FALLTHROUGH; case llvm::LockFileManager::LFS_Owned: // We're responsible for building the module ourselves. - if (!compileModule(ImportingInstance, ModuleNameLoc, Module, - ModuleFileName)) { - diagnoseBuildFailure(); - return false; - } - break; + return compileModuleAndReadASTImpl(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, ModuleFileName); case llvm::LockFileManager::LFS_Shared: - // Someone else is responsible for building the module. Wait for them to - // finish. - switch (Locked.waitForUnlock()) { - case llvm::LockFileManager::Res_Success: - ModuleLoadCapabilities |= ASTReader::ARR_OutOfDate; - break; - case llvm::LockFileManager::Res_OwnerDied: - continue; // try again to get the lock. - case llvm::LockFileManager::Res_Timeout: - // Since ModuleCache takes care of correctness, we try waiting for - // another process to complete the build so clang does not do it done - // twice. If case of timeout, build it ourselves. - Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout) - << Module->Name; - // Clear the lock file so that future invocations can make progress. - Locked.unsafeRemoveLockFile(); - continue; - } - break; + break; // The interesting case. } - // Try to read the module file, now that we've compiled it. - ASTReader::ASTReadResult ReadResult = - ImportingInstance.getASTReader()->ReadAST( - ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, - ModuleLoadCapabilities); - - if (ReadResult == ASTReader::OutOfDate && - Locked == llvm::LockFileManager::LFS_Shared) { - // The module may be out of date in the presence of file system races, - // or if one of its imports depends on header search paths that are not - // consistent with this ImportingInstance. Try again... + // Someone else is responsible for building the module. Wait for them to + // finish. + switch (Locked.waitForUnlock()) { + case llvm::LockFileManager::Res_Success: + break; // The interesting case. + case llvm::LockFileManager::Res_OwnerDied: + continue; // try again to get the lock. + case llvm::LockFileManager::Res_Timeout: + // Since ModuleCache takes care of correctness, we try waiting for + // another process to complete the build so clang does not do it done + // twice. If case of timeout, build it ourselves. + Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout) + << Module->Name; + // Clear the lock file so that future invocations can make progress. + Locked.unsafeRemoveLockFile(); continue; - } else if (ReadResult == ASTReader::Missing) { - diagnoseBuildFailure(); - } else if (ReadResult != ASTReader::Success && - !Diags.hasErrorOccurred()) { - // The ASTReader didn't diagnose the error, so conservatively report it. - diagnoseBuildFailure(); } - return ReadResult == ASTReader::Success; + + // Read the module that was just written by someone else. + bool OutOfDate = false; + if (readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc, + Module, ModuleFileName, &OutOfDate)) + return true; + if (!OutOfDate) + return false; + + // The module may be out of date in the presence of file system races, + // or if one of its imports depends on header search paths that are not + // consistent with this ImportingInstance. Try again... } } +/// Compile a module in a separate compiler instance and read the AST, +/// returning true if the module compiles without errors, potentially using a +/// lock manager to avoid building the same module in multiple compiler +/// instances. +static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, StringRef ModuleFileName) { + return ImportingInstance.getInvocation() + .getFrontendOpts() + .BuildingImplicitModuleUsesLock + ? compileModuleAndReadASTBehindLock(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, + ModuleFileName) + : compileModuleAndReadASTImpl(ImportingInstance, ImportLoc, + ModuleNameLoc, Module, + ModuleFileName); +} + /// Diagnose differences between the current definition of the given /// configuration macro and the definition provided on the command line. static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro, @@ -1555,52 +1687,6 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - // Helper to recursively read the module names for all modules we're adding. - // We mark these as known and redirect any attempt to load that module to - // the files we were handed. - struct ReadModuleNames : ASTReaderListener { - CompilerInstance &CI; - llvm::SmallVector LoadedModules; - - ReadModuleNames(CompilerInstance &CI) : CI(CI) {} - - void ReadModuleName(StringRef ModuleName) override { - LoadedModules.push_back( - CI.getPreprocessor().getIdentifierInfo(ModuleName)); - } - - void registerAll() { - ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - for (auto *II : LoadedModules) - MM.cacheModuleLoad(*II, MM.findModule(II->getName())); - LoadedModules.clear(); - } - - void markAllUnavailable() { - for (auto *II : LoadedModules) { - if (Module *M = CI.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .findModule(II->getName())) { - M->HasIncompatibleModuleFile = true; - - // Mark module as available if the only reason it was unavailable - // was missing headers. - SmallVector Stack; - Stack.push_back(M); - while (!Stack.empty()) { - Module *Current = Stack.pop_back_val(); - if (Current->IsUnimportable) continue; - Current->IsAvailable = true; - Stack.insert(Stack.end(), - Current->submodule_begin(), Current->submodule_end()); - } - } - } - LoadedModules.clear(); - } - }; - // If we don't already have an ASTReader, create one now. if (!TheASTReader) createASTReader(); @@ -1612,7 +1698,7 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { SourceLocation()) <= DiagnosticsEngine::Warning; - auto Listener = std::make_unique(*this); + auto Listener = std::make_unique(*PP); auto &ListenerRef = *Listener; ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader, std::move(Listener)); @@ -1691,7 +1777,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( SourceLocation ModuleNameLoc, bool IsInclusionDirective) { // Search for a module with the given name. HeaderSearch &HS = PP->getHeaderSearchInfo(); - Module *M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + Module *M = + HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective); // Select the source and filename for loading the named module. std::string ModuleFilename; @@ -1750,7 +1837,7 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( // A prebuilt module is indexed as a ModuleFile; the Module does not exist // until the first call to ReadAST. Look it up now. - M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + M = HS.lookupModule(ModuleName, ImportLoc, true, !IsInclusionDirective); // Check whether M refers to the file in the prebuilt module path. if (M && M->getASTFile()) @@ -1873,7 +1960,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. Module = PP->getHeaderSearchInfo().lookupModule( - ModuleName, /*AllowSearch*/ true, + ModuleName, ImportLoc, /*AllowSearch*/ true, /*AllowExtraModuleMapSearch*/ !IsInclusionDirective); /// FIXME: perhaps we should (a) look for a module using the module name // to file map (PrebuiltModuleFiles) and (b) diagnose if still not found? @@ -1903,90 +1990,84 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // Verify that the rest of the module path actually corresponds to // a submodule. bool MapPrivateSubModToTopLevel = false; - if (Path.size() > 1) { - for (unsigned I = 1, N = Path.size(); I != N; ++I) { - StringRef Name = Path[I].first->getName(); - clang::Module *Sub = Module->findSubmodule(Name); + for (unsigned I = 1, N = Path.size(); I != N; ++I) { + StringRef Name = Path[I].first->getName(); + clang::Module *Sub = Module->findSubmodule(Name); - // If the user is requesting Foo.Private and it doesn't exist, try to - // match Foo_Private and emit a warning asking for the user to write - // @import Foo_Private instead. FIXME: remove this when existing clients - // migrate off of Foo.Private syntax. - if (!Sub && PP->getLangOpts().ImplicitModules && Name == "Private" && - Module == Module->getTopLevelModule()) { - SmallString<128> PrivateModule(Module->Name); - PrivateModule.append("_Private"); + // If the user is requesting Foo.Private and it doesn't exist, try to + // match Foo_Private and emit a warning asking for the user to write + // @import Foo_Private instead. FIXME: remove this when existing clients + // migrate off of Foo.Private syntax. + if (!Sub && PP->getLangOpts().ImplicitModules && Name == "Private" && + Module == Module->getTopLevelModule()) { + SmallString<128> PrivateModule(Module->Name); + PrivateModule.append("_Private"); - SmallVector, 2> PrivPath; - auto &II = PP->getIdentifierTable().get( - PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID()); - PrivPath.push_back(std::make_pair(&II, Path[0].second)); + SmallVector, 2> PrivPath; + auto &II = PP->getIdentifierTable().get( + PrivateModule, PP->getIdentifierInfo(Module->Name)->getTokenID()); + PrivPath.push_back(std::make_pair(&II, Path[0].second)); - if (PP->getHeaderSearchInfo().lookupModule(PrivateModule, true, - !IsInclusionDirective)) - Sub = - loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective); - if (Sub) { - MapPrivateSubModToTopLevel = true; - if (!getDiagnostics().isIgnored( - diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) { - getDiagnostics().Report(Path[I].second, - diag::warn_no_priv_submodule_use_toplevel) - << Path[I].first << Module->getFullModuleName() << PrivateModule - << SourceRange(Path[0].second, Path[I].second) - << FixItHint::CreateReplacement(SourceRange(Path[0].second), - PrivateModule); - getDiagnostics().Report(Sub->DefinitionLoc, - diag::note_private_top_level_defined); + if (PP->getHeaderSearchInfo().lookupModule(PrivateModule, ImportLoc, true, + !IsInclusionDirective)) + Sub = loadModule(ImportLoc, PrivPath, Visibility, IsInclusionDirective); + if (Sub) { + MapPrivateSubModToTopLevel = true; + if (!getDiagnostics().isIgnored( + diag::warn_no_priv_submodule_use_toplevel, ImportLoc)) { + getDiagnostics().Report(Path[I].second, + diag::warn_no_priv_submodule_use_toplevel) + << Path[I].first << Module->getFullModuleName() << PrivateModule + << SourceRange(Path[0].second, Path[I].second) + << FixItHint::CreateReplacement(SourceRange(Path[0].second), + PrivateModule); + getDiagnostics().Report(Sub->DefinitionLoc, + diag::note_private_top_level_defined); + } + } + } + + if (!Sub) { + // Attempt to perform typo correction to find a module name that works. + SmallVector Best; + unsigned BestEditDistance = (std::numeric_limits::max)(); + + for (class Module *SubModule : Module->submodules()) { + unsigned ED = + Name.edit_distance(SubModule->Name, + /*AllowReplacements=*/true, BestEditDistance); + if (ED <= BestEditDistance) { + if (ED < BestEditDistance) { + Best.clear(); + BestEditDistance = ED; } + + Best.push_back(SubModule->Name); } } - if (!Sub) { - // Attempt to perform typo correction to find a module name that works. - SmallVector Best; - unsigned BestEditDistance = (std::numeric_limits::max)(); - - for (clang::Module::submodule_iterator J = Module->submodule_begin(), - JEnd = Module->submodule_end(); - J != JEnd; ++J) { - unsigned ED = Name.edit_distance((*J)->Name, - /*AllowReplacements=*/true, - BestEditDistance); - if (ED <= BestEditDistance) { - if (ED < BestEditDistance) { - Best.clear(); - BestEditDistance = ED; - } - - Best.push_back((*J)->Name); - } - } - - // If there was a clear winner, user it. - if (Best.size() == 1) { - getDiagnostics().Report(Path[I].second, - diag::err_no_submodule_suggest) + // If there was a clear winner, user it. + if (Best.size() == 1) { + getDiagnostics().Report(Path[I].second, diag::err_no_submodule_suggest) << Path[I].first << Module->getFullModuleName() << Best[0] - << SourceRange(Path[0].second, Path[I-1].second) + << SourceRange(Path[0].second, Path[I - 1].second) << FixItHint::CreateReplacement(SourceRange(Path[I].second), Best[0]); - Sub = Module->findSubmodule(Best[0]); - } + Sub = Module->findSubmodule(Best[0]); } - - if (!Sub) { - // No submodule by this name. Complain, and don't look for further - // submodules. - getDiagnostics().Report(Path[I].second, diag::err_no_submodule) - << Path[I].first << Module->getFullModuleName() - << SourceRange(Path[0].second, Path[I-1].second); - break; - } - - Module = Sub; } + + if (!Sub) { + // No submodule by this name. Complain, and don't look for further + // submodules. + getDiagnostics().Report(Path[I].second, diag::err_no_submodule) + << Path[I].first << Module->getFullModuleName() + << SourceRange(Path[0].second, Path[I - 1].second); + break; + } + + Module = Sub; } // Make the named module visible, if it's not already part of the module @@ -2071,8 +2152,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, const FileEntry *ModuleMapFile = Other.getFileManager().getVirtualFile( ModuleMapFileName, NullTerminatedSource.size(), 0); Other.getSourceManager().overrideFileContents( - ModuleMapFile, - llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource.c_str())); + ModuleMapFile, llvm::MemoryBuffer::getMemBuffer(NullTerminatedSource)); Other.BuiltModules = std::move(BuiltModules); Other.DeleteBuiltModules = false; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index d545e9358f0..c104a6f40e2 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -78,6 +78,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/HashBuilder.h" #include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -453,6 +454,8 @@ static bool FixupInvocation(CompilerInvocation &Invocation, CodeGenOpts.XRayAlwaysEmitTypedEvents = LangOpts.XRayAlwaysEmitTypedEvents; CodeGenOpts.DisableFree = FrontendOpts.DisableFree; FrontendOpts.GenerateGlobalModuleIndex = FrontendOpts.UseGlobalModuleIndex; + if (FrontendOpts.ShowStats) + CodeGenOpts.ClearASTBeforeBackend = false; LangOpts.SanitizeCoverage = CodeGenOpts.hasSanitizeCoverage(); LangOpts.ForceEmitVTables = CodeGenOpts.ForceEmitVTables; LangOpts.SpeculativeLoadHardening = CodeGenOpts.SpeculativeLoadHardening; @@ -503,9 +506,10 @@ static bool FixupInvocation(CompilerInvocation &Invocation, // -cl-strict-aliasing needs to emit diagnostic in the case where CL > 1.0. // This option should be deprecated for CL > 1.0 because // this option was added for compatibility with OpenCL 1.0. - if (Args.getLastArg(OPT_cl_strict_aliasing) && LangOpts.OpenCLVersion > 100) + if (Args.getLastArg(OPT_cl_strict_aliasing) && + (LangOpts.getOpenCLCompatibleVersion() > 100)) Diags.Report(diag::warn_option_invalid_ocl_version) - << LangOpts.getOpenCLVersionTuple().getAsString() + << LangOpts.getOpenCLVersionString() << Args.getLastArg(OPT_cl_strict_aliasing)->getAsString(Args); if (Arg *A = Args.getLastArg(OPT_fdefault_calling_conv_EQ)) { @@ -608,9 +612,8 @@ using GenerateFn = llvm::function_ref; // May perform round-trip of command line arguments. By default, the round-trip -// is enabled if CLANG_ROUND_TRIP_CC1_ARGS was defined during build. This can be -// overwritten at run-time via the "-round-trip-args" and "-no-round-trip-args" -// command line flags. +// is enabled in assert builds. This can be overwritten at run-time via the +// "-round-trip-args" and "-no-round-trip-args" command line flags. // During round-trip, the command line arguments are parsed into a dummy // instance of CompilerInvocation which is used to generate the command line // arguments again. The real CompilerInvocation instance is then created by @@ -620,8 +623,7 @@ static bool RoundTrip(ParseFn Parse, GenerateFn Generate, CompilerInvocation &DummyInvocation, ArrayRef CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0) { - // FIXME: Switch to '#ifndef NDEBUG' when possible. -#ifdef CLANG_ROUND_TRIP_CC1_ARGS +#ifndef NDEBUG bool DoRoundTripDefault = true; #else bool DoRoundTripDefault = false; @@ -995,7 +997,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, diag::err_analyzer_config_no_value) << configVal; break; } - if (val.find('=') != StringRef::npos) { + if (val.contains('=')) { Diags.Report(SourceLocation(), diag::err_analyzer_config_multiple_values) << configVal; @@ -1118,10 +1120,9 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, for (const StringRef &CheckerOrPackage : CheckersAndPackages) { if (Diags) { bool IsChecker = CheckerOrPackage.contains('.'); - bool IsValidName = - IsChecker - ? llvm::find(Checkers, CheckerOrPackage) != Checkers.end() - : llvm::find(Packages, CheckerOrPackage) != Packages.end(); + bool IsValidName = IsChecker + ? llvm::is_contained(Checkers, CheckerOrPackage) + : llvm::is_contained(Packages, CheckerOrPackage); if (!IsValidName) Diags->Report(diag::err_unknown_analyzer_checker_or_package) @@ -1172,8 +1173,9 @@ ParseOptimizationRemark(DiagnosticsEngine &Diags, ArgList &Args, OptSpecifier OptEQ, StringRef Name) { CodeGenOptions::OptRemark Result; - auto InitializeResultPattern = [&Diags, &Args, &Result](const Arg *A) { - Result.Pattern = A->getValue(); + auto InitializeResultPattern = [&Diags, &Args, &Result](const Arg *A, + StringRef Pattern) { + Result.Pattern = Pattern.str(); std::string RegexError; Result.Regex = std::make_shared(Result.Pattern); @@ -1198,19 +1200,23 @@ ParseOptimizationRemark(DiagnosticsEngine &Diags, ArgList &Args, Result.Kind = CodeGenOptions::RK_Disabled; else if (Value == "no-everything") Result.Kind = CodeGenOptions::RK_DisabledEverything; + else + continue; + + if (Result.Kind == CodeGenOptions::RK_Disabled || + Result.Kind == CodeGenOptions::RK_DisabledEverything) { + Result.Pattern = ""; + Result.Regex = nullptr; + } else { + InitializeResultPattern(A, ".*"); + } } else if (A->getOption().matches(OptEQ)) { Result.Kind = CodeGenOptions::RK_WithPattern; - if (!InitializeResultPattern(A)) + if (!InitializeResultPattern(A, A->getValue())) return CodeGenOptions::OptRemark(); } } - if (Result.Kind == CodeGenOptions::RK_Disabled || - Result.Kind == CodeGenOptions::RK_DisabledEverything) { - Result.Pattern = ""; - Result.Regex = nullptr; - } - return Result; } @@ -1406,6 +1412,13 @@ void CompilerInvocation::GenerateCodeGenArgs( llvm::DICompileUnit::DebugNameTableKind::Default)) GenerateArg(Args, OPT_gpubnames, SA); + auto TNK = Opts.getDebugSimpleTemplateNames(); + if (TNK != codegenoptions::DebugTemplateNamesKind::Full) { + if (TNK == codegenoptions::DebugTemplateNamesKind::Simple) + GenerateArg(Args, OPT_gsimple_template_names_EQ, "simple", SA); + else if (TNK == codegenoptions::DebugTemplateNamesKind::Mangled) + GenerateArg(Args, OPT_gsimple_template_names_EQ, "mangled", SA); + } // ProfileInstrumentUsePath is marshalled automatically, no need to generate // it or PGOUseInstrumentor. @@ -1417,7 +1430,7 @@ void CompilerInvocation::GenerateCodeGenArgs( } if (Opts.PrepareForLTO && !Opts.PrepareForThinLTO) - GenerateArg(Args, OPT_flto, SA); + GenerateArg(Args, OPT_flto_EQ, "full", SA); if (Opts.PrepareForThinLTO) GenerateArg(Args, OPT_flto_EQ, "thin", SA); @@ -1680,6 +1693,16 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, : Args.hasArg(OPT_gpubnames) ? llvm::DICompileUnit::DebugNameTableKind::Default : llvm::DICompileUnit::DebugNameTableKind::None); + if (const Arg *A = Args.getLastArg(OPT_gsimple_template_names_EQ)) { + StringRef Value = A->getValue(); + if (Value != "simple" && Value != "mangled") + Diags.Report(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(); + Opts.setDebugSimpleTemplateNames( + StringRef(A->getValue()) == "simple" + ? codegenoptions::DebugTemplateNamesKind::Simple + : codegenoptions::DebugTemplateNamesKind::Mangled); + } if (!Opts.ProfileInstrumentUsePath.empty()) setPGOUseInstrumentor(Opts, Opts.ProfileInstrumentUsePath); @@ -1704,9 +1727,10 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, } } - Opts.PrepareForLTO = Args.hasArg(OPT_flto, OPT_flto_EQ); + Opts.PrepareForLTO = false; Opts.PrepareForThinLTO = false; if (Arg *A = Args.getLastArg(OPT_flto_EQ)) { + Opts.PrepareForLTO = true; StringRef S = A->getValue(); if (S == "thin") Opts.PrepareForThinLTO = true; @@ -2035,13 +2059,13 @@ static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts, if (!Args.hasArg(OPT_fno_sanitize_ignorelist)) { for (const auto *A : Args.filtered(OPT_fsanitize_ignorelist_EQ)) { StringRef Val = A->getValue(); - if (Val.find('=') == StringRef::npos) + if (!Val.contains('=')) Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeIgnorelist); } if (Opts.IncludeSystemHeaders) { for (const auto *A : Args.filtered(OPT_fsanitize_system_ignorelist_EQ)) { StringRef Val = A->getValue(); - if (Val.find('=') == StringRef::npos) + if (!Val.contains('=')) Opts.ExtraDeps.emplace_back(std::string(Val), EDK_SanitizeIgnorelist); } } @@ -2058,7 +2082,7 @@ static bool ParseDependencyOutputArgs(DependencyOutputOptions &Opts, // Only the -fmodule-file= form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); - if (Val.find('=') == StringRef::npos) + if (!Val.contains('=')) Opts.ExtraDeps.emplace_back(std::string(Val), EDK_ModuleFile); } @@ -2255,6 +2279,19 @@ void CompilerInvocation::GenerateDiagnosticArgs( } } +std::unique_ptr +clang::CreateAndPopulateDiagOpts(ArrayRef Argv) { + auto DiagOpts = std::make_unique(); + unsigned MissingArgIndex, MissingArgCount; + InputArgList Args = getDriverOptTable().ParseArgs( + Argv.slice(1), MissingArgIndex, MissingArgCount); + // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. + // Any errors that would be diagnosed here will also be diagnosed later, + // when the DiagnosticsEngine actually exists. + (void)ParseDiagnosticArgs(*DiagOpts, Args); + return DiagOpts; +} + bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, DiagnosticsEngine *Diags, bool DefaultDiagColor) { @@ -2689,7 +2726,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, // Only the -fmodule-file= form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); - if (Val.find('=') == StringRef::npos) + if (!Val.contains('=')) Opts.ModuleFiles.push_back(std::string(Val)); } @@ -2837,7 +2874,7 @@ static void GenerateHeaderSearchArgs(HeaderSearchOptions &Opts, llvm::ArrayRef Groups, llvm::Optional IsFramework, llvm::Optional IgnoreSysRoot) { - return llvm::find(Groups, Entry.Group) != Groups.end() && + return llvm::is_contained(Groups, Entry.Group) && (!IsFramework || (Entry.IsFramework == *IsFramework)) && (!IgnoreSysRoot || (Entry.IgnoreSysRoot == *IgnoreSysRoot)); }; @@ -2964,7 +3001,7 @@ static bool ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args, // Only the -fmodule-file== form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); - if (Val.find('=') != StringRef::npos){ + if (Val.contains('=')) { auto Split = Val.split('='); Opts.PrebuiltModuleFiles.insert( {std::string(Split.first), std::string(Split.second)}); @@ -3091,7 +3128,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, LangStd = LangStandard::lang_opencl12; break; case Language::OpenCLCXX: - LangStd = LangStandard::lang_openclcpp; + LangStd = LangStandard::lang_openclcpp10; break; case Language::CUDA: LangStd = LangStandard::lang_cuda; @@ -3150,8 +3187,6 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.HexFloats = Std.hasHexFloats(); Opts.ImplicitInt = Std.hasImplicitInt(); - Opts.CPlusPlusModules = Opts.CPlusPlus20; - // Set OpenCL Version. Opts.OpenCL = Std.isOpenCL(); if (LangStd == LangStandard::lang_opencl10) @@ -3164,8 +3199,10 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.OpenCLVersion = 200; else if (LangStd == LangStandard::lang_opencl30) Opts.OpenCLVersion = 300; - else if (LangStd == LangStandard::lang_openclcpp) + else if (LangStd == LangStandard::lang_openclcpp10) Opts.OpenCLCPlusPlusVersion = 100; + else if (LangStd == LangStandard::lang_openclcpp2021) + Opts.OpenCLCPlusPlusVersion = 202100; // OpenCL has some additional defaults. if (Opts.OpenCL) { @@ -3173,9 +3210,8 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, Opts.ZVector = 0; Opts.setDefaultFPContractMode(LangOptions::FPM_On); Opts.OpenCLCPlusPlus = Opts.CPlusPlus; - Opts.OpenCLPipe = Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200; - Opts.OpenCLGenericAddressSpace = - Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200; + Opts.OpenCLPipes = Opts.getOpenCLCompatibleVersion() == 200; + Opts.OpenCLGenericAddressSpace = Opts.getOpenCLCompatibleVersion() == 200; // Include default header file for OpenCL. if (Opts.IncludeDefaultHeader) { @@ -3314,7 +3350,8 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, case LangStandard::lang_opencl12: case LangStandard::lang_opencl20: case LangStandard::lang_opencl30: - case LangStandard::lang_openclcpp: + case LangStandard::lang_openclcpp10: + case LangStandard::lang_openclcpp2021: StdOpt = OPT_cl_std_EQ; break; default: @@ -3445,6 +3482,19 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Args, OPT_fopenmp_version_EQ, Twine(Opts.OpenMP), SA); } + if (Opts.OpenMPTargetNewRuntime) + GenerateArg(Args, OPT_fopenmp_target_new_runtime, SA); + + if (Opts.OpenMPThreadSubscription) + GenerateArg(Args, OPT_fopenmp_assume_threads_oversubscription, SA); + + if (Opts.OpenMPTeamSubscription) + GenerateArg(Args, OPT_fopenmp_assume_teams_oversubscription, SA); + + if (Opts.OpenMPTargetDebug != 0) + GenerateArg(Args, OPT_fopenmp_target_debug_EQ, + Twine(Opts.OpenMPTargetDebug), SA); + if (Opts.OpenMPCUDANumSMs != 0) GenerateArg(Args, OPT_fopenmp_cuda_number_of_sm_EQ, Twine(Opts.OpenMPCUDANumSMs), SA); @@ -3528,6 +3578,9 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Args, OPT_fexperimental_relative_cxx_abi_vtables, SA); else GenerateArg(Args, OPT_fno_experimental_relative_cxx_abi_vtables, SA); + + for (const auto &MP : Opts.MacroPrefixMap) + GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA); } bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, @@ -3608,7 +3661,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, .Cases("cl1.2", "CL1.2", LangStandard::lang_opencl12) .Cases("cl2.0", "CL2.0", LangStandard::lang_opencl20) .Cases("cl3.0", "CL3.0", LangStandard::lang_opencl30) - .Cases("clc++", "CLC++", LangStandard::lang_openclcpp) + .Cases("clc++", "CLC++", LangStandard::lang_openclcpp10) + .Cases("clc++1.0", "CLC++1.0", LangStandard::lang_openclcpp10) + .Cases("clc++2021", "CLC++2021", LangStandard::lang_openclcpp2021) .Default(LangStandard::lang_unspecified); if (OpenCLLangStd == LangStandard::lang_unspecified) { @@ -3737,8 +3792,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // '-mignore-xcoff-visibility' is implied. The generated command line will // contain both '-fvisibility default' and '-mignore-xcoff-visibility' and // subsequent calls to `CreateFromArgs`/`generateCC1CommandLine` will always - // produce the same arguments. - + // produce the same arguments. + if (T.isOSAIX() && (Args.hasArg(OPT_mignore_xcoff_visibility) || !Args.hasArg(OPT_fvisibility))) Opts.IgnoreXCOFFVisibility = 1; @@ -3818,6 +3873,9 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_enable_irbuilder); bool IsTargetSpecified = Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); + Opts.OpenMPTargetNewRuntime = + Opts.OpenMPIsDevice && + Args.hasArg(options::OPT_fopenmp_target_new_runtime); Opts.ConvergentFunctions = Opts.ConvergentFunctions || Opts.OpenMPIsDevice; @@ -3845,6 +3903,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, // handling code for those requiring so. if ((Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN())) || Opts.OpenCLCPlusPlus) { + Opts.Exceptions = 0; Opts.CXXExceptions = 0; } @@ -3860,6 +3919,27 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.OpenMPCUDAReductionBufNum, Diags); } + // Set the value of the debugging flag used in the new offloading device RTL. + // Set either by a specific value or to a default if not specified. + if (Opts.OpenMPIsDevice && (Args.hasArg(OPT_fopenmp_target_debug) || + Args.hasArg(OPT_fopenmp_target_debug_EQ))) { + if (Opts.OpenMPTargetNewRuntime) { + Opts.OpenMPTargetDebug = getLastArgIntValue( + Args, OPT_fopenmp_target_debug_EQ, Opts.OpenMPTargetDebug, Diags); + if (!Opts.OpenMPTargetDebug && Args.hasArg(OPT_fopenmp_target_debug)) + Opts.OpenMPTargetDebug = 1; + } else { + Diags.Report(diag::err_drv_debug_no_new_runtime); + } + } + + if (Opts.OpenMPIsDevice && Opts.OpenMPTargetNewRuntime) { + if (Args.hasArg(OPT_fopenmp_assume_teams_oversubscription)) + Opts.OpenMPTeamSubscription = true; + if (Args.hasArg(OPT_fopenmp_assume_threads_oversubscription)) + Opts.OpenMPThreadSubscription = true; + } + // Get the OpenMP target triples if any. if (Arg *A = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) { enum ArchPtrSize { Arch16Bit, Arch32Bit, Arch64Bit }; @@ -4037,6 +4117,12 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, options::OPT_fno_experimental_relative_cxx_abi_vtables, TargetCXXABI::usesRelativeVTables(T)); + for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) { + auto Split = StringRef(A).split('='); + Opts.MacroPrefixMap.insert( + {std::string(Split.first), std::string(Split.second)}); + } + return Diags.getNumErrors() == NumErrorsBefore; } @@ -4109,9 +4195,6 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts, for (const auto &D : Opts.DeserializedPCHDeclsToErrorOn) GenerateArg(Args, OPT_error_on_deserialized_pch_decl, D, SA); - for (const auto &MP : Opts.MacroPrefixMap) - GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA); - if (Opts.PrecompiledPreambleBytes != std::make_pair(0u, false)) GenerateArg(Args, OPT_preamble_bytes_EQ, Twine(Opts.PrecompiledPreambleBytes.first) + "," + @@ -4180,12 +4263,6 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); - for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) { - auto Split = StringRef(A).split('='); - Opts.MacroPrefixMap.insert( - {std::string(Split.first), std::string(Split.second)}); - } - if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { StringRef Value(A->getValue()); size_t Comma = Value.find(','); @@ -4460,116 +4537,99 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Invocation, } std::string CompilerInvocation::getModuleHash() const { + // FIXME: Consider using SHA1 instead of MD5. + llvm::HashBuilder HBuilder; + // Note: For QoI reasons, the things we use as a hash here should all be // dumped via the -module-info flag. - using llvm::hash_code; - using llvm::hash_value; - using llvm::hash_combine; - using llvm::hash_combine_range; // Start the signature with the compiler version. - // FIXME: We'd rather use something more cryptographically sound than - // CityHash, but this will do for now. - hash_code code = hash_value(getClangFullRepositoryVersion()); + HBuilder.add(getClangFullRepositoryVersion()); // Also include the serialization version, in case LLVM_APPEND_VC_REV is off // and getClangFullRepositoryVersion() doesn't include git revision. - code = hash_combine(code, serialization::VERSION_MAJOR, - serialization::VERSION_MINOR); + HBuilder.add(serialization::VERSION_MAJOR, serialization::VERSION_MINOR); // Extend the signature with the language options -#define LANGOPT(Name, Bits, Default, Description) \ - code = hash_combine(code, LangOpts->Name); -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - code = hash_combine(code, static_cast(LangOpts->get##Name())); +#define LANGOPT(Name, Bits, Default, Description) HBuilder.add(LangOpts->Name); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + HBuilder.add(static_cast(LangOpts->get##Name())); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - for (StringRef Feature : LangOpts->ModuleFeatures) - code = hash_combine(code, Feature); + HBuilder.addRange(LangOpts->ModuleFeatures); - code = hash_combine(code, LangOpts->ObjCRuntime); - const auto &BCN = LangOpts->CommentOpts.BlockCommandNames; - code = hash_combine(code, hash_combine_range(BCN.begin(), BCN.end())); + HBuilder.add(LangOpts->ObjCRuntime); + HBuilder.addRange(LangOpts->CommentOpts.BlockCommandNames); // Extend the signature with the target options. - code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, - TargetOpts->TuneCPU, TargetOpts->ABI); - for (const auto &FeatureAsWritten : TargetOpts->FeaturesAsWritten) - code = hash_combine(code, FeatureAsWritten); + HBuilder.add(TargetOpts->Triple, TargetOpts->CPU, TargetOpts->TuneCPU, + TargetOpts->ABI); + HBuilder.addRange(TargetOpts->FeaturesAsWritten); // Extend the signature with preprocessor options. const PreprocessorOptions &ppOpts = getPreprocessorOpts(); - const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); - code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); + HBuilder.add(ppOpts.UsePredefines, ppOpts.DetailedRecord); - for (const auto &I : getPreprocessorOpts().Macros) { + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); + for (const auto &Macro : getPreprocessorOpts().Macros) { // If we're supposed to ignore this macro for the purposes of modules, // don't put it into the hash. if (!hsOpts.ModulesIgnoreMacros.empty()) { // Check whether we're ignoring this macro. - StringRef MacroDef = I.first; + StringRef MacroDef = Macro.first; if (hsOpts.ModulesIgnoreMacros.count( llvm::CachedHashString(MacroDef.split('=').first))) continue; } - code = hash_combine(code, I.first, I.second); + HBuilder.add(Macro); } // Extend the signature with the sysroot and other header search options. - code = hash_combine(code, hsOpts.Sysroot, - hsOpts.ModuleFormat, - hsOpts.UseDebugInfo, - hsOpts.UseBuiltinIncludes, - hsOpts.UseStandardSystemIncludes, - hsOpts.UseStandardCXXIncludes, - hsOpts.UseLibcxx, - hsOpts.ModulesValidateDiagnosticOptions); - code = hash_combine(code, hsOpts.ResourceDir); + HBuilder.add(hsOpts.Sysroot, hsOpts.ModuleFormat, hsOpts.UseDebugInfo, + hsOpts.UseBuiltinIncludes, hsOpts.UseStandardSystemIncludes, + hsOpts.UseStandardCXXIncludes, hsOpts.UseLibcxx, + hsOpts.ModulesValidateDiagnosticOptions); + HBuilder.add(hsOpts.ResourceDir); if (hsOpts.ModulesStrictContextHash) { - hash_code SHPC = hash_combine_range(hsOpts.SystemHeaderPrefixes.begin(), - hsOpts.SystemHeaderPrefixes.end()); - hash_code UEC = hash_combine_range(hsOpts.UserEntries.begin(), - hsOpts.UserEntries.end()); - code = hash_combine(code, hsOpts.SystemHeaderPrefixes.size(), SHPC, - hsOpts.UserEntries.size(), UEC); + HBuilder.addRange(hsOpts.SystemHeaderPrefixes); + HBuilder.addRange(hsOpts.UserEntries); const DiagnosticOptions &diagOpts = getDiagnosticOpts(); - #define DIAGOPT(Name, Bits, Default) \ - code = hash_combine(code, diagOpts.Name); - #define ENUM_DIAGOPT(Name, Type, Bits, Default) \ - code = hash_combine(code, diagOpts.get##Name()); - #include "clang/Basic/DiagnosticOptions.def" - #undef DIAGOPT - #undef ENUM_DIAGOPT +#define DIAGOPT(Name, Bits, Default) HBuilder.add(diagOpts.Name); +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + HBuilder.add(diagOpts.get##Name()); +#include "clang/Basic/DiagnosticOptions.def" +#undef DIAGOPT +#undef ENUM_DIAGOPT } // Extend the signature with the user build path. - code = hash_combine(code, hsOpts.ModuleUserBuildPath); + HBuilder.add(hsOpts.ModuleUserBuildPath); // Extend the signature with the module file extensions. - const FrontendOptions &frontendOpts = getFrontendOpts(); - for (const auto &ext : frontendOpts.ModuleFileExtensions) { - code = ext->hashExtension(code); - } + for (const auto &ext : getFrontendOpts().ModuleFileExtensions) + ext->hashExtension(HBuilder); // When compiling with -gmodules, also hash -fdebug-prefix-map as it // affects the debug info in the PCM. if (getCodeGenOpts().DebugTypeExtRefs) - for (const auto &KeyValue : getCodeGenOpts().DebugPrefixMap) - code = hash_combine(code, KeyValue.first, KeyValue.second); + HBuilder.addRange(getCodeGenOpts().DebugPrefixMap); // Extend the signature with the enabled sanitizers, if at least one is // enabled. Sanitizers which cannot affect AST generation aren't hashed. SanitizerSet SanHash = LangOpts->Sanitize; SanHash.clear(getPPTransparentSanitizers()); if (!SanHash.empty()) - code = hash_combine(code, SanHash.Mask); + HBuilder.add(SanHash.Mask); - return toString(llvm::APInt(64, code), 36, /*Signed=*/false); + llvm::MD5::MD5Result Result; + HBuilder.getHasher().final(Result); + uint64_t Hash = Result.high() ^ Result.low(); + return toString(llvm::APInt(64, Hash), 36, /*Signed=*/false); } void CompilerInvocation::generateCC1CommandLine( diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 2e23ebfdf16..c5627d13a7a 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -30,6 +30,7 @@ std::unique_ptr clang::createInvocationFromCommandLine( ArrayRef ArgList, IntrusiveRefCntPtr Diags, IntrusiveRefCntPtr VFS, bool ShouldRecoverOnErorrs, std::vector *CC1Args) { + assert(!ArgList.empty()); if (!Diags.get()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -79,22 +80,24 @@ std::unique_ptr clang::createInvocationFromCommandLine( } } } - if (Jobs.size() == 0 || !isa(*Jobs.begin()) || - (Jobs.size() > 1 && !OffloadCompilation)) { + + bool PickFirstOfMany = OffloadCompilation || ShouldRecoverOnErorrs; + if (Jobs.size() == 0 || (Jobs.size() > 1 && !PickFirstOfMany)) { SmallString<256> Msg; llvm::raw_svector_ostream OS(Msg); Jobs.Print(OS, "; ", true); Diags->Report(diag::err_fe_expected_compiler_job) << OS.str(); return nullptr; } - - const driver::Command &Cmd = cast(*Jobs.begin()); - if (StringRef(Cmd.getCreator().getName()) != "clang") { + auto Cmd = llvm::find_if(Jobs, [](const driver::Command &Cmd) { + return StringRef(Cmd.getCreator().getName()) == "clang"; + }); + if (Cmd == Jobs.end()) { Diags->Report(diag::err_fe_expected_clang_command); return nullptr; } - const ArgStringList &CCArgs = Cmd.getArguments(); + const ArgStringList &CCArgs = Cmd->getArguments(); if (CC1Args) *CC1Args = {CCArgs.begin(), CCArgs.end()}; auto CI = std::make_unique(); diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index c996c9c486b..089f40b3608 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -27,6 +27,7 @@ #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/GlobalModuleIndex.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/BuryPointer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" @@ -143,7 +144,7 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput, Module *FrontendAction::getCurrentModule() const { CompilerInstance &CI = getCompilerInstance(); return CI.getPreprocessor().getHeaderSearchInfo().lookupModule( - CI.getLangOpts().CurrentModule, /*AllowSearch*/false); + CI.getLangOpts().CurrentModule, SourceLocation(), /*AllowSearch*/false); } std::unique_ptr @@ -186,14 +187,19 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, FrontendPluginRegistry::entries()) { std::unique_ptr P = Plugin.instantiate(); PluginASTAction::ActionType ActionType = P->getActionType(); - if (ActionType == PluginASTAction::Cmdline) { + if (ActionType == PluginASTAction::CmdlineAfterMainAction || + ActionType == PluginASTAction::CmdlineBeforeMainAction) { // This is O(|plugins| * |add_plugins|), but since both numbers are // way below 50 in practice, that's ok. if (llvm::any_of(CI.getFrontendOpts().AddPluginActions, [&](const std::string &PluginAction) { return PluginAction == Plugin.getName(); - })) - ActionType = PluginASTAction::AddAfterMainAction; + })) { + if (ActionType == PluginASTAction::CmdlineBeforeMainAction) + ActionType = PluginASTAction::AddBeforeMainAction; + else + ActionType = PluginASTAction::AddAfterMainAction; + } } if ((ActionType == PluginASTAction::AddBeforeMainAction || ActionType == PluginASTAction::AddAfterMainAction) && @@ -211,8 +217,13 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, // Add to Consumers the main consumer, then all the plugins that go after it Consumers.push_back(std::move(Consumer)); - for (auto &C : AfterConsumers) { - Consumers.push_back(std::move(C)); + if (!AfterConsumers.empty()) { + // If we have plugins after the main consumer, which may be the codegen + // action, they likely will need the ASTContext, so don't clear it in the + // codegen action. + CI.getCodeGenOpts().ClearASTBeforeBackend = false; + for (auto &C : AfterConsumers) + Consumers.push_back(std::move(C)); } return std::make_unique(std::move(Consumers)); @@ -471,7 +482,7 @@ static Module *prepareToBuildModule(CompilerInstance &CI, // Dig out the module definition. HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo(); - Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, + Module *M = HS.lookupModule(CI.getLangOpts().CurrentModule, SourceLocation(), /*AllowSearch=*/true); if (!M) { CI.getDiagnostics().Report(diag::err_missing_module) @@ -558,8 +569,20 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, bool HasBegunSourceFile = false; bool ReplayASTFile = Input.getKind().getFormat() == InputKind::Precompiled && usesPreprocessorOnly(); + + // If we fail, reset state since the client will not end up calling the + // matching EndSourceFile(). All paths that return true should release this. + auto FailureCleanup = llvm::make_scope_exit([&]() { + if (HasBegunSourceFile) + CI.getDiagnosticClient().EndSourceFile(); + CI.clearOutputFiles(/*EraseFiles=*/true); + CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); + setCurrentInput(FrontendInputFile()); + setCompilerInstance(nullptr); + }); + if (!BeginInvocation(CI)) - goto failure; + return false; // If we're replaying the build of an AST file, import it and set up // the initial state from its build. @@ -580,7 +603,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, ASTUnit::LoadPreprocessorOnly, ASTDiags, CI.getFileSystemOpts(), CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) - goto failure; + return false; // Options relating to how we treat the input (but not what we do with it) // are inherited from the AST unit. @@ -617,7 +640,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (Kind.getFormat() == InputKind::ModuleMap) { Module *ASTModule = AST->getPreprocessor().getHeaderSearchInfo().lookupModule( - AST->getLangOpts().CurrentModule, /*AllowSearch*/ false); + AST->getLangOpts().CurrentModule, SourceLocation(), + /*AllowSearch*/ false); assert(ASTModule && "module file does not define its own module"); Input = FrontendInputFile(ASTModule->PresumedModuleMapFile, Kind); } else { @@ -649,7 +673,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getCodeGenOpts().DebugTypeExtRefs); if (!AST) - goto failure; + return false; // Inform the diagnostic client we are processing a source file. CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr); @@ -669,20 +693,21 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize the action. if (!BeginSourceFileAction(CI)) - goto failure; + return false; // Create the AST consumer. CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile)); if (!CI.hasASTConsumer()) - goto failure; + return false; + FailureCleanup.release(); return true; } // Set up the file and source managers, if needed. if (!CI.hasFileManager()) { if (!CI.createFileManager()) { - goto failure; + return false; } } if (!CI.hasSourceManager()) @@ -710,12 +735,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize the action. if (!BeginSourceFileAction(CI)) - goto failure; + return false; // Initialize the main file entry. if (!CI.InitializeSourceManager(CurrentInput)) - goto failure; + return false; + FailureCleanup.release(); return true; } @@ -748,7 +774,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (!Found) { CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude; - goto failure; + return false; } } } @@ -765,7 +791,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize the main file entry. if (!CI.InitializeSourceManager(Input)) - goto failure; + return false; // For module map files, we first parse the module map and synthesize a // "" buffer before more conventional processing. @@ -777,11 +803,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (loadModuleMapForModuleBuild(CI, Input.isSystem(), Input.isPreprocessed(), PresumedModuleMapFile, OffsetToContents)) - goto failure; + return false; auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); if (!CurrentModule) - goto failure; + return false; CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile; @@ -792,7 +818,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Otherwise, convert the module description to a suitable input buffer. auto Buffer = getInputBufferForModule(CI, CurrentModule); if (!Buffer) - goto failure; + return false; // Reinitialize the main file entry to refer to the new input. auto Kind = CurrentModule->IsSystem ? SrcMgr::C_System : SrcMgr::C_User; @@ -805,7 +831,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // Initialize the action. if (!BeginSourceFileAction(CI)) - goto failure; + return false; // If we were asked to load any module map files, do so now. for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) { @@ -839,7 +865,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, std::unique_ptr Consumer = CreateWrappedASTConsumer(CI, PresumedInputFile); if (!Consumer) - goto failure; + return false; // FIXME: should not overwrite ASTMutationListener when parsing model files? if (!isModelParsingAction()) @@ -850,7 +876,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, IntrusiveRefCntPtr source, FinalReader; source = createChainedIncludesSource(CI, FinalReader); if (!source) - goto failure; + return false; CI.setASTReader(static_cast(FinalReader.get())); CI.getASTContext().setExternalSource(source); } else if (CI.getLangOpts().Modules || @@ -879,7 +905,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener, DeleteDeserialListener); if (!CI.getASTContext().getExternalSource()) - goto failure; + return false; } // If modules are enabled, create the AST reader before creating // any builtins, so that all declarations know that they might be @@ -894,7 +920,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setASTConsumer(std::move(Consumer)); if (!CI.hasASTConsumer()) - goto failure; + return false; } // Initialize built-in info as long as we aren't using an external AST @@ -915,7 +941,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // If we were asked to load any module files, do so now. for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles) if (!CI.loadModuleFile(ModuleFile)) - goto failure; + return false; // If there is a layout overrides file, attach an external AST source that // provides the layouts from that file. @@ -927,18 +953,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.getASTContext().setExternalSource(Override); } + FailureCleanup.release(); return true; - - // If we failed, reset state since the client will not end up calling the - // matching EndSourceFile(). -failure: - if (HasBegunSourceFile) - CI.getDiagnosticClient().EndSourceFile(); - CI.clearOutputFiles(/*EraseFiles=*/true); - CI.getLangOpts().setCompilingModule(LangOptions::CMK_None); - setCurrentInput(FrontendInputFile()); - setCompilerInstance(nullptr); - return false; } llvm::Error FrontendAction::Execute() { diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index c6ebbdc8c04..b5544afa9f2 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -993,3 +993,17 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { } llvm::outs() << Output; } + +void GetDependenciesByModuleNameAction::ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + Preprocessor &PP = CI.getPreprocessor(); + SourceManager &SM = PP.getSourceManager(); + FileID MainFileID = SM.getMainFileID(); + SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); + SmallVector, 2> Path; + IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); + Path.push_back(std::make_pair(ModuleID, FileStart)); + auto ModResult = CI.loadModule(FileStart, Path, Module::Hidden, false); + PPCallbacks *CB = PP.getPPCallbacks(); + CB->moduleImport(SourceLocation(), Path, ModResult); +} diff --git a/clang/lib/Frontend/HeaderIncludeGen.cpp b/clang/lib/Frontend/HeaderIncludeGen.cpp index 1ee47d8d248..5db8792bf42 100644 --- a/clang/lib/Frontend/HeaderIncludeGen.cpp +++ b/clang/lib/Frontend/HeaderIncludeGen.cpp @@ -119,7 +119,7 @@ void clang::AttachHeaderIncludeGen(Preprocessor &PP, // Print header info for extra headers, pretending they were discovered by // the regular preprocessor. The primary use case is to support proper // generation of Make / Ninja file dependencies for implicit includes, such - // as sanitizer blacklists. It's only important for cl.exe compatibility, + // as sanitizer ignorelists. It's only important for cl.exe compatibility, // the GNU way to generate rules is -M / -MM / -MD / -MMD. for (const auto &Header : DepOpts.ExtraDeps) PrintHeaderInfo(OutputFile, Header.first, ShowDepth, 2, MSStyle); diff --git a/clang/lib/Frontend/InitHeaderSearch.cpp b/clang/lib/Frontend/InitHeaderSearch.cpp index ba9f96384f8..ed1314f3b03 100644 --- a/clang/lib/Frontend/InitHeaderSearch.cpp +++ b/clang/lib/Frontend/InitHeaderSearch.cpp @@ -36,9 +36,11 @@ namespace { struct DirectoryLookupInfo { IncludeDirGroup Group; DirectoryLookup Lookup; + Optional UserEntryIdx; - DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup) - : Group(Group), Lookup(Lookup) {} + DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup, + Optional UserEntryIdx) + : Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {} }; /// InitHeaderSearch - This class makes it easier to set the search paths of @@ -60,13 +62,15 @@ public: /// AddPath - Add the specified path to the specified group list, prefixing /// the sysroot if used. /// Returns true if the path exists, false if it was ignored. - bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework); + bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework, + Optional UserEntryIdx = None); /// AddUnmappedPath - Add the specified path to the specified group list, /// without performing any sysroot remapping. /// Returns true if the path exists, false if it was ignored. bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, - bool isFramework); + bool isFramework, + Optional UserEntryIdx = None); /// AddSystemHeaderPrefix - Add the specified prefix to the system header /// prefix list. @@ -119,22 +123,25 @@ static bool CanPrefixSysroot(StringRef Path) { } bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, - bool isFramework) { + bool isFramework, + Optional UserEntryIdx) { // Add the path with sysroot prepended, if desired and this is a system header // group. if (HasSysroot) { SmallString<256> MappedPathStorage; StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); if (CanPrefixSysroot(MappedPathStr)) { - return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework); + return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework, + UserEntryIdx); } } - return AddUnmappedPath(Path, Group, isFramework); + return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx); } bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, - bool isFramework) { + bool isFramework, + Optional UserEntryIdx) { assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); FileManager &FM = Headers.getFileMgr(); @@ -160,7 +167,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, // If the directory exists, add it. if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) { - IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework)); + IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework), + UserEntryIdx); return true; } @@ -171,7 +179,8 @@ bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) { // It is a headermap, add it to the search path. IncludePath.emplace_back( - Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap)); + Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap), + UserEntryIdx); return true; } } @@ -471,7 +480,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang, /// RemoveDuplicates - If there are duplicate directory entries in the specified /// search list, remove the later (dead) ones. Returns the number of non-system /// headers removed, which is used to update NumAngled. -static unsigned RemoveDuplicates(std::vector &SearchList, +static unsigned RemoveDuplicates(std::vector &SearchList, unsigned First, bool Verbose) { llvm::SmallPtrSet SeenDirs; llvm::SmallPtrSet SeenFrameworkDirs; @@ -480,7 +489,7 @@ static unsigned RemoveDuplicates(std::vector &SearchList, for (unsigned i = First; i != SearchList.size(); ++i) { unsigned DirToRemove = i; - const DirectoryLookup &CurEntry = SearchList[i]; + const DirectoryLookup &CurEntry = SearchList[i].Lookup; if (CurEntry.isNormalDir()) { // If this isn't the first time we've seen this dir, remove it. @@ -510,7 +519,7 @@ static unsigned RemoveDuplicates(std::vector &SearchList, for (FirstDir = First;; ++FirstDir) { assert(FirstDir != i && "Didn't find dupe?"); - const DirectoryLookup &SearchEntry = SearchList[FirstDir]; + const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup; // If these are different lookup types, then they can't be the dupe. if (SearchEntry.getLookupType() != CurEntry.getLookupType()) @@ -532,7 +541,7 @@ static unsigned RemoveDuplicates(std::vector &SearchList, // If the first dir in the search path is a non-system dir, zap it // instead of the system one. - if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User) + if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User) DirToRemove = FirstDir; } @@ -554,16 +563,37 @@ static unsigned RemoveDuplicates(std::vector &SearchList, return NonSystemRemoved; } +/// Extract DirectoryLookups from DirectoryLookupInfos. +static std::vector +extractLookups(const std::vector &Infos) { + std::vector Lookups; + Lookups.reserve(Infos.size()); + llvm::transform(Infos, std::back_inserter(Lookups), + [](const DirectoryLookupInfo &Info) { return Info.Lookup; }); + return Lookups; +} + +/// Collect the mapping between indices of DirectoryLookups and UserEntries. +static llvm::DenseMap +mapToUserEntries(const std::vector &Infos) { + llvm::DenseMap LookupsToUserEntries; + for (unsigned I = 0, E = Infos.size(); I < E; ++I) { + // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry. + if (Infos[I].UserEntryIdx) + LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx}); + } + return LookupsToUserEntries; +} void InitHeaderSearch::Realize(const LangOptions &Lang) { // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList. - std::vector SearchList; + std::vector SearchList; SearchList.reserve(IncludePath.size()); // Quoted arguments go first. for (auto &Include : IncludePath) if (Include.Group == Quoted) - SearchList.push_back(Include.Lookup); + SearchList.push_back(Include); // Deduplicate and remember index. RemoveDuplicates(SearchList, 0, Verbose); @@ -571,7 +601,7 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (auto &Include : IncludePath) if (Include.Group == Angled || Include.Group == IndexHeaderMap) - SearchList.push_back(Include.Lookup); + SearchList.push_back(Include); RemoveDuplicates(SearchList, NumQuoted, Verbose); unsigned NumAngled = SearchList.size(); @@ -583,11 +613,11 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { Include.Group == CXXSystem) || (Lang.ObjC && !Lang.CPlusPlus && Include.Group == ObjCSystem) || (Lang.ObjC && Lang.CPlusPlus && Include.Group == ObjCXXSystem)) - SearchList.push_back(Include.Lookup); + SearchList.push_back(Include); for (auto &Include : IncludePath) if (Include.Group == After) - SearchList.push_back(Include.Lookup); + SearchList.push_back(Include); // Remove duplicates across both the Angled and System directories. GCC does // this and failing to remove duplicates across these two groups breaks @@ -596,7 +626,8 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { NumAngled -= NonSystemRemoved; bool DontSearchCurDir = false; // TODO: set to true if -I- is set? - Headers.SetSearchPaths(SearchList, NumQuoted, NumAngled, DontSearchCurDir); + Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled, + DontSearchCurDir, mapToUserEntries(SearchList)); Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes); @@ -606,14 +637,14 @@ void InitHeaderSearch::Realize(const LangOptions &Lang) { for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { if (i == NumQuoted) llvm::errs() << "#include <...> search starts here:\n"; - StringRef Name = SearchList[i].getName(); + StringRef Name = SearchList[i].Lookup.getName(); const char *Suffix; - if (SearchList[i].isNormalDir()) + if (SearchList[i].Lookup.isNormalDir()) Suffix = ""; - else if (SearchList[i].isFramework()) + else if (SearchList[i].Lookup.isFramework()) Suffix = " (framework directory)"; else { - assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup"); + assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup"); Suffix = " (headermap)"; } llvm::errs() << " " << Name << Suffix << "\n"; @@ -632,9 +663,9 @@ void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; if (E.IgnoreSysRoot) { - Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework); + Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework, i); } else { - Init.AddPath(E.Path, E.Group, E.IsFramework); + Init.AddPath(E.Path, E.Group, E.IsFramework, i); } } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index bca0bb4ada6..0ecb024fc6b 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -371,7 +371,10 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // value is, are implementation-defined. // (Removed in C++20.) if (!LangOpts.CPlusPlus) { - if (LangOpts.C17) + // FIXME: Use correct value for C23. + if (LangOpts.C2x) + Builder.defineMacro("__STDC_VERSION__", "202000L"); + else if (LangOpts.C17) Builder.defineMacro("__STDC_VERSION__", "201710L"); else if (LangOpts.C11) Builder.defineMacro("__STDC_VERSION__", "201112L"); @@ -433,11 +436,18 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, // OpenCL v1.0/1.1 s6.9, v1.2/2.0 s6.10: Preprocessor Directives and Macros. if (LangOpts.OpenCL) { if (LangOpts.CPlusPlus) { - if (LangOpts.OpenCLCPlusPlusVersion == 100) + switch (LangOpts.OpenCLCPlusPlusVersion) { + case 100: Builder.defineMacro("__OPENCL_CPP_VERSION__", "100"); - else + break; + case 202100: + Builder.defineMacro("__OPENCL_CPP_VERSION__", "202100"); + break; + default: llvm_unreachable("Unsupported C++ version for OpenCL"); + } Builder.defineMacro("__CL_CPP_VERSION_1_0__", "100"); + Builder.defineMacro("__CL_CPP_VERSION_2021__", "202100"); } else { // OpenCL v1.0 and v1.1 do not have a predefined macro to indicate the // language standard with which the program is compiled. __OPENCL_VERSION__ @@ -590,7 +600,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, //Builder.defineMacro("__cpp_consteval", "201811L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); Builder.defineMacro("__cpp_constinit", "201907L"); - //Builder.defineMacro("__cpp_coroutines", "201902L"); + Builder.defineMacro("__cpp_impl_coroutine", "201902L"); Builder.defineMacro("__cpp_designated_initializers", "201707L"); Builder.defineMacro("__cpp_impl_three_way_comparison", "201907L"); //Builder.defineMacro("__cpp_modules", "201907L"); @@ -600,6 +610,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.CPlusPlus2b) { Builder.defineMacro("__cpp_implicit_move", "202011L"); Builder.defineMacro("__cpp_size_t_suffix", "202011L"); + Builder.defineMacro("__cpp_if_consteval", "202106L"); } if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "201811L"); @@ -1141,6 +1152,12 @@ static void InitializePredefinedMacros(const TargetInfo &TI, case 45: Builder.defineMacro("_OPENMP", "201511"); break; + case 51: + Builder.defineMacro("_OPENMP", "202011"); + break; + case 52: + Builder.defineMacro("_OPENMP", "202111"); + break; default: // Default version is OpenMP 5.0 Builder.defineMacro("_OPENMP", "201811"); @@ -1171,7 +1188,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (LangOpts.OpenCL) { InitializeOpenCLFeatureTestMacros(TI, LangOpts, Builder); - if (TI.getTriple().isSPIR()) + if (TI.getTriple().isSPIR() || TI.getTriple().isSPIRV()) Builder.defineMacro("__IMAGE_SUPPORT__"); } diff --git a/clang/lib/Frontend/LayoutOverrideSource.cpp b/clang/lib/Frontend/LayoutOverrideSource.cpp index 76762d58fe2..0d288db0632 100644 --- a/clang/lib/Frontend/LayoutOverrideSource.cpp +++ b/clang/lib/Frontend/LayoutOverrideSource.cpp @@ -16,11 +16,11 @@ using namespace clang; /// Parse a simple identifier. static std::string parseName(StringRef S) { - if (S.empty() || !isIdentifierHead(S[0])) + if (S.empty() || !isAsciiIdentifierStart(S[0])) return ""; unsigned Offset = 1; - while (Offset < S.size() && isIdentifierBody(S[Offset])) + while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset])) ++Offset; return S.substr(0, Offset).str(); @@ -43,7 +43,7 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) { StringRef LineStr(Line); // Determine whether the following line will start a - if (LineStr.find("*** Dumping AST Record Layout") != StringRef::npos) { + if (LineStr.contains("*** Dumping AST Record Layout")) { // Flush the last type/layout, if there is one. if (!CurrentType.empty()) Layouts[CurrentType] = CurrentLayout; diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index b7259569595..45df86ef91c 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -155,7 +155,7 @@ public: void PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) override; void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, diag::Severity Map, StringRef Str) override; - void PragmaWarning(SourceLocation Loc, StringRef WarningSpec, + void PragmaWarning(SourceLocation Loc, PragmaWarningSpecifier WarningSpec, ArrayRef Ids) override; void PragmaWarningPush(SourceLocation Loc, int Level) override; void PragmaWarningPop(SourceLocation Loc) override; @@ -182,25 +182,23 @@ public: /// implicitly when at the beginning of the file. /// /// @param Tok Token where to move to. - /// @param RequiresStartOfLine Whether the next line depends on being in the + /// @param RequireStartOfLine Whether the next line depends on being in the /// first column, such as a directive. /// /// @return Whether column adjustments are necessary. bool MoveToLine(const Token &Tok, bool RequireStartOfLine) { PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation()); - if (PLoc.isInvalid()) - return false; + unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine; bool IsFirstInFile = Tok.isAtStartOfLine() && PLoc.getLine() == 1; - return MoveToLine(PLoc.getLine(), RequireStartOfLine) || IsFirstInFile; + return MoveToLine(TargetLine, RequireStartOfLine) || IsFirstInFile; } /// Move to the line of the provided source location. Returns true if a new /// line was inserted. bool MoveToLine(SourceLocation Loc, bool RequireStartOfLine) { PresumedLoc PLoc = SM.getPresumedLoc(Loc); - if (PLoc.isInvalid()) - return false; - return MoveToLine(PLoc.getLine(), RequireStartOfLine); + unsigned TargetLine = PLoc.isValid() ? PLoc.getLine() : CurLine; + return MoveToLine(TargetLine, RequireStartOfLine); } bool MoveToLine(unsigned LineNo, bool RequireStartOfLine); @@ -276,20 +274,27 @@ bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo, // otherwise print a #line directive. if (CurLine == LineNo) { // Nothing to do if we are already on the correct line. - } else if (!StartedNewLine && (!MinimizeWhitespace || !DisableLineMarkers) && - LineNo - CurLine == 1) { + } else if (MinimizeWhitespace && DisableLineMarkers) { + // With -E -P -fminimize-whitespace, don't emit anything if not necessary. + } else if (!StartedNewLine && LineNo - CurLine == 1) { // Printing a single line has priority over printing a #line directive, even // when minimizing whitespace which otherwise would print #line directives // for every single line. OS << '\n'; StartedNewLine = true; - } else if (!MinimizeWhitespace && LineNo - CurLine <= 8) { - const char *NewLines = "\n\n\n\n\n\n\n\n"; - OS.write(NewLines, LineNo - CurLine); - StartedNewLine = true; } else if (!DisableLineMarkers) { - // Emit a #line or line marker. - WriteLineInfo(LineNo, nullptr, 0); + if (LineNo - CurLine <= 8) { + const char *NewLines = "\n\n\n\n\n\n\n\n"; + OS.write(NewLines, LineNo - CurLine); + } else { + // Emit a #line or line marker. + WriteLineInfo(LineNo, nullptr, 0); + } + StartedNewLine = true; + } else if (EmittedTokensOnThisLine) { + // If we are not on the correct line and don't need to be line-correct, + // at least ensure we start on a new line. + OS << '\n'; StartedNewLine = true; } @@ -573,10 +578,24 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc, } void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc, - StringRef WarningSpec, + PragmaWarningSpecifier WarningSpec, ArrayRef Ids) { MoveToLine(Loc, /*RequireStartOfLine=*/true); - OS << "#pragma warning(" << WarningSpec << ':'; + + OS << "#pragma warning("; + switch(WarningSpec) { + case PWS_Default: OS << "default"; break; + case PWS_Disable: OS << "disable"; break; + case PWS_Error: OS << "error"; break; + case PWS_Once: OS << "once"; break; + case PWS_Suppress: OS << "suppress"; break; + case PWS_Level1: OS << '1'; break; + case PWS_Level2: OS << '2'; break; + case PWS_Level3: OS << '3'; break; + case PWS_Level4: OS << '4'; break; + } + OS << ':'; + for (ArrayRef::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I) OS << ' ' << *I; OS << ')'; @@ -639,7 +658,9 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, !Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end))) return; - if (!RequireSameLine && MoveToLine(Tok, /*RequireStartOfLine=*/false)) { + // EmittedDirectiveOnThisLine takes priority over RequireSameLine. + if ((!RequireSameLine || EmittedDirectiveOnThisLine) && + MoveToLine(Tok, /*RequireStartOfLine=*/EmittedDirectiveOnThisLine)) { if (MinimizeWhitespace) { // Avoid interpreting hash as a directive under -fpreprocessed. if (Tok.is(tok::hash)) @@ -677,7 +698,7 @@ void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, // - The whitespace is necessary to keep the tokens apart and there is not // already a newline between them if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) || - ((EmittedTokensOnThisLine || EmittedTokensOnThisLine) && + ((EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) && AvoidConcat(PrevPrevTok, PrevTok, Tok))) OS << ' '; } diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 09ed07be923..6685109f8d3 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -231,7 +231,7 @@ public: assert(OS && "loaded module file after finishing rewrite action?"); (*OS) << "#pragma clang module build "; - if (isValidIdentifier(MF->ModuleName)) + if (isValidAsciiIdentifier(MF->ModuleName)) (*OS) << MF->ModuleName; else { (*OS) << '"'; diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index fd54bcbf7c3..626ec4d71cc 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -1957,15 +1957,15 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { // @try -> try ReplaceText(startLoc, 1, ""); - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *Catch = S->getCatchStmt(I); + for (ObjCAtCatchStmt *Catch : S->catch_stmts()) { VarDecl *catchDecl = Catch->getCatchParamDecl(); startLoc = Catch->getBeginLoc(); bool AtRemoved = false; if (catchDecl) { QualType t = catchDecl->getType(); - if (const ObjCObjectPointerType *Ptr = t->getAs()) { + if (const ObjCObjectPointerType *Ptr = + t->getAs()) { // Should be a pointer to a class. ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); if (IDecl) { diff --git a/clang/lib/Frontend/TestModuleFileExtension.cpp b/clang/lib/Frontend/TestModuleFileExtension.cpp index 7d4026a7efc..ea737e6891b 100644 --- a/clang/lib/Frontend/TestModuleFileExtension.cpp +++ b/clang/lib/Frontend/TestModuleFileExtension.cpp @@ -93,16 +93,14 @@ TestModuleFileExtension::getExtensionMetadata() const { return { BlockName, MajorVersion, MinorVersion, UserInfo }; } -llvm::hash_code TestModuleFileExtension::hashExtension( - llvm::hash_code Code) const { +void TestModuleFileExtension::hashExtension( + ExtensionHashBuilder &HBuilder) const { if (Hashed) { - Code = llvm::hash_combine(Code, BlockName); - Code = llvm::hash_combine(Code, MajorVersion); - Code = llvm::hash_combine(Code, MinorVersion); - Code = llvm::hash_combine(Code, UserInfo); + HBuilder.add(BlockName); + HBuilder.add(MajorVersion); + HBuilder.add(MinorVersion); + HBuilder.add(UserInfo); } - - return Code; } std::unique_ptr diff --git a/clang/lib/Frontend/TestModuleFileExtension.h b/clang/lib/Frontend/TestModuleFileExtension.h index c8ca4cd4f21..e22c87ed2d1 100644 --- a/clang/lib/Frontend/TestModuleFileExtension.h +++ b/clang/lib/Frontend/TestModuleFileExtension.h @@ -55,7 +55,7 @@ public: ModuleFileExtensionMetadata getExtensionMetadata() const override; - llvm::hash_code hashExtension(llvm::hash_code Code) const override; + void hashExtension(ExtensionHashBuilder &HBuilder) const override; std::unique_ptr createExtensionWriter(ASTWriter &Writer) override; diff --git a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp index 0503ae46a15..2759625ae25 100644 --- a/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/clang/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -99,9 +99,7 @@ public: return true; } - bool match(StringRef S) override { - return S.find(Text) != StringRef::npos; - } + bool match(StringRef S) override { return S.contains(Text); } }; /// RegexDirective - Directive with regular-expression matching. diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index b95851e380d..8e18f33af0c 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -79,7 +79,7 @@ CreateFrontendBaseAction(CompilerInstance &CI) { if (Plugin.getName() == CI.getFrontendOpts().ActionName) { std::unique_ptr P(Plugin.instantiate()); if ((P->getActionType() != PluginASTAction::ReplaceAction && - P->getActionType() != PluginASTAction::Cmdline) || + P->getActionType() != PluginASTAction::CmdlineAfterMainAction) || !P->ParseArgs( CI, CI.getFrontendOpts().PluginArgs[std::string(Plugin.getName())])) @@ -203,24 +203,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) { return true; } - // Load any requested plugins. - for (const std::string &Path : Clang->getFrontendOpts().Plugins) { - std::string Error; - if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(), &Error)) - Clang->getDiagnostics().Report(diag::err_fe_unable_to_load_plugin) - << Path << Error; - } - - // Check if any of the loaded plugins replaces the main AST action - for (const FrontendPluginRegistry::entry &Plugin : - FrontendPluginRegistry::entries()) { - std::unique_ptr P(Plugin.instantiate()); - if (P->getActionType() == PluginASTAction::ReplaceAction) { - Clang->getFrontendOpts().ProgramAction = clang::frontend::PluginAction; - Clang->getFrontendOpts().ActionName = Plugin.getName().str(); - break; - } - } + Clang->LoadRequestedPlugins(); // Honor -mllvm. // diff --git a/clang/lib/Headers/__clang_cuda_complex_builtins.h b/clang/lib/Headers/__clang_cuda_complex_builtins.h index 2b701fef0ea..7bc7bc2ce63 100644 --- a/clang/lib/Headers/__clang_cuda_complex_builtins.h +++ b/clang/lib/Headers/__clang_cuda_complex_builtins.h @@ -16,7 +16,7 @@ // to work with CUDA and OpenMP target offloading [in C and C++ mode].) #pragma push_macro("__DEVICE__") -#ifdef __OPENMP_NVPTX__ +#if defined(__OPENMP_NVPTX__) || defined(__OPENMP_AMDGCN__) #pragma omp declare target #define __DEVICE__ __attribute__((noinline, nothrow, cold, weak)) #else @@ -26,7 +26,7 @@ // To make the algorithms available for C and C++ in CUDA and OpenMP we select // different but equivalent function versions. TODO: For OpenMP we currently // select the native builtins as the overload support for templates is lacking. -#if !defined(__OPENMP_NVPTX__) +#if !defined(__OPENMP_NVPTX__) && !defined(__OPENMP_AMDGCN__) #define _ISNANd std::isnan #define _ISNANf std::isnan #define _ISINFd std::isinf @@ -276,7 +276,7 @@ __DEVICE__ float _Complex __divsc3(float __a, float __b, float __c, float __d) { #undef _fmaxd #undef _fmaxf -#ifdef __OPENMP_NVPTX__ +#if defined(__OPENMP_NVPTX__) || defined(__OPENMP_AMDGCN__) #pragma omp end declare target #endif diff --git a/clang/lib/Headers/__clang_cuda_device_functions.h b/clang/lib/Headers/__clang_cuda_device_functions.h index f801e5426aa..cc4e1a4dd96 100644 --- a/clang/lib/Headers/__clang_cuda_device_functions.h +++ b/clang/lib/Headers/__clang_cuda_device_functions.h @@ -34,10 +34,12 @@ __DEVICE__ unsigned long long __brevll(unsigned long long __a) { return __nv_brevll(__a); } #if defined(__cplusplus) -__DEVICE__ void __brkpt() { asm volatile("brkpt;"); } +__DEVICE__ void __brkpt() { __asm__ __volatile__("brkpt;"); } __DEVICE__ void __brkpt(int __a) { __brkpt(); } #else -__DEVICE__ void __attribute__((overloadable)) __brkpt(void) { asm volatile("brkpt;"); } +__DEVICE__ void __attribute__((overloadable)) __brkpt(void) { + __asm__ __volatile__("brkpt;"); +} __DEVICE__ void __attribute__((overloadable)) __brkpt(int __a) { __brkpt(); } #endif __DEVICE__ unsigned int __byte_perm(unsigned int __a, unsigned int __b, @@ -507,7 +509,7 @@ __DEVICE__ float __powf(float __a, float __b) { } // Parameter must have a known integer value. -#define __prof_trigger(__a) asm __volatile__("pmevent \t%0;" ::"i"(__a)) +#define __prof_trigger(__a) __asm__ __volatile__("pmevent \t%0;" ::"i"(__a)) __DEVICE__ int __rhadd(int __a, int __b) { return __nv_rhadd(__a, __b); } __DEVICE__ unsigned int __sad(int __a, int __b, unsigned int __c) { return __nv_sad(__a, __b, __c); @@ -526,7 +528,7 @@ __DEVICE__ float __tanf(float __a) { return __nv_fast_tanf(__a); } __DEVICE__ void __threadfence(void) { __nvvm_membar_gl(); } __DEVICE__ void __threadfence_block(void) { __nvvm_membar_cta(); }; __DEVICE__ void __threadfence_system(void) { __nvvm_membar_sys(); }; -__DEVICE__ void __trap(void) { asm volatile("trap;"); } +__DEVICE__ void __trap(void) { __asm__ __volatile__("trap;"); } __DEVICE__ unsigned int __uAtomicAdd(unsigned int *__p, unsigned int __v) { return __nvvm_atom_add_gen_i((int *)__p, __v); } @@ -1051,122 +1053,136 @@ __DEVICE__ unsigned int __bool2mask(unsigned int __a, int shift) { } __DEVICE__ unsigned int __vabs2(unsigned int __a) { unsigned int r; - asm("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabs4(unsigned int __a) { unsigned int r; - asm("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffs2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.u32.u32.u32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsdiffu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.u32.u32.u32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vabsss2(unsigned int __a) { unsigned int r; - asm("vabsdiff2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vabsss4(unsigned int __a) { unsigned int r; - asm("vabsdiff4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(0), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(0), "r"(0)); return r; } __DEVICE__ unsigned int __vadd2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vadd4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddss2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddss4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddus2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd2.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd2.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vaddus4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vadd4.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vadd4.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgs2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg2.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vavgu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vavrg4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vavrg4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vseteq2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.eq %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.eq %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpeq2(unsigned int __a, unsigned int __b) { @@ -1174,7 +1190,9 @@ __DEVICE__ unsigned int __vcmpeq2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vseteq4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.eq %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.eq %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpeq4(unsigned int __a, unsigned int __b) { @@ -1182,7 +1200,9 @@ __DEVICE__ unsigned int __vcmpeq4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetges2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpges2(unsigned int __a, unsigned int __b) { @@ -1190,7 +1210,9 @@ __DEVICE__ unsigned int __vcmpges2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetges4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpges4(unsigned int __a, unsigned int __b) { @@ -1198,7 +1220,9 @@ __DEVICE__ unsigned int __vcmpges4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgeu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgeu2(unsigned int __a, unsigned int __b) { @@ -1206,7 +1230,9 @@ __DEVICE__ unsigned int __vcmpgeu2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgeu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.ge %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.ge %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgeu4(unsigned int __a, unsigned int __b) { @@ -1214,7 +1240,9 @@ __DEVICE__ unsigned int __vcmpgeu4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgts2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgts2(unsigned int __a, unsigned int __b) { @@ -1222,7 +1250,9 @@ __DEVICE__ unsigned int __vcmpgts2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgts4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgts4(unsigned int __a, unsigned int __b) { @@ -1230,7 +1260,9 @@ __DEVICE__ unsigned int __vcmpgts4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgtu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgtu2(unsigned int __a, unsigned int __b) { @@ -1238,7 +1270,9 @@ __DEVICE__ unsigned int __vcmpgtu2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetgtu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.gt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.gt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpgtu4(unsigned int __a, unsigned int __b) { @@ -1246,7 +1280,9 @@ __DEVICE__ unsigned int __vcmpgtu4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetles2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmples2(unsigned int __a, unsigned int __b) { @@ -1254,7 +1290,9 @@ __DEVICE__ unsigned int __vcmples2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetles4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmples4(unsigned int __a, unsigned int __b) { @@ -1262,7 +1300,9 @@ __DEVICE__ unsigned int __vcmples4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetleu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpleu2(unsigned int __a, unsigned int __b) { @@ -1270,7 +1310,9 @@ __DEVICE__ unsigned int __vcmpleu2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetleu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.le %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.le %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpleu4(unsigned int __a, unsigned int __b) { @@ -1278,7 +1320,9 @@ __DEVICE__ unsigned int __vcmpleu4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetlts2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.s32.s32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.s32.s32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmplts2(unsigned int __a, unsigned int __b) { @@ -1286,7 +1330,9 @@ __DEVICE__ unsigned int __vcmplts2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetlts4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.s32.s32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.s32.s32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmplts4(unsigned int __a, unsigned int __b) { @@ -1294,7 +1340,9 @@ __DEVICE__ unsigned int __vcmplts4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetltu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpltu2(unsigned int __a, unsigned int __b) { @@ -1302,7 +1350,9 @@ __DEVICE__ unsigned int __vcmpltu2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetltu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.lt %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.lt %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpltu4(unsigned int __a, unsigned int __b) { @@ -1310,7 +1360,9 @@ __DEVICE__ unsigned int __vcmpltu4(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetne2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset2.u32.u32.ne %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset2.u32.u32.ne %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpne2(unsigned int __a, unsigned int __b) { @@ -1318,7 +1370,9 @@ __DEVICE__ unsigned int __vcmpne2(unsigned int __a, unsigned int __b) { } __DEVICE__ unsigned int __vsetne4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vset4.u32.u32.ne %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vset4.u32.u32.ne %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vcmpne4(unsigned int __a, unsigned int __b) { @@ -1345,94 +1399,112 @@ __DEVICE__ unsigned int __vmaxs2(unsigned int __a, unsigned int __b) { unsigned mask = __vcmpgts2(__a, __b); r = (__a & mask) | (__b & ~mask); } else { - asm("vmax2.s32.s32.s32 %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); } return r; } __DEVICE__ unsigned int __vmaxs4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmaxu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmaxu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmax4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmax4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmins2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin2.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin2.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vmins4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin4.s32.s32.s32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin4.s32.s32.s32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vminu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vminu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vmin4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vmin4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsads2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.s32.s32.s32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.s32.s32.s32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsads4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.s32.s32.s32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.s32.s32.s32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsadu2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff2.u32.u32.u32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff2.u32.u32.u32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsadu4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vabsdiff4.u32.u32.u32.add %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vabsdiff4.u32.u32.u32.add %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsub2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vneg2(unsigned int __a) { return __vsub2(0, __a); } __DEVICE__ unsigned int __vsub4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.u32.u32.u32 %0,%1,%2,%3;" : "=r"(r) : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.u32.u32.u32 %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vneg4(unsigned int __a) { return __vsub4(0, __a); } __DEVICE__ unsigned int __vsubss2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vnegss2(unsigned int __a) { @@ -1440,9 +1512,9 @@ __DEVICE__ unsigned int __vnegss2(unsigned int __a) { } __DEVICE__ unsigned int __vsubss4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.s32.s32.s32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.s32.s32.s32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vnegss4(unsigned int __a) { @@ -1450,16 +1522,16 @@ __DEVICE__ unsigned int __vnegss4(unsigned int __a) { } __DEVICE__ unsigned int __vsubus2(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub2.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub2.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } __DEVICE__ unsigned int __vsubus4(unsigned int __a, unsigned int __b) { unsigned int r; - asm("vsub4.u32.u32.u32.sat %0,%1,%2,%3;" - : "=r"(r) - : "r"(__a), "r"(__b), "r"(0)); + __asm__("vsub4.u32.u32.u32.sat %0,%1,%2,%3;" + : "=r"(r) + : "r"(__a), "r"(__b), "r"(0)); return r; } #endif // CUDA_VERSION >= 9020 diff --git a/clang/lib/Headers/__clang_cuda_intrinsics.h b/clang/lib/Headers/__clang_cuda_intrinsics.h index c7bff6a9d8f..e0875bbcbf4 100644 --- a/clang/lib/Headers/__clang_cuda_intrinsics.h +++ b/clang/lib/Headers/__clang_cuda_intrinsics.h @@ -483,4 +483,36 @@ inline __device__ unsigned __funnelshift_rc(unsigned low32, unsigned high32, #endif // !defined(__CUDA_ARCH__) || __CUDA_ARCH__ >= 320 +#if CUDA_VERSION >= 11000 +extern "C" { +__device__ inline size_t __nv_cvta_generic_to_global_impl(const void *__ptr) { + return (size_t)(void __attribute__((address_space(1))) *)__ptr; +} +__device__ inline size_t __nv_cvta_generic_to_shared_impl(const void *__ptr) { + return (size_t)(void __attribute__((address_space(3))) *)__ptr; +} +__device__ inline size_t __nv_cvta_generic_to_constant_impl(const void *__ptr) { + return (size_t)(void __attribute__((address_space(4))) *)__ptr; +} +__device__ inline size_t __nv_cvta_generic_to_local_impl(const void *__ptr) { + return (size_t)(void __attribute__((address_space(5))) *)__ptr; +} +__device__ inline void *__nv_cvta_global_to_generic_impl(size_t __ptr) { + return (void *)(void __attribute__((address_space(1))) *)__ptr; +} +__device__ inline void *__nv_cvta_shared_to_generic_impl(size_t __ptr) { + return (void *)(void __attribute__((address_space(3))) *)__ptr; +} +__device__ inline void *__nv_cvta_constant_to_generic_impl(size_t __ptr) { + return (void *)(void __attribute__((address_space(4))) *)__ptr; +} +__device__ inline void *__nv_cvta_local_to_generic_impl(size_t __ptr) { + return (void *)(void __attribute__((address_space(5))) *)__ptr; +} +__device__ inline uint32_t __nvvm_get_smem_pointer(void *__ptr) { + return __nv_cvta_generic_to_shared_impl(__ptr); +} +} // extern "C" +#endif // CUDA_VERSION >= 11000 + #endif // defined(__CLANG_CUDA_INTRINSICS_H__) diff --git a/clang/lib/Headers/__clang_cuda_libdevice_declares.h b/clang/lib/Headers/__clang_cuda_libdevice_declares.h index 6173b589e3e..23f35964ea9 100644 --- a/clang/lib/Headers/__clang_cuda_libdevice_declares.h +++ b/clang/lib/Headers/__clang_cuda_libdevice_declares.h @@ -16,6 +16,7 @@ extern "C" { #if defined(__OPENMP_NVPTX__) #define __DEVICE__ +#pragma omp begin assumes ext_spmd_amenable no_openmp #elif defined(__CUDA__) #define __DEVICE__ __device__ #endif @@ -456,6 +457,11 @@ __DEVICE__ double __nv_y1(double __a); __DEVICE__ float __nv_y1f(float __a); __DEVICE__ float __nv_ynf(int __a, float __b); __DEVICE__ double __nv_yn(int __a, double __b); + +#if defined(__OPENMP_NVPTX__) +#pragma omp end assumes ext_spmd_amenable no_openmp +#endif + #if defined(__cplusplus) } // extern "C" #endif diff --git a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h index f401964bd52..512fc300fc3 100644 --- a/clang/lib/Headers/__clang_cuda_runtime_wrapper.h +++ b/clang/lib/Headers/__clang_cuda_runtime_wrapper.h @@ -41,6 +41,7 @@ #include #include #include +#include #undef __CUDACC__ // Preserve common macros that will be changed below by us or by CUDA @@ -64,9 +65,9 @@ #endif // Make largest subset of device functions available during host -// compilation -- SM_35 for the time being. +// compilation. #ifndef __CUDA_ARCH__ -#define __CUDA_ARCH__ 350 +#define __CUDA_ARCH__ 9999 #endif #include "__clang_cuda_builtin_vars.h" @@ -205,11 +206,6 @@ inline __host__ double __signbitd(double x) { #endif #if CUDA_VERSION >= 9000 -// CUDA-9.2 needs host-side memcpy for some host functions in -// device_functions.hpp -#if CUDA_VERSION >= 9020 -#include -#endif #include "crt/math_functions.hpp" #else #include "math_functions.hpp" @@ -275,7 +271,38 @@ static inline __device__ void __brkpt(int __c) { __brkpt(); } #undef __CUDABE__ #endif #include "sm_20_atomic_functions.hpp" +// Predicate functions used in `__builtin_assume` need to have no side effect. +// However, sm_20_intrinsics.hpp doesn't define them with neither pure nor +// const attribute. Rename definitions from sm_20_intrinsics.hpp and re-define +// them as pure ones. +#pragma push_macro("__isGlobal") +#pragma push_macro("__isShared") +#pragma push_macro("__isConstant") +#pragma push_macro("__isLocal") +#define __isGlobal __ignored_cuda___isGlobal +#define __isShared __ignored_cuda___isShared +#define __isConstant __ignored_cuda___isConstant +#define __isLocal __ignored_cuda___isLocal #include "sm_20_intrinsics.hpp" +#pragma pop_macro("__isGlobal") +#pragma pop_macro("__isShared") +#pragma pop_macro("__isConstant") +#pragma pop_macro("__isLocal") +#pragma push_macro("__DEVICE__") +#define __DEVICE__ static __device__ __forceinline__ __attribute__((const)) +__DEVICE__ unsigned int __isGlobal(const void *p) { + return __nvvm_isspacep_global(p); +} +__DEVICE__ unsigned int __isShared(const void *p) { + return __nvvm_isspacep_shared(p); +} +__DEVICE__ unsigned int __isConstant(const void *p) { + return __nvvm_isspacep_const(p); +} +__DEVICE__ unsigned int __isLocal(const void *p) { + return __nvvm_isspacep_local(p); +} +#pragma pop_macro("__DEVICE__") #include "sm_32_atomic_functions.hpp" // Don't include sm_30_intrinsics.h and sm_32_intrinsics.h. These define the @@ -330,6 +357,34 @@ static inline __device__ void __brkpt(int __c) { __brkpt(); } #pragma pop_macro("__host__") +// __clang_cuda_texture_intrinsics.h must be included first in order to provide +// implementation for __nv_tex_surf_handler that CUDA's headers depend on. +// The implementation requires c++11 and only works with CUDA-9 or newer. +#if __cplusplus >= 201103L && CUDA_VERSION >= 9000 +// clang-format off +#include <__clang_cuda_texture_intrinsics.h> +// clang-format on +#else +#if CUDA_VERSION >= 9000 +// Provide a hint that texture support needs C++11. +template struct __nv_tex_needs_cxx11 { + const static bool value = false; +}; +template +__host__ __device__ void __nv_tex_surf_handler(const char *name, T *ptr, + cudaTextureObject_t obj, + float x) { + _Static_assert(__nv_tex_needs_cxx11::value, + "Texture support requires C++11"); +} +#else +// Textures in CUDA-8 and older are not supported by clang.There's no +// convenient way to intercept texture use in these versions, so we can't +// produce a meaningful error. The source code that attempts to use textures +// will continue to fail as it does now. +#endif // CUDA_VERSION +#endif // __cplusplus >= 201103L && CUDA_VERSION >= 9000 +#include "texture_fetch_functions.h" #include "texture_indirect_functions.h" // Restore state of __CUDA_ARCH__ and __THROW we had on entry. diff --git a/clang/lib/Headers/__clang_cuda_texture_intrinsics.h b/clang/lib/Headers/__clang_cuda_texture_intrinsics.h new file mode 100644 index 00000000000..3c0f0026f1f --- /dev/null +++ b/clang/lib/Headers/__clang_cuda_texture_intrinsics.h @@ -0,0 +1,740 @@ +/*===--- __clang_cuda_texture_intrinsics.h - Device-side texture support ---=== + * + * 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 header provides in-header implmentations for NVCC's built-in + * __nv_tex_surf_handler() which is used by CUDA's texture-related headers. The + * built-in is unusual as it's actually a set of function overloads that use the + * first string literal argument as one of the overload parameters. + */ +#ifndef __CLANG_CUDA_TEXTURE_INTRINSICS_H__ +#define __CLANG_CUDA_TEXTURE_INTRINSICS_H__ +#ifndef __CUDA__ +#error "This file is for CUDA compilation only." +#endif + +// __nv_tex_surf_handler() provided by this header as a macro. +#define __nv_tex_surf_handler(__op, __ptr, ...) \ + ::__cuda_tex::__tex_fetch< \ + ::__cuda_tex::__Tag<::__cuda_tex::__tex_op_hash(__op)>>(__ptr, \ + __VA_ARGS__) + +#pragma push_macro("__ASM_OUT") +#pragma push_macro("__ASM_OUTP") +#pragma push_macro("__Args") +#pragma push_macro("__ID") +#pragma push_macro("__IDV") +#pragma push_macro("__IMPL_2DGATHER") +#pragma push_macro("__IMPL_ALIAS") +#pragma push_macro("__IMPL_ALIASI") +#pragma push_macro("__IMPL_F1") +#pragma push_macro("__IMPL_F3") +#pragma push_macro("__IMPL_F3N") +#pragma push_macro("__IMPL_F3S") +#pragma push_macro("__IMPL_S") +#pragma push_macro("__IMPL_S3") +#pragma push_macro("__IMPL_S3I") +#pragma push_macro("__IMPL_S3N") +#pragma push_macro("__IMPL_S3NI") +#pragma push_macro("__IMPL_S3S") +#pragma push_macro("__IMPL_S3SI") +#pragma push_macro("__IMPL_SI") +#pragma push_macro("__L") +#pragma push_macro("__STRIP_PARENS") + +// Put all functions into anonymous namespace so they have internal linkage. +// The device-only function here must be internal in order to avoid ODR +// violations in case they are used from the files compiled with +// -fgpu-rdc. E.g. a library and an app using it may be built with a different +// version of this header file. +namespace { + +// Put the implmentation into its own namespace so we don't pollute the TU. +namespace __cuda_tex { + +// First, we need a perfect hash function and a few constexpr helper functions +// for converting a string literal into a numeric value which can be used to +// parametrize a template. We can not use string literals for that as that would +// require C++20. +// +// The hash function was generated with 'gperf' and then manually converted into +// its constexpr equivalent. +// +// NOTE: the perfect hashing scheme comes with inherent self-test. If the hash +// function has a collision for any of the texture operations, the compilation +// will fail due to an attempt to redefine a tag with the same value. If the +// header compiles, then the hash function is good enough for the job. + +constexpr int __tex_len(const char *s) { + return (s[0] == 0) ? 0 + : (s[1] == 0) ? 1 + : (s[2] == 0) ? 2 + : (s[3] == 0) ? 3 + : (s[4] == 0) ? 4 + : (s[5] == 0) ? 5 + : (s[6] == 0) ? 6 + : (s[7] == 0) ? 7 + : (s[8] == 0) ? 8 + : (s[9] == 0) ? 9 + : (s[10] == 0) ? 10 + : (s[11] == 0) ? 11 + : (s[12] == 0) ? 12 + : (s[13] == 0) ? 13 + : (s[14] == 0) ? 14 + : (s[15] == 0) ? 15 + : (s[16] == 0) ? 16 + : (s[17] == 0) ? 17 + : (s[18] == 0) ? 18 + : (s[19] == 0) ? 19 + : (s[20] == 0) ? 20 + : (s[21] == 0) ? 21 + : (s[22] == 0) ? 22 + : (s[23] == 0) ? 23 + : (s[24] == 0) ? 24 + : (s[25] == 0) ? 25 + : (s[26] == 0) ? 26 + : (s[27] == 0) ? 27 + : (s[28] == 0) ? 28 + : (s[29] == 0) ? 29 + : (s[30] == 0) ? 30 + : (s[31] == 0) ? 31 + : 32; +} + +constexpr int __tex_hash_map(int c) { + return (c == 49) ? 10 + : (c == 50) ? 0 + : (c == 51) ? 100 + : (c == 52) ? 30 + : (c == 67) ? 10 + : (c == 68) ? 0 + : (c == 69) ? 25 + : (c == 72) ? 70 + : (c == 77) ? 0 + : (c == 96) ? 44 + : (c == 99) ? 10 + : (c == 100) ? 5 + : (c == 101) ? 60 + : (c == 102) ? 40 + : (c == 103) ? 70 + : (c == 104) ? 25 + : (c == 112) ? 0 + : (c == 114) ? 45 + : (c == 117) ? 5 + : (c == 118) ? 85 + : (c == 120) ? 20 + : 225; +} + +constexpr int __tex_op_hash(const char *str) { + return __tex_len(str) + __tex_hash_map(str[7] + 1) + __tex_hash_map(str[6]) + + __tex_hash_map(str[5]) + __tex_hash_map(str[__tex_len(str) - 1]); +} + +// Tag type to identify particular texture operation. +template struct __Tag; +#define __ID(__op) __Tag<__tex_op_hash(__op)> +// Tags for variants of particular operation. E.g. tex2Dgather can translate +// into 4 different instructions. +#define __IDV(__op, __variant) \ + __Tag<10000 + __tex_op_hash(__op) * 100 + __variant> + +// Helper classes for figuring out key data types for derived types. +// E.g. char2 has __base_t = char, __fetch_t = char4 +template struct __TypeInfoT; +// Type info for the fundamental types. +template <> struct __TypeInfoT { + using __base_t = float; + using __fetch_t = float4; +}; +template <> struct __TypeInfoT { + using __base_t = char; + using __fetch_t = int4; +}; +template <> struct __TypeInfoT { + using __base_t = signed char; + using __fetch_t = int4; +}; +template <> struct __TypeInfoT { + using __base_t = unsigned char; + using __fetch_t = uint4; +}; +template <> struct __TypeInfoT { + using __base_t = short; + using __fetch_t = int4; +}; +template <> struct __TypeInfoT { + using __base_t = unsigned short; + using __fetch_t = uint4; +}; +template <> struct __TypeInfoT { + using __base_t = int; + using __fetch_t = int4; +}; +template <> struct __TypeInfoT { + using __base_t = unsigned int; + using __fetch_t = uint4; +}; + +// Derived base/fetch types for N-element vectors. +template struct __TypeInfoT { + using __base_t = decltype(__T::x); + using __fetch_t = typename __TypeInfoT<__base_t>::__fetch_t; +}; + +// Classes that implement specific texture ops. +template struct __tex_fetch_v4; + +// Helper macros to strip parens from a macro argument. +#define __Args(...) __VA_ARGS__ +#define __STRIP_PARENS(__X) __X +#define __L(__X) __STRIP_PARENS(__Args __X) + +// Construct inline assembly output args. +// Results are stored in a temp var __r. +// isResident bool is pointed to by __ir +// Asm args for return values. It's a 4-element vector +#define __ASM_OUT(__t) \ + ("=" __t(__r.x), "=" __t(__r.y), "=" __t(__r.z), "=" __t(__r.w)) +// .. possibly combined with a predicate. +#define __ASM_OUTP(__t) (__L(__ASM_OUT(__t)), "=h"(*__ir)) + +// Implements a single variant of texture fetch instruction. +#define __IMPL_F1(__rt, __dt, __args, __asm_op, __asm_outs, __asm_args) \ + template <> \ + __device__ __rt __run<__dt>(cudaTextureObject_t __obj, __L(__args)) { \ + __rt __r; \ + asm(__asm_op : __L(__asm_outs) : "l"(__obj), __L(__asm_args)); \ + return __r; \ + } + +// Implements texture fetch instructions for int4/uint4/float4 data types. +#define __IMPL_F3(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_F1(int4, int4, __args, __asm_op ".s32." __ctype "\t" __asm_op_args, \ + __ASM_OUT("r"), __asm_args) \ + __IMPL_F1(uint4, uint4, __args, __asm_op ".u32." __ctype "\t" __asm_op_args, \ + __ASM_OUT("r"), __asm_args) \ + __IMPL_F1(float4, float4, __args, \ + __asm_op ".f32." __ctype "\t" __asm_op_args, __ASM_OUT("f"), \ + __asm_args) +// Implements 'sparse' texture fetch instructions for int4/uint4/float4 data +// types. Similar to above, but returns a boolean 'isPresent' value in addition +// to texture data, +#define __IMPL_F3S(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_F1(int4, int4, __args, __asm_op ".s32." __ctype "\t" __asm_op_args, \ + __ASM_OUTP("r"), __asm_args) \ + __IMPL_F1(uint4, uint4, __args, __asm_op ".u32." __ctype "\t" __asm_op_args, \ + __ASM_OUTP("r"), __asm_args) \ + __IMPL_F1(float4, float4, __args, \ + __asm_op ".f32." __ctype "\t" __asm_op_args, __ASM_OUTP("f"), \ + __asm_args) + +// Similar to F3, but for integer data which is returned as normalized floats. +// Only instantiates fetch functions for int4/uint4. +#define __IMPL_F3N(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_F1(float4, int4, __args, __asm_op ".s32." __ctype "\t" __asm_op_args, \ + __ASM_OUT("r"), __asm_args) \ + __IMPL_F1(float4, uint4, __args, \ + __asm_op ".u32." __ctype "\t" __asm_op_args, __ASM_OUT("r"), \ + __asm_args) + +// Instantiates __tex_fetch_v4 with regular fetch functions. +#define __IMPL_S3I(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + template <> struct __tex_fetch_v4<__op> { \ + template \ + __device__ static T __run(cudaTextureObject_t __obj, __L(__args)); \ + __IMPL_F3(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + } + +// Same, but for sparse ops. Only available on sm_60+ +#if !defined(__CUDA_ARCH__) || (__CUDA_ARCH__ >= 600) +#define __IMPL_S3SI(__op, __args, __asm_op, __ctype, __asm_op_args, \ + __asm_args) \ + template <> struct __tex_fetch_v4<__op> { \ + template \ + __device__ static T __run(cudaTextureObject_t __obj, __L(__args)); \ + __IMPL_F3S(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + } +#else +#define __IMPL_S3SI(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args) +#endif + +// Same, but for normalized float ops. +#define __IMPL_S3NI(__op, __args, __asm_op, __ctype, __asm_op_args, \ + __asm_args) \ + template <> struct __tex_fetch_v4<__op> { \ + template \ + __device__ static float4 __run(cudaTextureObject_t __obj, __L(__args)); \ + __IMPL_F3N(__args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + } + +// Regular and normalized float ops share a lot of similarities. This macro +// instantiates both variants -- normal for __op and normalized for __opn. +#define __IMPL_SI(__op, __opn, __args, __asm_op, __ctype, __asm_op_args, \ + __asm_args) \ + __IMPL_S3I(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args); \ + __IMPL_S3NI(__opn, __args, __asm_op, __ctype, __asm_op_args, __asm_args) + +// Convenience macros which converts string literal __op into a __Tag, +#define __IMPL_S3(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_S3I(__ID(__op), __args, __asm_op, __ctype, __asm_op_args, __asm_args) +#define __IMPL_S3S(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_S3SI(__ID(__op), __args, __asm_op, __ctype, __asm_op_args, __asm_args) +#define __IMPL_S3N(__op, __args, __asm_op, __ctype, __asm_op_args, __asm_args) \ + __IMPL_S3NI(__ID(__op), __args, __asm_op, __ctype, __asm_op_args, __asm_args) +#define __IMPL_S(__op, __opn, __args, __asm_op, __ctype, __asm_op_args, \ + __asm_args) \ + __IMPL_SI(__ID(__op), __ID(__opn), __args, __asm_op, __ctype, __asm_op_args, \ + __asm_args) + +// CUDA headers have some 'legacy' texture oprerations that duplicate +// functionality. So, we just inherit it, instead of refining a copy. +#define __IMPL_ALIASI(__op, __opn) \ + template <> struct __tex_fetch_v4<__op> : __tex_fetch_v4<__opn> {} +#define __IMPL_ALIAS(__op, __opn) __IMPL_ALIASI(__ID(__op), __ID(__opn)) + +// Now we can instantiate everything we need for each specific texture fetch +// variant. +__IMPL_S("__tex1D_v2", "__tex1D_rmnf_v2", (float __x), "tex.1d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5}];", ("f"(__x))); +__IMPL_S("__tex1Dfetch_v2", "__tex1Dfetch_rmnf_v2", (int __x), "tex.1d.v4", + "s32", "{%0, %1, %2, %3}, [%4, {%5}];", ("r"(__x))); +__IMPL_ALIAS("__itex1D", "__tex1D_v2"); +__IMPL_ALIAS("__itex1Dfetch", "__tex1Dfetch_v2"); + +__IMPL_S("__tex1DGrad_v2", "__tex1DGrad_rmnf_v2", + (float __x, float __dPdx, float __dPdy), "tex.grad.1d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5}], {%6}, {%7};", + ("f"(__x), "f"(__dPdx), "f"(__dPdy))); +__IMPL_ALIAS("__itex1DGrad", "__tex1DGrad_v2"); + +__IMPL_S("__tex1DLayered_v2", "__tex1DLayered_rmnf_v2", + (float __x, int __layer), "tex.a1d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6}];", ("r"(__layer), "f"(__x))); +__IMPL_ALIAS("__itex1DLayered", "__tex1DLayered_v2"); + +__IMPL_S("__tex1DLayeredGrad_v2", "__tex1DLayeredGrad_rmnf_v2", + (float __x, int __layer, float __dPdx, float __dPdy), + "tex.grad.a1d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6}], {%7}, {%8};", + ("r"(__layer), "f"(__x), "f"(__dPdx), "f"(__dPdy))); +__IMPL_ALIAS("__itex1DLayeredGrad", "__tex1DLayeredGrad_v2"); + +__IMPL_S("__tex1DLayeredLod_v2", "__tex1DLayeredLod_rmnf_v2", + (float __x, int __layer, float __level), "tex.level.a1d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6}], %7;", + ("r"(__layer), "f"(__x), "f"(__level))); +__IMPL_ALIAS("__itex1DLayeredLod", "__tex1DLayeredLod_v2"); + +__IMPL_S("__tex1DLod_v2", "__tex1DLod_rmnf_v2", (float __x, float __level), + "tex.level.1d.v4", "f32", "{%0, %1, %2, %3}, [%4, {%5}], %6;", + ("f"(__x), "f"(__level))); +__IMPL_ALIAS("__itex1DLod", "__tex1DLod_v2"); + +// 2D +__IMPL_S("__tex2D_v2", "__tex2D_rmnf_v2", (float __x, float __y), "tex.2d.v4", + "f32", "{%0, %1, %2, %3}, [%4, {%5, %6}];", ("f"(__x), "f"(__y))); +__IMPL_ALIAS("__itex2D", "__tex2D_v2"); + +__IMPL_S3S("__itex2D_sparse", (float __x, float __y, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7}];\n\t" + " selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y))); + +__IMPL_S("__tex2DGrad_v2", "__tex2DGrad_rmnf_v2", + (float __x, float __y, const float2 *__dPdx, const float2 *__dPdy), + "tex.grad.2d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6}], {%7, %8}, {%9, %10};", + ("f"(__x), "f"(__y), "f"(__dPdx->x), "f"(__dPdx->y), "f"(__dPdy->x), + "f"(__dPdy->y))); +__IMPL_ALIAS("__itex2DGrad_v2", "__tex2DGrad_v2"); + +__IMPL_S3S("__itex2DGrad_sparse", + (float __x, float __y, const float2 *__dPdx, const float2 *__dPdy, + unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.grad.2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7}], {%8, %9}, {%10, %11};\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__dPdx->x), "f"(__dPdx->y), "f"(__dPdy->x), + "f"(__dPdy->y))); + +__IMPL_S("__tex2DLayered_v2", "__tex2DLayered_rmnf_v2", + (float __x, float __y, int __layer), "tex.a2d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}];", + ("r"(__layer), "f"(__x), "f"(__y))); +__IMPL_ALIAS("__itex2DLayered", "__tex2DLayered_v2"); + +__IMPL_S3S("__itex2DLayered_sparse", + (float __x, float __y, int __layer, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.a2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}];\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("r"(__layer), "f"(__x), "f"(__y))); + +__IMPL_S("__tex2DLayeredGrad_v2", "__tex2DLayeredGrad_rmnf_v2", + (float __x, float __y, int __layer, const float2 *__dPdx, + const float2 *__dPdy), + "tex.grad.a2d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], {%8, %9}, {%10, %11};", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__dPdx->x), "f"(__dPdx->y), + "f"(__dPdy->x), "f"(__dPdy->y))); +__IMPL_ALIAS("__itex2DLayeredGrad_v2", "__tex2DLayeredGrad_v2"); + +__IMPL_S3S( + "__itex2DLayeredGrad_sparse", + (float __x, float __y, int __layer, const float2 *__dPdx, + const float2 *__dPdy, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.grad.a2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}], {%9, %10}, {%11, %12};\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__dPdx->x), "f"(__dPdx->y), + "f"(__dPdy->x), "f"(__dPdy->y))); + +__IMPL_S("__tex2DLayeredLod_v2", "__tex2DLayeredLod_rmnf_v2", + (float __x, float __y, int __layer, float __level), "tex.level.a2d.v4", + "f32", "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], %8;", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__level))); +__IMPL_ALIAS("__itex2DLayeredLod", "__tex2DLayeredLod_v2"); + +__IMPL_S3S("__itex2DLayeredLod_sparse", + (float __x, float __y, int __layer, float __level, + unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.level.a2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}], %9;\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__level))); + +__IMPL_S("__tex2DLod_v2", "__tex2DLod_rmnf_v2", + (float __x, float __y, float __level), "tex.level.2d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6}], %7;", + ("f"(__x), "f"(__y), "f"(__level))); +__IMPL_ALIAS("__itex2DLod", "__tex2DLod_v2"); + +__IMPL_S3S("__itex2DLod_sparse", + (float __x, float __y, float __level, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.level.2d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7}], %8;\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__level))); + +// 2D gather is special. Unlike other variants that translate into exactly one +// asm instruction, it uses one of the four different instructions selected by +// __comp. We implement each instruction variant separately, and dispatch the +// right one from the manually implemented 'umbrella' fetch. +#define __IMPL_2DGATHER(variant, instr) \ + __IMPL_SI(__IDV("__tex2Dgather_v2", variant), \ + __IDV("__tex2Dgather_rmnf_v2", variant), \ + (float __x, float __y, int __comp), instr, "f32", \ + "{%0, %1, %2, %3}, [%4, {%5, %6}];", ("f"(__x), "f"(__y))); \ + __IMPL_ALIASI(__IDV("__itex2Dgather", variant), \ + __IDV("__tex2Dgather_v2", variant)); \ + __IMPL_S3SI(__IDV("__itex2Dgather_sparse", variant), \ + (float __x, float __y, unsigned char *__ir, int __comp), \ + "{.reg .pred %%p0;\n\t" instr, "f32", \ + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7}];\n\t" \ + "selp.u16 %4, 1, 0, %%p0; }", \ + ("f"(__x), "f"(__y))); +__IMPL_2DGATHER(0, "tld4.r.2d.v4"); +__IMPL_2DGATHER(1, "tld4.g.2d.v4"); +__IMPL_2DGATHER(2, "tld4.b.2d.v4"); +__IMPL_2DGATHER(3, "tld4.a.2d.v4"); + +// Umbrella dispatcher -- calls into specific 2Dgather variant. +template <> struct __tex_fetch_v4<__ID("__tex2Dgather_v2")> { + template + __device__ static __T __run(cudaTextureObject_t __obj, float __x, float __y, + int __comp) { + switch (__comp) { + case 0: + return __tex_fetch_v4<__IDV("__tex2Dgather_v2", 0)>::__run<__T>( + __obj, __x, __y, __comp); + case 1: + return __tex_fetch_v4<__IDV("__tex2Dgather_v2", 1)>::__run<__T>( + __obj, __x, __y, __comp); + case 2: + return __tex_fetch_v4<__IDV("__tex2Dgather_v2", 2)>::__run<__T>( + __obj, __x, __y, __comp); + case 3: + return __tex_fetch_v4<__IDV("__tex2Dgather_v2", 3)>::__run<__T>( + __obj, __x, __y, __comp); + } + } +}; +__IMPL_ALIAS("__itex2Dgather", "__tex2Dgather_v2"); + +template <> struct __tex_fetch_v4<__ID("__tex2Dgather_rmnf_v2")> { + template + __device__ static float4 __run(cudaTextureObject_t __obj, float __x, + float __y, int __comp) { + switch (__comp) { + case 0: + return __tex_fetch_v4<__IDV("__tex2Dgather_rmnf_v2", 0)>::__run<__T>( + __obj, __x, __y, __comp); + case 1: + return __tex_fetch_v4<__IDV("__tex2Dgather_rmnf_v2", 1)>::__run<__T>( + __obj, __x, __y, __comp); + case 2: + return __tex_fetch_v4<__IDV("__tex2Dgather_rmnf_v2", 2)>::__run<__T>( + __obj, __x, __y, __comp); + case 3: + return __tex_fetch_v4<__IDV("__tex2Dgather_rmnf_v2", 3)>::__run<__T>( + __obj, __x, __y, __comp); + } + } +}; + +#if !defined(__CUDA_ARCH__) || (__CUDA_ARCH__ >= 600) +template <> struct __tex_fetch_v4<__ID("__itex2Dgather_sparse")> { + template + __device__ static __T __run(cudaTextureObject_t __obj, float __x, float __y, + unsigned char *__ir, int __comp) { + switch (__comp) { + case 0: + return __tex_fetch_v4<__IDV("__itex2Dgather_sparse", 0)>::__run<__T>( + __obj, __x, __y, __ir, __comp); + case 1: + return __tex_fetch_v4<__IDV("__itex2Dgather_sparse", 1)>::__run<__T>( + __obj, __x, __y, __ir, __comp); + case 2: + return __tex_fetch_v4<__IDV("__itex2Dgather_sparse", 2)>::__run<__T>( + __obj, __x, __y, __ir, __comp); + case 3: + return __tex_fetch_v4<__IDV("__itex2Dgather_sparse", 3)>::__run<__T>( + __obj, __x, __y, __ir, __comp); + } + } +}; +#endif + +// 3D +__IMPL_S("__tex3D_v2", "__tex3D_rmnf_v2", (float __x, float __y, float __z), + "tex.3d.v4", "f32", "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}];", + ("f"(__x), "f"(__y), "f"(__z))); +__IMPL_ALIAS("__itex3D", "__tex3D_v2"); + +__IMPL_S3S("__itex3D_sparse", + (float __x, float __y, float __z, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.3d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}];\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__z))); + +__IMPL_S("__tex3DGrad_v2", "__tex3DGrad_rmnf_v2", + (float __x, float __y, float __z, const float4 *__dPdx, + const float4 *__dPdy), + "tex.grad.3d.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], " + "{%8, %9, %10, %10}, {%11, %12, %13, %13};", + ("f"(__x), "f"(__y), "f"(__z), "f"(__dPdx->x), "f"(__dPdx->y), + "f"(__dPdx->z), "f"(__dPdy->x), "f"(__dPdy->y), "f"(__dPdy->z))); +__IMPL_ALIAS("__itex3DGrad_v2", "__tex3DGrad_v2"); + +__IMPL_S3S("__itex3DGrad_sparse", + (float __x, float __y, float __z, const float4 *__dPdx, + const float4 *__dPdy, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.grad.3d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}], " + "{%9, %10, %11, %11}, {%12, %13, %14, %14};\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__z), "f"(__dPdx->x), "f"(__dPdx->y), + "f"(__dPdx->z), "f"(__dPdy->x), "f"(__dPdy->y), "f"(__dPdy->z))); + +__IMPL_S("__tex3DLod_v2", "__tex3DLod_rmnf_v2", + (float __x, float __y, float __z, float __level), "tex.level.3d.v4", + "f32", "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], %8;", + ("f"(__x), "f"(__y), "f"(__z), "f"(__level))); +__IMPL_ALIAS("__itex3DLod", "__tex3DLod_v2"); + +__IMPL_S3S("__itex3DLod_sparse", + (float __x, float __y, float __z, float __level, + unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.level.3d.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}], %9;\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__z), "f"(__level))); + +// Cubemap +__IMPL_S("__texCubemap_v2", "__texCubemap_rmnf_v2", + (float __x, float __y, float __z), "tex.cube.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}];", + ("f"(__x), "f"(__y), "f"(__z))); +__IMPL_ALIAS("__itexCubemap", "__texCubemap_v2"); + +__IMPL_S3S("__itexCubemap_sparse", + (float __x, float __y, float __z, unsigned char *__ir), + "{.reg .pred %%p0;\n\t" + "tex.cube.v4", + "f32", + "{%0, %1, %2, %3}|%%p0, [%5, {%6, %7, %8, %8}];\n\t" + "selp.u16 %4, 1, 0, %%p0; }", + ("f"(__x), "f"(__y), "f"(__z))); + +__IMPL_S("__texCubemapGrad_v2", "__texCubemapGrad_rmnf_v2", + (float __x, float __y, float __z, const float4 *__dPdx, + const float4 *__dPdy), + "tex.grad.cube.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], " + "{%8, %9, %10, %10}, {%11, %12, %13, %13};", + ("f"(__x), "f"(__y), "f"(__z), "f"(__dPdx->x), "f"(__dPdx->y), + "f"(__dPdx->z), "f"(__dPdy->x), "f"(__dPdy->y), "f"(__dPdy->z))); +__IMPL_ALIAS("__itexCubemapGrad_v2", "__texCubemapGrad_v2"); + +__IMPL_S("__texCubemapLayered_v2", "__texCubemapLayered_rmnf_v2", + (float __x, float __y, float __z, int __layer), "tex.acube.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}];", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__z))); +__IMPL_ALIAS("__itexCubemapLayered", "__texCubemapLayered_v2"); + +__IMPL_S("__texCubemapLayeredGrad_v2", "__texCubemapLayeredGrad_rmnf_v2", + (float __x, float __y, float __z, int __layer, const float4 *__dPdx, + const float4 *__dPdy), + "tex.grad.acube.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], " + "{%9, %10, %11, %11}, {%12, %13, %14, %14};", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__z), "f"(__dPdx->x), + "f"(__dPdx->y), "f"(__dPdx->z), "f"(__dPdy->x), "f"(__dPdy->y), + "f"(__dPdy->z))); +__IMPL_ALIAS("__itexCubemapLayeredGrad_v2", "__texCubemapLayeredGrad_v2"); + +__IMPL_S("__texCubemapLayeredLod_v2", "__texCubemapLayeredLod_rmnf_v2", + (float __x, float __y, float __z, int __layer, float __level), + "tex.level.acube.v4", "f32", + "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %8}], %9;", + ("r"(__layer), "f"(__x), "f"(__y), "f"(__z), "f"(__level))); +__IMPL_ALIAS("__itexCubemapLayeredLod", "__texCubemapLayeredLod_v2"); + +__IMPL_S("__texCubemapLod_v2", "__texCubemapLod_rmnf_v2", + (float __x, float __y, float __z, float __level), "tex.level.cube.v4", + "f32", "{%0, %1, %2, %3}, [%4, {%5, %6, %7, %7}], %8;", + ("f"(__x), "f"(__y), "f"(__z), "f"(__level))); +__IMPL_ALIAS("__itexCubemapLod", "__texCubemapLod_v2"); + +// Helper class for extracting slice of data from V4 fetch results. +template struct __convert { + template ::__base_t)> + __device__ static __DestT __run(__SrcT __v); + template <> __device__ static __DestT __run<1>(__SrcT __v) { return {__v.x}; } + template <> __device__ static __DestT __run<2>(__SrcT __v) { + return {__v.x, __v.y}; + } + template <> __device__ static __DestT __run<3>(__SrcT __v) { + return {__v.x, __v.y, __v.z}; + } + template <> __device__ static __DestT __run<4>(__SrcT __v) { + return {__v.x, __v.y, __v.z, __v.w}; + } +}; + +// These are the top-level function overloads the __nv_tex_surf_handler expands +// to. Each overload deals with one of the several ways __nv_tex_surf_handler +// is called by CUDA headers. In the end, each of the overloads does the same +// job -- it figures out which `__tex_fetch_v4::run` variant should be used to +// fetch texture data and which `__convert::run` is needed to convert it into +// appropriate return type. + +// __nv_tex_surf_handler("__tex...", &ret, cudaTextureObject_t handle, args...); +// Data type and return type are based on ret. +template +__device__ static void __tex_fetch(__T *__ptr, cudaTextureObject_t __handle, + __Args... __args) { + using __FetchT = typename __TypeInfoT<__T>::__fetch_t; + *__ptr = __convert<__T, __FetchT>::__run( + __tex_fetch_v4<__op>::template __run<__FetchT>(__handle, __args...)); +} + +// texture<> objects get magically converted into a texture reference. However, +// there's no way to convert them to cudaTextureObject_t on C++ level. So, we +// cheat a bit and use inline assembly to do it. It costs us an extra register +// and a move, but that is easy for ptxas to optimize away. +template +__device__ cudaTextureObject_t __tex_handle_to_obj(__T __handle) { + cudaTextureObject_t __obj; + asm("mov.b64 %0, %1; " : "=l"(__obj) : "l"(__handle)); + return __obj; +} + +// __nv_tex_surf_handler ("__tex...", &ret, textureReference, args...); +// Data type and return type is based on ret. +template +__device__ static void __tex_fetch(__T *__ptr, __HandleT __handle, + __Args... __args) { + using __FetchT = typename __TypeInfoT<__T>::__fetch_t; + *__ptr = __convert<__T, __FetchT>::__run( + __tex_fetch_v4<__op>::template __run<__FetchT>( + __tex_handle_to_obj(__handle), __args...)); +} + +// __nv_tex_surf_handler ("__tex...", &type_dummy, &ret, texture<...>, args...); +// cudaReadModeNormalizedFloat fetches always return float4. +template +__device__ static void +__tex_fetch(__DataT *, __RetT *__ptr, + texture<__DataT, __TexT, cudaReadModeNormalizedFloat> __handle, + __Args... __args) { + using __FetchT = typename __TypeInfoT<__DataT>::__fetch_t; + *__ptr = __convert<__RetT, float4>::__run( + __tex_fetch_v4<__op>::template __run<__FetchT>( + __tex_handle_to_obj(__handle), __args...)); +} + +// __nv_tex_surf_handler ("__tex...", &type_dummy, &ret, texture<...>, args...); +// For cudaReadModeElementType fetch return type is based on type_dummy. +template +__device__ static void +__tex_fetch(__DataT *, __RetT *__ptr, + texture<__DataT, __TexT, cudaReadModeElementType> __handle, + __Args... __args) { + using __FetchT = typename __TypeInfoT<__DataT>::__fetch_t; + *__ptr = __convert<__RetT, __FetchT>::__run( + __tex_fetch_v4<__op>::template __run<__FetchT>( + __tex_handle_to_obj(__handle), __args...)); +} +} // namespace __cuda_tex +} // namespace +#pragma pop_macro("__ASM_OUT") +#pragma pop_macro("__ASM_OUTP") +#pragma pop_macro("__Args") +#pragma pop_macro("__ID") +#pragma pop_macro("__IDV") +#pragma pop_macro("__IMPL_2DGATHER") +#pragma pop_macro("__IMPL_ALIAS") +#pragma pop_macro("__IMPL_ALIASI") +#pragma pop_macro("__IMPL_F1") +#pragma pop_macro("__IMPL_F3") +#pragma pop_macro("__IMPL_F3N") +#pragma pop_macro("__IMPL_F3S") +#pragma pop_macro("__IMPL_S") +#pragma pop_macro("__IMPL_S3") +#pragma pop_macro("__IMPL_S3I") +#pragma pop_macro("__IMPL_S3N") +#pragma pop_macro("__IMPL_S3NI") +#pragma pop_macro("__IMPL_S3S") +#pragma pop_macro("__IMPL_S3SI") +#pragma pop_macro("__IMPL_SI") +#pragma pop_macro("__L") +#pragma pop_macro("__STRIP_PARENS") +#endif // __CLANG_CUDA_TEXTURE_INTRINSICS_H__ diff --git a/clang/lib/Headers/__clang_hip_cmath.h b/clang/lib/Headers/__clang_hip_cmath.h index 7342705434e..d488db0a94d 100644 --- a/clang/lib/Headers/__clang_hip_cmath.h +++ b/clang/lib/Headers/__clang_hip_cmath.h @@ -10,7 +10,7 @@ #ifndef __CLANG_HIP_CMATH_H__ #define __CLANG_HIP_CMATH_H__ -#if !defined(__HIP__) +#if !defined(__HIP__) && !defined(__OPENMP_AMDGCN__) #error "This file is for HIP and OpenMP AMDGCN device compilation only." #endif @@ -25,31 +25,43 @@ #endif // !defined(__HIPCC_RTC__) #pragma push_macro("__DEVICE__") +#pragma push_macro("__CONSTEXPR__") +#ifdef __OPENMP_AMDGCN__ +#define __DEVICE__ static __attribute__((always_inline, nothrow)) +#define __CONSTEXPR__ constexpr +#else #define __DEVICE__ static __device__ inline __attribute__((always_inline)) +#define __CONSTEXPR__ +#endif // __OPENMP_AMDGCN__ // Start with functions that cannot be defined by DEF macros below. #if defined(__cplusplus) -__DEVICE__ double abs(double __x) { return ::fabs(__x); } -__DEVICE__ float abs(float __x) { return ::fabsf(__x); } -__DEVICE__ long long abs(long long __n) { return ::llabs(__n); } -__DEVICE__ long abs(long __n) { return ::labs(__n); } -__DEVICE__ float fma(float __x, float __y, float __z) { +#if defined __OPENMP_AMDGCN__ +__DEVICE__ __CONSTEXPR__ float fabs(float __x) { return ::fabsf(__x); } +__DEVICE__ __CONSTEXPR__ float sin(float __x) { return ::sinf(__x); } +__DEVICE__ __CONSTEXPR__ float cos(float __x) { return ::cosf(__x); } +#endif +__DEVICE__ __CONSTEXPR__ double abs(double __x) { return ::fabs(__x); } +__DEVICE__ __CONSTEXPR__ float abs(float __x) { return ::fabsf(__x); } +__DEVICE__ __CONSTEXPR__ long long abs(long long __n) { return ::llabs(__n); } +__DEVICE__ __CONSTEXPR__ long abs(long __n) { return ::labs(__n); } +__DEVICE__ __CONSTEXPR__ float fma(float __x, float __y, float __z) { return ::fmaf(__x, __y, __z); } #if !defined(__HIPCC_RTC__) // The value returned by fpclassify is platform dependent, therefore it is not // supported by hipRTC. -__DEVICE__ int fpclassify(float __x) { +__DEVICE__ __CONSTEXPR__ int fpclassify(float __x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); } -__DEVICE__ int fpclassify(double __x) { +__DEVICE__ __CONSTEXPR__ int fpclassify(double __x) { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, FP_SUBNORMAL, FP_ZERO, __x); } #endif // !defined(__HIPCC_RTC__) -__DEVICE__ float frexp(float __arg, int *__exp) { +__DEVICE__ __CONSTEXPR__ float frexp(float __arg, int *__exp) { return ::frexpf(__arg, __exp); } @@ -71,93 +83,101 @@ __DEVICE__ float frexp(float __arg, int *__exp) { // of the variants inside the inner region and avoid the clash. #pragma omp begin declare variant match(implementation = {vendor(llvm)}) -__DEVICE__ int isinf(float __x) { return ::__isinff(__x); } -__DEVICE__ int isinf(double __x) { return ::__isinf(__x); } -__DEVICE__ int isfinite(float __x) { return ::__finitef(__x); } -__DEVICE__ int isfinite(double __x) { return ::__finite(__x); } -__DEVICE__ int isnan(float __x) { return ::__isnanf(__x); } -__DEVICE__ int isnan(double __x) { return ::__isnan(__x); } +__DEVICE__ __CONSTEXPR__ int isinf(float __x) { return ::__isinff(__x); } +__DEVICE__ __CONSTEXPR__ int isinf(double __x) { return ::__isinf(__x); } +__DEVICE__ __CONSTEXPR__ int isfinite(float __x) { return ::__finitef(__x); } +__DEVICE__ __CONSTEXPR__ int isfinite(double __x) { return ::__finite(__x); } +__DEVICE__ __CONSTEXPR__ int isnan(float __x) { return ::__isnanf(__x); } +__DEVICE__ __CONSTEXPR__ int isnan(double __x) { return ::__isnan(__x); } #pragma omp end declare variant #endif // defined(__OPENMP_AMDGCN__) -__DEVICE__ bool isinf(float __x) { return ::__isinff(__x); } -__DEVICE__ bool isinf(double __x) { return ::__isinf(__x); } -__DEVICE__ bool isfinite(float __x) { return ::__finitef(__x); } -__DEVICE__ bool isfinite(double __x) { return ::__finite(__x); } -__DEVICE__ bool isnan(float __x) { return ::__isnanf(__x); } -__DEVICE__ bool isnan(double __x) { return ::__isnan(__x); } +__DEVICE__ __CONSTEXPR__ bool isinf(float __x) { return ::__isinff(__x); } +__DEVICE__ __CONSTEXPR__ bool isinf(double __x) { return ::__isinf(__x); } +__DEVICE__ __CONSTEXPR__ bool isfinite(float __x) { return ::__finitef(__x); } +__DEVICE__ __CONSTEXPR__ bool isfinite(double __x) { return ::__finite(__x); } +__DEVICE__ __CONSTEXPR__ bool isnan(float __x) { return ::__isnanf(__x); } +__DEVICE__ __CONSTEXPR__ bool isnan(double __x) { return ::__isnan(__x); } #if defined(__OPENMP_AMDGCN__) #pragma omp end declare variant #endif // defined(__OPENMP_AMDGCN__) -__DEVICE__ bool isgreater(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isgreater(float __x, float __y) { return __builtin_isgreater(__x, __y); } -__DEVICE__ bool isgreater(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isgreater(double __x, double __y) { return __builtin_isgreater(__x, __y); } -__DEVICE__ bool isgreaterequal(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isgreaterequal(float __x, float __y) { return __builtin_isgreaterequal(__x, __y); } -__DEVICE__ bool isgreaterequal(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isgreaterequal(double __x, double __y) { return __builtin_isgreaterequal(__x, __y); } -__DEVICE__ bool isless(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isless(float __x, float __y) { return __builtin_isless(__x, __y); } -__DEVICE__ bool isless(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isless(double __x, double __y) { return __builtin_isless(__x, __y); } -__DEVICE__ bool islessequal(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool islessequal(float __x, float __y) { return __builtin_islessequal(__x, __y); } -__DEVICE__ bool islessequal(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool islessequal(double __x, double __y) { return __builtin_islessequal(__x, __y); } -__DEVICE__ bool islessgreater(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool islessgreater(float __x, float __y) { return __builtin_islessgreater(__x, __y); } -__DEVICE__ bool islessgreater(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool islessgreater(double __x, double __y) { return __builtin_islessgreater(__x, __y); } -__DEVICE__ bool isnormal(float __x) { return __builtin_isnormal(__x); } -__DEVICE__ bool isnormal(double __x) { return __builtin_isnormal(__x); } -__DEVICE__ bool isunordered(float __x, float __y) { +__DEVICE__ __CONSTEXPR__ bool isnormal(float __x) { + return __builtin_isnormal(__x); +} +__DEVICE__ __CONSTEXPR__ bool isnormal(double __x) { + return __builtin_isnormal(__x); +} +__DEVICE__ __CONSTEXPR__ bool isunordered(float __x, float __y) { return __builtin_isunordered(__x, __y); } -__DEVICE__ bool isunordered(double __x, double __y) { +__DEVICE__ __CONSTEXPR__ bool isunordered(double __x, double __y) { return __builtin_isunordered(__x, __y); } -__DEVICE__ float modf(float __x, float *__iptr) { return ::modff(__x, __iptr); } -__DEVICE__ float pow(float __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ float modf(float __x, float *__iptr) { + return ::modff(__x, __iptr); +} +__DEVICE__ __CONSTEXPR__ float pow(float __base, int __iexp) { return ::powif(__base, __iexp); } -__DEVICE__ double pow(double __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ double pow(double __base, int __iexp) { return ::powi(__base, __iexp); } -__DEVICE__ float remquo(float __x, float __y, int *__quo) { +__DEVICE__ __CONSTEXPR__ float remquo(float __x, float __y, int *__quo) { return ::remquof(__x, __y, __quo); } -__DEVICE__ float scalbln(float __x, long int __n) { +__DEVICE__ __CONSTEXPR__ float scalbln(float __x, long int __n) { return ::scalblnf(__x, __n); } -__DEVICE__ bool signbit(float __x) { return ::__signbitf(__x); } -__DEVICE__ bool signbit(double __x) { return ::__signbit(__x); } +__DEVICE__ __CONSTEXPR__ bool signbit(float __x) { return ::__signbitf(__x); } +__DEVICE__ __CONSTEXPR__ bool signbit(double __x) { return ::__signbit(__x); } // Notably missing above is nexttoward. We omit it because // ocml doesn't provide an implementation, and we don't want to be in the // business of implementing tricky libm functions in this header. // Other functions. -__DEVICE__ _Float16 fma(_Float16 __x, _Float16 __y, _Float16 __z) { +__DEVICE__ __CONSTEXPR__ _Float16 fma(_Float16 __x, _Float16 __y, + _Float16 __z) { return __ocml_fma_f16(__x, __y, __z); } -__DEVICE__ _Float16 pow(_Float16 __base, int __iexp) { +__DEVICE__ __CONSTEXPR__ _Float16 pow(_Float16 __base, int __iexp) { return __ocml_pown_f16(__base, __iexp); } +#ifndef __OPENMP_AMDGCN__ // BEGIN DEF_FUN and HIP_OVERLOAD // BEGIN DEF_FUN @@ -168,18 +188,19 @@ __DEVICE__ _Float16 pow(_Float16 __base, int __iexp) { // Define cmath functions with float argument and returns __retty. #define __DEF_FUN1(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x) { return __func##f(__x); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x) { return __func##f(__x); } // Define cmath functions with two float arguments and returns __retty. #define __DEF_FUN2(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x, float __y) { return __func##f(__x, __y); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x, float __y) { \ + return __func##f(__x, __y); \ + } // Define cmath functions with a float and an int argument and returns __retty. #define __DEF_FUN2_FI(__retty, __func) \ - __DEVICE__ \ - __retty __func(float __x, int __y) { return __func##f(__x, __y); } + __DEVICE__ __CONSTEXPR__ __retty __func(float __x, int __y) { \ + return __func##f(__x, __y); \ + } __DEF_FUN1(float, acos) __DEF_FUN1(float, acosh) @@ -426,7 +447,7 @@ class __promote : public __promote_imp<_A1, _A2, _A3> {}; // floor(double). #define __HIP_OVERLOAD1(__retty, __fn) \ template \ - __DEVICE__ \ + __DEVICE__ __CONSTEXPR__ \ typename __hip_enable_if<__hip::is_integral<__T>::value, __retty>::type \ __fn(__T __x) { \ return ::__fn((double)__x); \ @@ -438,7 +459,7 @@ class __promote : public __promote_imp<_A1, _A2, _A3> {}; #if __cplusplus >= 201103L #define __HIP_OVERLOAD2(__retty, __fn) \ template \ - __DEVICE__ typename __hip_enable_if< \ + __DEVICE__ __CONSTEXPR__ typename __hip_enable_if< \ __hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value, \ typename __hip::__promote<__T1, __T2>::type>::type \ __fn(__T1 __x, __T2 __y) { \ @@ -448,10 +469,11 @@ class __promote : public __promote_imp<_A1, _A2, _A3> {}; #else #define __HIP_OVERLOAD2(__retty, __fn) \ template \ - __DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && \ - __hip::is_arithmetic<__T2>::value, \ - __retty>::type \ - __fn(__T1 __x, __T2 __y) { \ + __DEVICE__ __CONSTEXPR__ \ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && \ + __hip::is_arithmetic<__T2>::value, \ + __retty>::type \ + __fn(__T1 __x, __T2 __y) { \ return __fn((double)__x, (double)__y); \ } #endif @@ -526,7 +548,7 @@ __HIP_OVERLOAD2(double, min) // Additional Overloads that don't quite match HIP_OVERLOAD. #if __cplusplus >= 201103L template -__DEVICE__ typename __hip_enable_if< +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if< __hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value && __hip::is_arithmetic<__T3>::value, typename __hip::__promote<__T1, __T2, __T3>::type>::type @@ -536,31 +558,32 @@ fma(__T1 __x, __T2 __y, __T3 __z) { } #else template -__DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && - __hip::is_arithmetic<__T2>::value && - __hip::is_arithmetic<__T3>::value, - double>::type -fma(__T1 __x, __T2 __y, __T3 __z) { +__DEVICE__ __CONSTEXPR__ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && + __hip::is_arithmetic<__T2>::value && + __hip::is_arithmetic<__T3>::value, + double>::type + fma(__T1 __x, __T2 __y, __T3 __z) { return ::fma((double)__x, (double)__y, (double)__z); } #endif template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type frexp(__T __x, int *__exp) { return ::frexp((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type ldexp(__T __x, int __exp) { return ::ldexp((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type modf(__T __x, double *__exp) { return ::modf((double)__x, __exp); @@ -568,7 +591,7 @@ __DEVICE__ #if __cplusplus >= 201103L template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && __hip::is_arithmetic<__T2>::value, typename __hip::__promote<__T1, __T2>::type>::type @@ -578,23 +601,24 @@ __DEVICE__ } #else template -__DEVICE__ typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && - __hip::is_arithmetic<__T2>::value, - double>::type -remquo(__T1 __x, __T2 __y, int *__quo) { +__DEVICE__ __CONSTEXPR__ + typename __hip_enable_if<__hip::is_arithmetic<__T1>::value && + __hip::is_arithmetic<__T2>::value, + double>::type + remquo(__T1 __x, __T2 __y, int *__quo) { return ::remquo((double)__x, (double)__y, __quo); } #endif template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type scalbln(__T __x, long int __exp) { return ::scalbln((double)__x, __exp); } template -__DEVICE__ +__DEVICE__ __CONSTEXPR__ typename __hip_enable_if<__hip::is_integral<__T>::value, double>::type scalbn(__T __x, int __exp) { return ::scalbn((double)__x, __exp); @@ -607,8 +631,10 @@ __DEVICE__ // END DEF_FUN and HIP_OVERLOAD +#endif // ifndef __OPENMP_AMDGCN__ #endif // defined(__cplusplus) +#ifndef __OPENMP_AMDGCN__ // Define these overloads inside the namespace our standard library uses. #if !defined(__HIPCC_RTC__) #ifdef _LIBCPP_BEGIN_NAMESPACE_STD @@ -781,22 +807,26 @@ _GLIBCXX_END_NAMESPACE_VERSION #if defined(__cplusplus) extern "C" { #endif // defined(__cplusplus) -__DEVICE__ __attribute__((overloadable)) double _Cosh(double x, double y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) double _Cosh(double x, + double y) { return cosh(x) * y; } -__DEVICE__ __attribute__((overloadable)) float _FCosh(float x, float y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) float _FCosh(float x, + float y) { return coshf(x) * y; } -__DEVICE__ __attribute__((overloadable)) short _Dtest(double *p) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) short _Dtest(double *p) { return fpclassify(*p); } -__DEVICE__ __attribute__((overloadable)) short _FDtest(float *p) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) short _FDtest(float *p) { return fpclassify(*p); } -__DEVICE__ __attribute__((overloadable)) double _Sinh(double x, double y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) double _Sinh(double x, + double y) { return sinh(x) * y; } -__DEVICE__ __attribute__((overloadable)) float _FSinh(float x, float y) { +__DEVICE__ __CONSTEXPR__ __attribute__((overloadable)) float _FSinh(float x, + float y) { return sinhf(x) * y; } #if defined(__cplusplus) @@ -804,7 +834,9 @@ __DEVICE__ __attribute__((overloadable)) float _FSinh(float x, float y) { #endif // defined(__cplusplus) #endif // defined(_MSC_VER) #endif // !defined(__HIPCC_RTC__) +#endif // ifndef __OPENMP_AMDGCN__ #pragma pop_macro("__DEVICE__") +#pragma pop_macro("__CONSTEXPR__") #endif // __CLANG_HIP_CMATH_H__ diff --git a/clang/lib/Headers/__clang_hip_math.h b/clang/lib/Headers/__clang_hip_math.h index 1f0982d92ef..ef7e087b832 100644 --- a/clang/lib/Headers/__clang_hip_math.h +++ b/clang/lib/Headers/__clang_hip_math.h @@ -9,7 +9,7 @@ #ifndef __CLANG_HIP_MATH_H__ #define __CLANG_HIP_MATH_H__ -#if !defined(__HIP__) +#if !defined(__HIP__) && !defined(__OPENMP_AMDGCN__) #error "This file is for HIP and OpenMP AMDGCN device compilation only." #endif @@ -19,18 +19,30 @@ #endif #include #include -#endif // __HIPCC_RTC__ +#ifdef __OPENMP_AMDGCN__ +#include +#endif +#endif // !defined(__HIPCC_RTC__) #pragma push_macro("__DEVICE__") + +#ifdef __OPENMP_AMDGCN__ +#define __DEVICE__ static inline __attribute__((always_inline, nothrow)) +#else #define __DEVICE__ static __device__ inline __attribute__((always_inline)) +#endif // A few functions return bool type starting only in C++11. #pragma push_macro("__RETURN_TYPE") +#ifdef __OPENMP_AMDGCN__ +#define __RETURN_TYPE int +#else #if defined(__cplusplus) #define __RETURN_TYPE bool #else #define __RETURN_TYPE int #endif +#endif // __OPENMP_AMDGCN__ #if defined (__cplusplus) && __cplusplus < 201103L // emulate static_assert on type sizes @@ -249,6 +261,9 @@ float fmodf(float __x, float __y) { return __ocml_fmod_f32(__x, __y); } __DEVICE__ float frexpf(float __x, int *__nptr) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_frexp_f32(__x, (__attribute__((address_space(5))) int *)&__tmp); *__nptr = __tmp; @@ -334,6 +349,9 @@ long int lroundf(float __x) { return __ocml_round_f32(__x); } __DEVICE__ float modff(float __x, float *__iptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_modf_f32(__x, (__attribute__((address_space(5))) float *)&__tmp); *__iptr = __tmp; @@ -414,6 +432,9 @@ float remainderf(float __x, float __y) { __DEVICE__ float remquof(float __x, float __y, int *__quo) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif float __r = __ocml_remquo_f32( __x, __y, (__attribute__((address_space(5))) int *)&__tmp); *__quo = __tmp; @@ -470,6 +491,9 @@ __RETURN_TYPE __signbitf(float __x) { return __ocml_signbit_f32(__x); } __DEVICE__ void sincosf(float __x, float *__sinptr, float *__cosptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincos_f32(__x, (__attribute__((address_space(5))) float *)&__tmp); *__cosptr = __tmp; @@ -478,6 +502,9 @@ void sincosf(float __x, float *__sinptr, float *__cosptr) { __DEVICE__ void sincospif(float __x, float *__sinptr, float *__cosptr) { float __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincospi_f32( __x, (__attribute__((address_space(5))) float *)&__tmp); *__cosptr = __tmp; @@ -790,6 +817,9 @@ double fmod(double __x, double __y) { return __ocml_fmod_f64(__x, __y); } __DEVICE__ double frexp(double __x, int *__nptr) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_frexp_f64(__x, (__attribute__((address_space(5))) int *)&__tmp); *__nptr = __tmp; @@ -874,6 +904,9 @@ long int lround(double __x) { return __ocml_round_f64(__x); } __DEVICE__ double modf(double __x, double *__iptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_modf_f64(__x, (__attribute__((address_space(5))) double *)&__tmp); *__iptr = __tmp; @@ -962,6 +995,9 @@ double remainder(double __x, double __y) { __DEVICE__ double remquo(double __x, double __y, int *__quo) { int __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif double __r = __ocml_remquo_f64( __x, __y, (__attribute__((address_space(5))) int *)&__tmp); *__quo = __tmp; @@ -1020,6 +1056,9 @@ double sin(double __x) { return __ocml_sin_f64(__x); } __DEVICE__ void sincos(double __x, double *__sinptr, double *__cosptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincos_f64( __x, (__attribute__((address_space(5))) double *)&__tmp); *__cosptr = __tmp; @@ -1028,6 +1067,9 @@ void sincos(double __x, double *__sinptr, double *__cosptr) { __DEVICE__ void sincospi(double __x, double *__sinptr, double *__cosptr) { double __tmp; +#ifdef __OPENMP_AMDGCN__ +#pragma omp allocate(__tmp) allocator(omp_thread_mem_alloc) +#endif *__sinptr = __ocml_sincospi_f64( __x, (__attribute__((address_space(5))) double *)&__tmp); *__cosptr = __tmp; @@ -1262,7 +1304,7 @@ float min(float __x, float __y) { return fminf(__x, __y); } __DEVICE__ double min(double __x, double __y) { return fmin(__x, __y); } -#if !defined(__HIPCC_RTC__) +#if !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) __host__ inline static int min(int __arg1, int __arg2) { return std::min(__arg1, __arg2); } @@ -1270,7 +1312,7 @@ __host__ inline static int min(int __arg1, int __arg2) { __host__ inline static int max(int __arg1, int __arg2) { return std::max(__arg1, __arg2); } -#endif // __HIPCC_RTC__ +#endif // !defined(__HIPCC_RTC__) && !defined(__OPENMP_AMDGCN__) #endif #pragma pop_macro("__DEVICE__") diff --git a/clang/lib/Headers/__wmmintrin_aes.h b/clang/lib/Headers/__wmmintrin_aes.h index f540319c7fd..3010b38711e 100644 --- a/clang/lib/Headers/__wmmintrin_aes.h +++ b/clang/lib/Headers/__wmmintrin_aes.h @@ -133,7 +133,7 @@ _mm_aesimc_si128(__m128i __V) /// An 8-bit round constant used to generate the AES encryption key. /// \returns A 128-bit round key for AES encryption. #define _mm_aeskeygenassist_si128(C, R) \ - (__m128i)__builtin_ia32_aeskeygenassist128((__v2di)(__m128i)(C), (int)(R)) + ((__m128i)__builtin_ia32_aeskeygenassist128((__v2di)(__m128i)(C), (int)(R))) #undef __DEFAULT_FN_ATTRS diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h index 0dd8c859366..fb808d7b0a4 100644 --- a/clang/lib/Headers/altivec.h +++ b/clang/lib/Headers/altivec.h @@ -1810,6 +1810,11 @@ vec_cmpeq(vector unsigned __int128 __a, vector unsigned __int128 __b) { return (vector bool __int128)__builtin_altivec_vcmpequq( (vector bool __int128)__a, (vector bool __int128)__b); } + +static __inline__ vector bool __int128 __ATTRS_o_ai +vec_cmpeq(vector bool __int128 __a, vector bool __int128 __b) { + return (vector bool __int128)__builtin_altivec_vcmpequq(__a, __b); +} #endif #ifdef __POWER9_VECTOR__ @@ -1887,6 +1892,11 @@ vec_cmpne(vector signed __int128 __a, vector signed __int128 __b) { return (vector bool __int128) ~(__builtin_altivec_vcmpequq( (vector bool __int128)__a, (vector bool __int128)__b)); } + +static __inline__ vector bool __int128 __ATTRS_o_ai +vec_cmpne(vector bool __int128 __a, vector bool __int128 __b) { + return (vector bool __int128) ~(__builtin_altivec_vcmpequq(__a, __b)); +} #endif /* vec_cmpnez */ @@ -2472,7 +2482,7 @@ vec_cmplt(vector unsigned long long __a, vector unsigned long long __b) { #ifdef __POWER8_VECTOR__ /* vec_popcnt */ -static __inline__ vector signed char __ATTRS_o_ai +static __inline__ vector unsigned char __ATTRS_o_ai vec_popcnt(vector signed char __a) { return __builtin_altivec_vpopcntb(__a); } @@ -2480,7 +2490,7 @@ static __inline__ vector unsigned char __ATTRS_o_ai vec_popcnt(vector unsigned char __a) { return __builtin_altivec_vpopcntb(__a); } -static __inline__ vector signed short __ATTRS_o_ai +static __inline__ vector unsigned short __ATTRS_o_ai vec_popcnt(vector signed short __a) { return __builtin_altivec_vpopcnth(__a); } @@ -2488,7 +2498,7 @@ static __inline__ vector unsigned short __ATTRS_o_ai vec_popcnt(vector unsigned short __a) { return __builtin_altivec_vpopcnth(__a); } -static __inline__ vector signed int __ATTRS_o_ai +static __inline__ vector unsigned int __ATTRS_o_ai vec_popcnt(vector signed int __a) { return __builtin_altivec_vpopcntw(__a); } @@ -2496,7 +2506,7 @@ static __inline__ vector unsigned int __ATTRS_o_ai vec_popcnt(vector unsigned int __a) { return __builtin_altivec_vpopcntw(__a); } -static __inline__ vector signed long long __ATTRS_o_ai +static __inline__ vector unsigned long long __ATTRS_o_ai vec_popcnt(vector signed long long __a) { return __builtin_altivec_vpopcntd(__a); } @@ -3049,13 +3059,10 @@ static __inline__ vector unsigned char __ATTRS_o_ai vec_xl_len_r(const unsigned char *__a, size_t __b) { vector unsigned char __res = (vector unsigned char)__builtin_vsx_lxvll(__a, (__b << 56)); -#ifdef __LITTLE_ENDIAN__ vector unsigned char __mask = (vector unsigned char)__builtin_altivec_lvsr(16 - __b, (int *)NULL); - __res = (vector unsigned char)__builtin_altivec_vperm_4si( + return (vector unsigned char)__builtin_altivec_vperm_4si( (vector int)__res, (vector int)__res, __mask); -#endif - return __res; } // vec_xst_len @@ -3130,15 +3137,11 @@ static __inline__ void __ATTRS_o_ai vec_xst_len(vector double __a, double *__b, static __inline__ void __ATTRS_o_ai vec_xst_len_r(vector unsigned char __a, unsigned char *__b, size_t __c) { -#ifdef __LITTLE_ENDIAN__ vector unsigned char __mask = (vector unsigned char)__builtin_altivec_lvsl(16 - __c, (int *)NULL); vector unsigned char __res = __builtin_altivec_vperm_4si((vector int)__a, (vector int)__a, __mask); return __builtin_vsx_stxvll((vector int)__res, __b, (__c << 56)); -#else - return __builtin_vsx_stxvll((vector int)__a, __b, (__c << 56)); -#endif } #endif #endif @@ -7106,6 +7109,11 @@ vec_orc(vector float __a, vector bool int __b) { return (vector float)((vector unsigned int)__a | ~__b); } +static __inline__ vector float __ATTRS_o_ai vec_orc(vector float __a, + vector float __b) { + return (vector float)((vector unsigned int)__a | ~(vector unsigned int)__b); +} + static __inline__ vector signed long long __ATTRS_o_ai vec_orc(vector signed long long __a, vector signed long long __b) { return __a | ~__b; @@ -7150,6 +7158,12 @@ static __inline__ vector double __ATTRS_o_ai vec_orc(vector bool long long __a, vector double __b) { return (vector double)(__a | ~(vector unsigned long long)__b); } + +static __inline__ vector double __ATTRS_o_ai vec_orc(vector double __a, + vector double __b) { + return (vector double)((vector bool long long)__a | + ~(vector unsigned long long)__b); +} #endif /* vec_vor */ @@ -8839,7 +8853,7 @@ static __inline__ vector long long __ATTRS_o_ai vec_sl(vector long long __a, vector unsigned long long __b) { return (vector long long)vec_sl((vector unsigned long long)__a, __b); } -#else +#elif defined(__VSX__) static __inline__ vector unsigned char __ATTRS_o_ai vec_vspltb(vector unsigned char __a, unsigned char __b); static __inline__ vector unsigned long long __ATTRS_o_ai @@ -8885,7 +8899,7 @@ static __inline__ vector long long __ATTRS_o_ai vec_sl(vector long long __a, vector unsigned long long __b) { return (vector long long)vec_sl((vector unsigned long long)__a, __b); } -#endif +#endif /* __VSX__ */ /* vec_vslb */ @@ -10350,7 +10364,7 @@ static __inline__ vector long long __ATTRS_o_ai vec_sr(vector long long __a, vector unsigned long long __b) { return (vector long long)vec_sr((vector unsigned long long)__a, __b); } -#else +#elif defined(__VSX__) static __inline__ vector unsigned long long __ATTRS_o_ai vec_sr(vector unsigned long long __a, vector unsigned long long __b) { __b %= (vector unsigned long long)(sizeof(unsigned long long) * __CHAR_BIT__); @@ -10394,7 +10408,7 @@ static __inline__ vector long long __ATTRS_o_ai vec_sr(vector long long __a, vector unsigned long long __b) { return (vector long long)vec_sr((vector unsigned long long)__a, __b); } -#endif +#endif /* __VSX__ */ /* vec_vsrb */ @@ -10480,7 +10494,7 @@ static __inline__ vector unsigned long long __ATTRS_o_ai vec_sra(vector unsigned long long __a, vector unsigned long long __b) { return (vector unsigned long long)((vector signed long long)__a >> __b); } -#else +#elif defined(__VSX__) static __inline__ vector signed long long __ATTRS_o_ai vec_sra(vector signed long long __a, vector unsigned long long __b) { __b %= (vector unsigned long long)(sizeof(unsigned long long) * __CHAR_BIT__); @@ -10492,7 +10506,7 @@ vec_sra(vector unsigned long long __a, vector unsigned long long __b) { __b %= (vector unsigned long long)(sizeof(unsigned long long) * __CHAR_BIT__); return (vector unsigned long long)((vector signed long long)__a >> __b); } -#endif +#endif /* __VSX__ */ /* vec_vsrab */ @@ -13441,74 +13455,74 @@ vec_vxor(vector bool long long __a, vector bool long long __b) { /* vec_extract */ static __inline__ signed char __ATTRS_o_ai vec_extract(vector signed char __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0xf]; } static __inline__ unsigned char __ATTRS_o_ai -vec_extract(vector unsigned char __a, unsigned int __b) { +vec_extract(vector unsigned char __a, signed int __b) { return __a[__b & 0xf]; } static __inline__ unsigned char __ATTRS_o_ai vec_extract(vector bool char __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0xf]; } static __inline__ signed short __ATTRS_o_ai vec_extract(vector signed short __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x7]; } static __inline__ unsigned short __ATTRS_o_ai -vec_extract(vector unsigned short __a, unsigned int __b) { +vec_extract(vector unsigned short __a, signed int __b) { return __a[__b & 0x7]; } static __inline__ unsigned short __ATTRS_o_ai vec_extract(vector bool short __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x7]; } static __inline__ signed int __ATTRS_o_ai vec_extract(vector signed int __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x3]; } static __inline__ unsigned int __ATTRS_o_ai vec_extract(vector unsigned int __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x3]; } static __inline__ unsigned int __ATTRS_o_ai vec_extract(vector bool int __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x3]; } #ifdef __VSX__ static __inline__ signed long long __ATTRS_o_ai -vec_extract(vector signed long long __a, unsigned int __b) { +vec_extract(vector signed long long __a, signed int __b) { return __a[__b & 0x1]; } static __inline__ unsigned long long __ATTRS_o_ai -vec_extract(vector unsigned long long __a, unsigned int __b) { +vec_extract(vector unsigned long long __a, signed int __b) { return __a[__b & 0x1]; } static __inline__ unsigned long long __ATTRS_o_ai -vec_extract(vector bool long long __a, unsigned int __b) { +vec_extract(vector bool long long __a, signed int __b) { return __a[__b & 0x1]; } static __inline__ double __ATTRS_o_ai vec_extract(vector double __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x1]; } #endif static __inline__ float __ATTRS_o_ai vec_extract(vector float __a, - unsigned int __b) { + signed int __b) { return __a[__b & 0x3]; } @@ -13568,82 +13582,82 @@ vec_extract_fp32_from_shortl(vector unsigned short __a) { static __inline__ vector signed char __ATTRS_o_ai vec_insert(signed char __a, vector signed char __b, int __c) { - __b[__c] = __a; + __b[__c & 0xF] = __a; return __b; } static __inline__ vector unsigned char __ATTRS_o_ai vec_insert(unsigned char __a, vector unsigned char __b, int __c) { - __b[__c] = __a; + __b[__c & 0xF] = __a; return __b; } static __inline__ vector bool char __ATTRS_o_ai vec_insert(unsigned char __a, vector bool char __b, int __c) { - __b[__c] = __a; + __b[__c & 0xF] = __a; return __b; } static __inline__ vector signed short __ATTRS_o_ai vec_insert(signed short __a, vector signed short __b, int __c) { - __b[__c] = __a; + __b[__c & 0x7] = __a; return __b; } static __inline__ vector unsigned short __ATTRS_o_ai vec_insert(unsigned short __a, vector unsigned short __b, int __c) { - __b[__c] = __a; + __b[__c & 0x7] = __a; return __b; } static __inline__ vector bool short __ATTRS_o_ai vec_insert(unsigned short __a, vector bool short __b, int __c) { - __b[__c] = __a; + __b[__c & 0x7] = __a; return __b; } static __inline__ vector signed int __ATTRS_o_ai vec_insert(signed int __a, vector signed int __b, int __c) { - __b[__c] = __a; + __b[__c & 0x3] = __a; return __b; } static __inline__ vector unsigned int __ATTRS_o_ai vec_insert(unsigned int __a, vector unsigned int __b, int __c) { - __b[__c] = __a; + __b[__c & 0x3] = __a; return __b; } static __inline__ vector bool int __ATTRS_o_ai vec_insert(unsigned int __a, vector bool int __b, int __c) { - __b[__c] = __a; + __b[__c & 0x3] = __a; return __b; } #ifdef __VSX__ static __inline__ vector signed long long __ATTRS_o_ai vec_insert(signed long long __a, vector signed long long __b, int __c) { - __b[__c] = __a; + __b[__c & 0x1] = __a; return __b; } static __inline__ vector unsigned long long __ATTRS_o_ai vec_insert(unsigned long long __a, vector unsigned long long __b, int __c) { - __b[__c] = __a; + __b[__c & 0x1] = __a; return __b; } static __inline__ vector bool long long __ATTRS_o_ai vec_insert(unsigned long long __a, vector bool long long __b, int __c) { - __b[__c] = __a; + __b[__c & 0x1] = __a; return __b; } static __inline__ vector double __ATTRS_o_ai vec_insert(double __a, vector double __b, int __c) { - __b[__c] = __a; + __b[__c & 0x1] = __a; return __b; } #endif @@ -13651,7 +13665,7 @@ static __inline__ vector double __ATTRS_o_ai vec_insert(double __a, static __inline__ vector float __ATTRS_o_ai vec_insert(float __a, vector float __b, int __c) { - __b[__c] = __a; + __b[__c & 0x3] = __a; return __b; } @@ -14812,42 +14826,43 @@ static __inline__ int __ATTRS_o_ai vec_all_eq(vector bool int __a, #ifdef __VSX__ static __inline__ int __ATTRS_o_ai vec_all_eq(vector signed long long __a, vector signed long long __b) { +#ifdef __POWER8_VECTOR__ return __builtin_altivec_vcmpequd_p(__CR6_LT, __a, __b); +#else + // No vcmpequd on Power7 so we xor the two vectors and compare against zero as + // 32-bit elements. + return vec_all_eq((vector signed int)vec_xor(__a, __b), (vector signed int)0); +#endif } static __inline__ int __ATTRS_o_ai vec_all_eq(vector long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, __a, (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_all_eq(vector unsigned long long __a, vector unsigned long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a, - (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_all_eq(vector unsigned long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a, - (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_all_eq(vector bool long long __a, vector long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a, - (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_all_eq(vector bool long long __a, vector unsigned long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a, - (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_all_eq(vector bool long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT, (vector long long)__a, - (vector long long)__b); + return vec_all_eq((vector signed long long)__a, (vector signed long long)__b); } #endif @@ -14877,6 +14892,11 @@ static __inline__ int __ATTRS_o_ai vec_all_eq(vector unsigned __int128 __a, vector unsigned __int128 __b) { return __builtin_altivec_vcmpequq_p(__CR6_LT, __a, __b); } + +static __inline__ int __ATTRS_o_ai vec_all_eq(vector bool __int128 __a, + vector bool __int128 __b) { + return __builtin_altivec_vcmpequq_p(__CR6_LT, __a, __b); +} #endif /* vec_all_ge */ @@ -15822,6 +15842,11 @@ static __inline__ int __ATTRS_o_ai vec_all_ne(vector unsigned __int128 __a, vector unsigned __int128 __b) { return __builtin_altivec_vcmpequq_p(__CR6_EQ, __a, __b); } + +static __inline__ int __ATTRS_o_ai vec_all_ne(vector bool __int128 __a, + vector bool __int128 __b) { + return __builtin_altivec_vcmpequq_p(__CR6_EQ, __a, __b); +} #endif /* vec_all_nge */ @@ -16111,6 +16136,11 @@ static __inline__ int __ATTRS_o_ai vec_any_eq(vector unsigned __int128 __a, vector unsigned __int128 __b) { return __builtin_altivec_vcmpequq_p(__CR6_EQ_REV, __a, __b); } + +static __inline__ int __ATTRS_o_ai vec_any_eq(vector bool __int128 __a, + vector bool __int128 __b) { + return __builtin_altivec_vcmpequq_p(__CR6_EQ_REV, __a, __b); +} #endif /* vec_any_ge */ @@ -17020,43 +17050,43 @@ static __inline__ int __ATTRS_o_ai vec_any_ne(vector bool int __a, #ifdef __VSX__ static __inline__ int __ATTRS_o_ai vec_any_ne(vector signed long long __a, vector signed long long __b) { +#ifdef __POWER8_VECTOR__ return __builtin_altivec_vcmpequd_p(__CR6_LT_REV, __a, __b); +#else + // Take advantage of the optimized sequence for vec_all_eq when vcmpequd is + // not available. + return !vec_all_eq(__a, __b); +#endif } static __inline__ int __ATTRS_o_ai vec_any_ne(vector unsigned long long __a, vector unsigned long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT_REV, (vector long long)__a, - (vector long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_any_ne(vector signed long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p(__CR6_LT_REV, __a, - (vector signed long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_any_ne(vector unsigned long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p( - __CR6_LT_REV, (vector signed long long)__a, (vector signed long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_any_ne(vector bool long long __a, vector signed long long __b) { - return __builtin_altivec_vcmpequd_p( - __CR6_LT_REV, (vector signed long long)__a, (vector signed long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_any_ne(vector bool long long __a, vector unsigned long long __b) { - return __builtin_altivec_vcmpequd_p( - __CR6_LT_REV, (vector signed long long)__a, (vector signed long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } static __inline__ int __ATTRS_o_ai vec_any_ne(vector bool long long __a, vector bool long long __b) { - return __builtin_altivec_vcmpequd_p( - __CR6_LT_REV, (vector signed long long)__a, (vector signed long long)__b); + return vec_any_ne((vector signed long long)__a, (vector signed long long)__b); } #endif @@ -17086,6 +17116,11 @@ static __inline__ int __ATTRS_o_ai vec_any_ne(vector unsigned __int128 __a, vector unsigned __int128 __b) { return __builtin_altivec_vcmpequq_p(__CR6_LT_REV, __a, __b); } + +static __inline__ int __ATTRS_o_ai vec_any_ne(vector bool __int128 __a, + vector bool __int128 __b) { + return __builtin_altivec_vcmpequq_p(__CR6_LT_REV, __a, __b); +} #endif /* vec_any_nge */ @@ -17203,6 +17238,7 @@ provided. #define vec_ncipher_be __builtin_altivec_crypto_vncipher #define vec_ncipherlast_be __builtin_altivec_crypto_vncipherlast +#ifdef __VSX__ static __inline__ vector unsigned long long __attribute__((__always_inline__)) __builtin_crypto_vsbox(vector unsigned long long __a) { return __builtin_altivec_crypto_vsbox(__a); @@ -17231,6 +17267,7 @@ __builtin_crypto_vncipherlast(vector unsigned long long __a, vector unsigned long long __b) { return __builtin_altivec_crypto_vncipherlast(__a, __b); } +#endif /* __VSX__ */ #define __builtin_crypto_vshasigmad __builtin_altivec_crypto_vshasigmad #define __builtin_crypto_vshasigmaw __builtin_altivec_crypto_vshasigmaw @@ -17346,12 +17383,22 @@ vec_vbpermq(vector unsigned char __a, vector unsigned char __b) { } #if defined(__powerpc64__) && defined(__SIZEOF_INT128__) -static __inline__ vector unsigned long long __attribute__((__always_inline__)) +static __inline__ vector unsigned long long __ATTRS_o_ai vec_bperm(vector unsigned __int128 __a, vector unsigned char __b) { return __builtin_altivec_vbpermq((vector unsigned char)__a, (vector unsigned char)__b); } #endif +static __inline__ vector unsigned char __ATTRS_o_ai +vec_bperm(vector unsigned char __a, vector unsigned char __b) { + return __builtin_altivec_vbpermq(__a, __b); +} +#endif // __POWER8_VECTOR__ +#ifdef __POWER9_VECTOR__ +static __inline__ vector unsigned long long __ATTRS_o_ai +vec_bperm(vector unsigned long long __a, vector unsigned char __b) { + return __builtin_altivec_vbpermd(__a, __b); +} #endif @@ -18198,13 +18245,13 @@ vec_expandm(vector unsigned __int128 __a) { #define vec_cntm(__a, __mp) \ _Generic((__a), vector unsigned char \ - : __builtin_altivec_vcntmbb((__a), (unsigned int)(__mp)), \ + : __builtin_altivec_vcntmbb((__a), (unsigned char)(__mp)), \ vector unsigned short \ - : __builtin_altivec_vcntmbh((__a), (unsigned int)(__mp)), \ + : __builtin_altivec_vcntmbh((__a), (unsigned char)(__mp)), \ vector unsigned int \ - : __builtin_altivec_vcntmbw((__a), (unsigned int)(__mp)), \ + : __builtin_altivec_vcntmbw((__a), (unsigned char)(__mp)), \ vector unsigned long long \ - : __builtin_altivec_vcntmbd((__a), (unsigned int)(__mp))) + : __builtin_altivec_vcntmbd((__a), (unsigned char)(__mp))) /* vec_gen[b|h|w|d|q]m */ @@ -18319,10 +18366,10 @@ vec_cfuge(vector unsigned long long __a, vector unsigned long long __b) { : __builtin_vsx_xxgenpcvdm((__a), (int)(__imm))) #endif /* __VSX__ */ -/* vec_clrl */ +/* vec_clr_first */ static __inline__ vector signed char __ATTRS_o_ai -vec_clrl(vector signed char __a, unsigned int __n) { +vec_clr_first(vector signed char __a, unsigned int __n) { #ifdef __LITTLE_ENDIAN__ return __builtin_altivec_vclrrb(__a, __n); #else @@ -18331,7 +18378,7 @@ vec_clrl(vector signed char __a, unsigned int __n) { } static __inline__ vector unsigned char __ATTRS_o_ai -vec_clrl(vector unsigned char __a, unsigned int __n) { +vec_clr_first(vector unsigned char __a, unsigned int __n) { #ifdef __LITTLE_ENDIAN__ return __builtin_altivec_vclrrb((vector signed char)__a, __n); #else @@ -18339,10 +18386,10 @@ vec_clrl(vector unsigned char __a, unsigned int __n) { #endif } -/* vec_clrr */ +/* vec_clr_last */ static __inline__ vector signed char __ATTRS_o_ai -vec_clrr(vector signed char __a, unsigned int __n) { +vec_clr_last(vector signed char __a, unsigned int __n) { #ifdef __LITTLE_ENDIAN__ return __builtin_altivec_vclrlb(__a, __n); #else @@ -18351,7 +18398,7 @@ vec_clrr(vector signed char __a, unsigned int __n) { } static __inline__ vector unsigned char __ATTRS_o_ai -vec_clrr(vector unsigned char __a, unsigned int __n) { +vec_clr_last(vector unsigned char __a, unsigned int __n) { #ifdef __LITTLE_ENDIAN__ return __builtin_altivec_vclrlb((vector signed char)__a, __n); #else @@ -18733,36 +18780,39 @@ static __inline__ vector double __ATTRS_o_ai vec_splatid(const float __a) { static __inline__ vector signed int __ATTRS_o_ai vec_splati_ins( vector signed int __a, const unsigned int __b, const signed int __c) { + const unsigned int __d = __b & 0x01; #ifdef __LITTLE_ENDIAN__ - __a[1 - __b] = __c; - __a[3 - __b] = __c; + __a[1 - __d] = __c; + __a[3 - __d] = __c; #else - __a[__b] = __c; - __a[2 + __b] = __c; + __a[__d] = __c; + __a[2 + __d] = __c; #endif return __a; } static __inline__ vector unsigned int __ATTRS_o_ai vec_splati_ins( vector unsigned int __a, const unsigned int __b, const unsigned int __c) { + const unsigned int __d = __b & 0x01; #ifdef __LITTLE_ENDIAN__ - __a[1 - __b] = __c; - __a[3 - __b] = __c; + __a[1 - __d] = __c; + __a[3 - __d] = __c; #else - __a[__b] = __c; - __a[2 + __b] = __c; + __a[__d] = __c; + __a[2 + __d] = __c; #endif return __a; } static __inline__ vector float __ATTRS_o_ai vec_splati_ins(vector float __a, const unsigned int __b, const float __c) { + const unsigned int __d = __b & 0x01; #ifdef __LITTLE_ENDIAN__ - __a[1 - __b] = __c; - __a[3 - __b] = __c; + __a[1 - __d] = __c; + __a[3 - __d] = __c; #else - __a[__b] = __c; - __a[2 + __b] = __c; + __a[__d] = __c; + __a[2 + __d] = __c; #endif return __a; } diff --git a/clang/lib/Headers/ammintrin.h b/clang/lib/Headers/ammintrin.h index 3806be6ebc4..1af2096595c 100644 --- a/clang/lib/Headers/ammintrin.h +++ b/clang/lib/Headers/ammintrin.h @@ -10,6 +10,10 @@ #ifndef __AMMINTRIN_H #define __AMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include /* Define the default attributes for the functions in this file. */ diff --git a/clang/lib/Headers/amxintrin.h b/clang/lib/Headers/amxintrin.h index ec601a58e7c..4940666e808 100644 --- a/clang/lib/Headers/amxintrin.h +++ b/clang/lib/Headers/amxintrin.h @@ -314,8 +314,8 @@ typedef struct __tile1024i_str { /// \param stride /// The stride between the rows' data to be loaded in memory. __DEFAULT_FN_ATTRS_TILE -static void __tile_loadd(__tile1024i *dst, const void *base, - __SIZE_TYPE__ stride) { +static __inline__ void __tile_loadd(__tile1024i *dst, const void *base, + __SIZE_TYPE__ stride) { dst->tile = _tile_loadd_internal(dst->row, dst->col, base, stride); } @@ -335,8 +335,8 @@ static void __tile_loadd(__tile1024i *dst, const void *base, /// \param stride /// The stride between the rows' data to be loaded in memory. __DEFAULT_FN_ATTRS_TILE -static void __tile_stream_loadd(__tile1024i *dst, const void *base, - __SIZE_TYPE__ stride) { +static __inline__ void __tile_stream_loadd(__tile1024i *dst, const void *base, + __SIZE_TYPE__ stride) { dst->tile = _tile_loaddt1_internal(dst->row, dst->col, base, stride); } @@ -357,8 +357,8 @@ static void __tile_stream_loadd(__tile1024i *dst, const void *base, /// \param src1 /// The 2nd source tile. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_INT8 -static void __tile_dpbssd(__tile1024i *dst, __tile1024i src0, - __tile1024i src1) { +static __inline__ void __tile_dpbssd(__tile1024i *dst, __tile1024i src0, + __tile1024i src1) { dst->tile = _tile_dpbssd_internal(src0.row, src1.col, src0.col, dst->tile, src0.tile, src1.tile); } @@ -380,8 +380,8 @@ static void __tile_dpbssd(__tile1024i *dst, __tile1024i src0, /// \param src1 /// The 2nd source tile. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_INT8 -static void __tile_dpbsud(__tile1024i *dst, __tile1024i src0, - __tile1024i src1) { +static __inline__ void __tile_dpbsud(__tile1024i *dst, __tile1024i src0, + __tile1024i src1) { dst->tile = _tile_dpbsud_internal(src0.row, src1.col, src0.col, dst->tile, src0.tile, src1.tile); } @@ -403,8 +403,8 @@ static void __tile_dpbsud(__tile1024i *dst, __tile1024i src0, /// \param src1 /// The 2nd source tile. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_INT8 -static void __tile_dpbusd(__tile1024i *dst, __tile1024i src0, - __tile1024i src1) { +static __inline__ void __tile_dpbusd(__tile1024i *dst, __tile1024i src0, + __tile1024i src1) { dst->tile = _tile_dpbusd_internal(src0.row, src1.col, src0.col, dst->tile, src0.tile, src1.tile); } @@ -426,8 +426,8 @@ static void __tile_dpbusd(__tile1024i *dst, __tile1024i src0, /// \param src1 /// The 2nd source tile. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_INT8 -static void __tile_dpbuud(__tile1024i *dst, __tile1024i src0, - __tile1024i src1) { +static __inline__ void __tile_dpbuud(__tile1024i *dst, __tile1024i src0, + __tile1024i src1) { dst->tile = _tile_dpbuud_internal(src0.row, src1.col, src0.col, dst->tile, src0.tile, src1.tile); } @@ -446,7 +446,8 @@ static void __tile_dpbuud(__tile1024i *dst, __tile1024i src0, /// \param stride /// The stride between the rows' data to be stored in memory. __DEFAULT_FN_ATTRS_TILE -static void __tile_stored(void *base, __SIZE_TYPE__ stride, __tile1024i src) { +static __inline__ void __tile_stored(void *base, __SIZE_TYPE__ stride, + __tile1024i src) { _tile_stored_internal(src.row, src.col, base, stride, src.tile); } @@ -459,7 +460,7 @@ static void __tile_stored(void *base, __SIZE_TYPE__ stride, __tile1024i src) { /// \param dst /// The destination tile to be zero. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_TILE -static void __tile_zero(__tile1024i *dst) { +static __inline__ void __tile_zero(__tile1024i *dst) { dst->tile = __builtin_ia32_tilezero_internal(dst->row, dst->col); } @@ -479,8 +480,8 @@ static void __tile_zero(__tile1024i *dst) { /// \param src1 /// The 2nd source tile. Max size is 1024 Bytes. __DEFAULT_FN_ATTRS_BF16 -static void __tile_dpbf16ps(__tile1024i *dst, __tile1024i src0, - __tile1024i src1) { +static __inline__ void __tile_dpbf16ps(__tile1024i *dst, __tile1024i src0, + __tile1024i src1) { dst->tile = _tile_dpbf16ps_internal(src0.row, src1.col, src0.col, dst->tile, src0.tile, src1.tile); } diff --git a/clang/lib/Headers/avx2intrin.h b/clang/lib/Headers/avx2intrin.h index cc16720949e..5064c87c2bb 100644 --- a/clang/lib/Headers/avx2intrin.h +++ b/clang/lib/Headers/avx2intrin.h @@ -20,8 +20,8 @@ /* SSE4 Multiple Packed Sums of Absolute Difference. */ #define _mm256_mpsadbw_epu8(X, Y, M) \ - (__m256i)__builtin_ia32_mpsadbw256((__v32qi)(__m256i)(X), \ - (__v32qi)(__m256i)(Y), (int)(M)) + ((__m256i)__builtin_ia32_mpsadbw256((__v32qi)(__m256i)(X), \ + (__v32qi)(__m256i)(Y), (int)(M))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_abs_epi8(__m256i __a) @@ -114,8 +114,8 @@ _mm256_adds_epu16(__m256i __a, __m256i __b) } #define _mm256_alignr_epi8(a, b, n) \ - (__m256i)__builtin_ia32_palignr256((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (n)) + ((__m256i)__builtin_ia32_palignr256((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (n))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_and_si256(__m256i __a, __m256i __b) @@ -149,8 +149,8 @@ _mm256_blendv_epi8(__m256i __V1, __m256i __V2, __m256i __M) } #define _mm256_blend_epi16(V1, V2, M) \ - (__m256i)__builtin_ia32_pblendw256((__v16hi)(__m256i)(V1), \ - (__v16hi)(__m256i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_pblendw256((__v16hi)(__m256i)(V1), \ + (__v16hi)(__m256i)(V2), (int)(M))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_cmpeq_epi8(__m256i __a, __m256i __b) @@ -467,13 +467,13 @@ _mm256_shuffle_epi8(__m256i __a, __m256i __b) } #define _mm256_shuffle_epi32(a, imm) \ - (__m256i)__builtin_ia32_pshufd256((__v8si)(__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_pshufd256((__v8si)(__m256i)(a), (int)(imm))) #define _mm256_shufflehi_epi16(a, imm) \ - (__m256i)__builtin_ia32_pshufhw256((__v16hi)(__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_pshufhw256((__v16hi)(__m256i)(a), (int)(imm))) #define _mm256_shufflelo_epi16(a, imm) \ - (__m256i)__builtin_ia32_pshuflw256((__v16hi)(__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_pshuflw256((__v16hi)(__m256i)(a), (int)(imm))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sign_epi8(__m256i __a, __m256i __b) @@ -494,10 +494,10 @@ _mm256_sign_epi32(__m256i __a, __m256i __b) } #define _mm256_slli_si256(a, imm) \ - (__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm))) #define _mm256_bslli_epi128(a, imm) \ - (__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_pslldqi256_byteshift((__v4di)(__m256i)(a), (int)(imm))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_slli_epi16(__m256i __a, int __count) @@ -560,10 +560,10 @@ _mm256_sra_epi32(__m256i __a, __m128i __count) } #define _mm256_srli_si256(a, imm) \ - (__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm))) #define _mm256_bsrli_epi128(a, imm) \ - (__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm)) + ((__m256i)__builtin_ia32_psrldqi256_byteshift((__m256i)(a), (int)(imm))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_srli_epi16(__m256i __a, int __count) @@ -743,12 +743,12 @@ _mm256_broadcastsi128_si256(__m128i __X) #define _mm_broadcastsi128_si256(X) _mm256_broadcastsi128_si256(X) #define _mm_blend_epi32(V1, V2, M) \ - (__m128i)__builtin_ia32_pblendd128((__v4si)(__m128i)(V1), \ - (__v4si)(__m128i)(V2), (int)(M)) + ((__m128i)__builtin_ia32_pblendd128((__v4si)(__m128i)(V1), \ + (__v4si)(__m128i)(V2), (int)(M))) #define _mm256_blend_epi32(V1, V2, M) \ - (__m256i)__builtin_ia32_pblendd256((__v8si)(__m256i)(V1), \ - (__v8si)(__m256i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_pblendd256((__v8si)(__m256i)(V1), \ + (__v8si)(__m256i)(V2), (int)(M))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_broadcastb_epi8(__m128i __X) @@ -806,7 +806,7 @@ _mm256_permutevar8x32_epi32(__m256i __a, __m256i __b) } #define _mm256_permute4x64_pd(V, M) \ - (__m256d)__builtin_ia32_permdf256((__v4df)(__m256d)(V), (int)(M)) + ((__m256d)__builtin_ia32_permdf256((__v4df)(__m256d)(V), (int)(M))) static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_permutevar8x32_ps(__m256 __a, __m256i __b) @@ -815,17 +815,17 @@ _mm256_permutevar8x32_ps(__m256 __a, __m256i __b) } #define _mm256_permute4x64_epi64(V, M) \ - (__m256i)__builtin_ia32_permdi256((__v4di)(__m256i)(V), (int)(M)) + ((__m256i)__builtin_ia32_permdi256((__v4di)(__m256i)(V), (int)(M))) #define _mm256_permute2x128_si256(V1, V2, M) \ - (__m256i)__builtin_ia32_permti256((__m256i)(V1), (__m256i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_permti256((__m256i)(V1), (__m256i)(V2), (int)(M))) #define _mm256_extracti128_si256(V, M) \ - (__m128i)__builtin_ia32_extract128i256((__v4di)(__m256i)(V), (int)(M)) + ((__m128i)__builtin_ia32_extract128i256((__v4di)(__m256i)(V), (int)(M))) #define _mm256_inserti128_si256(V1, V2, M) \ - (__m256i)__builtin_ia32_insert128i256((__v4di)(__m256i)(V1), \ - (__v2di)(__m128i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_insert128i256((__v4di)(__m256i)(V1), \ + (__v2di)(__m128i)(V2), (int)(M))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskload_epi32(int const *__X, __m256i __M) @@ -936,211 +936,211 @@ _mm_srlv_epi64(__m128i __X, __m128i __Y) } #define _mm_mask_i32gather_pd(a, m, i, mask, s) \ - (__m128d)__builtin_ia32_gatherd_pd((__v2df)(__m128i)(a), \ - (double const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v2df)(__m128d)(mask), (s)) + ((__m128d)__builtin_ia32_gatherd_pd((__v2df)(__m128i)(a), \ + (double const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v2df)(__m128d)(mask), (s))) #define _mm256_mask_i32gather_pd(a, m, i, mask, s) \ - (__m256d)__builtin_ia32_gatherd_pd256((__v4df)(__m256d)(a), \ - (double const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4df)(__m256d)(mask), (s)) + ((__m256d)__builtin_ia32_gatherd_pd256((__v4df)(__m256d)(a), \ + (double const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4df)(__m256d)(mask), (s))) #define _mm_mask_i64gather_pd(a, m, i, mask, s) \ - (__m128d)__builtin_ia32_gatherq_pd((__v2df)(__m128d)(a), \ - (double const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v2df)(__m128d)(mask), (s)) + ((__m128d)__builtin_ia32_gatherq_pd((__v2df)(__m128d)(a), \ + (double const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v2df)(__m128d)(mask), (s))) #define _mm256_mask_i64gather_pd(a, m, i, mask, s) \ - (__m256d)__builtin_ia32_gatherq_pd256((__v4df)(__m256d)(a), \ - (double const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4df)(__m256d)(mask), (s)) + ((__m256d)__builtin_ia32_gatherq_pd256((__v4df)(__m256d)(a), \ + (double const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4df)(__m256d)(mask), (s))) #define _mm_mask_i32gather_ps(a, m, i, mask, s) \ - (__m128)__builtin_ia32_gatherd_ps((__v4sf)(__m128)(a), \ - (float const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4sf)(__m128)(mask), (s)) + ((__m128)__builtin_ia32_gatherd_ps((__v4sf)(__m128)(a), \ + (float const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4sf)(__m128)(mask), (s))) #define _mm256_mask_i32gather_ps(a, m, i, mask, s) \ - (__m256)__builtin_ia32_gatherd_ps256((__v8sf)(__m256)(a), \ - (float const *)(m), \ - (__v8si)(__m256i)(i), \ - (__v8sf)(__m256)(mask), (s)) + ((__m256)__builtin_ia32_gatherd_ps256((__v8sf)(__m256)(a), \ + (float const *)(m), \ + (__v8si)(__m256i)(i), \ + (__v8sf)(__m256)(mask), (s))) #define _mm_mask_i64gather_ps(a, m, i, mask, s) \ - (__m128)__builtin_ia32_gatherq_ps((__v4sf)(__m128)(a), \ - (float const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v4sf)(__m128)(mask), (s)) + ((__m128)__builtin_ia32_gatherq_ps((__v4sf)(__m128)(a), \ + (float const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v4sf)(__m128)(mask), (s))) #define _mm256_mask_i64gather_ps(a, m, i, mask, s) \ - (__m128)__builtin_ia32_gatherq_ps256((__v4sf)(__m128)(a), \ - (float const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4sf)(__m128)(mask), (s)) + ((__m128)__builtin_ia32_gatherq_ps256((__v4sf)(__m128)(a), \ + (float const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4sf)(__m128)(mask), (s))) #define _mm_mask_i32gather_epi32(a, m, i, mask, s) \ - (__m128i)__builtin_ia32_gatherd_d((__v4si)(__m128i)(a), \ - (int const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4si)(__m128i)(mask), (s)) + ((__m128i)__builtin_ia32_gatherd_d((__v4si)(__m128i)(a), \ + (int const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4si)(__m128i)(mask), (s))) #define _mm256_mask_i32gather_epi32(a, m, i, mask, s) \ - (__m256i)__builtin_ia32_gatherd_d256((__v8si)(__m256i)(a), \ - (int const *)(m), \ - (__v8si)(__m256i)(i), \ - (__v8si)(__m256i)(mask), (s)) + ((__m256i)__builtin_ia32_gatherd_d256((__v8si)(__m256i)(a), \ + (int const *)(m), \ + (__v8si)(__m256i)(i), \ + (__v8si)(__m256i)(mask), (s))) #define _mm_mask_i64gather_epi32(a, m, i, mask, s) \ - (__m128i)__builtin_ia32_gatherq_d((__v4si)(__m128i)(a), \ - (int const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v4si)(__m128i)(mask), (s)) + ((__m128i)__builtin_ia32_gatherq_d((__v4si)(__m128i)(a), \ + (int const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v4si)(__m128i)(mask), (s))) #define _mm256_mask_i64gather_epi32(a, m, i, mask, s) \ - (__m128i)__builtin_ia32_gatherq_d256((__v4si)(__m128i)(a), \ - (int const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4si)(__m128i)(mask), (s)) + ((__m128i)__builtin_ia32_gatherq_d256((__v4si)(__m128i)(a), \ + (int const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4si)(__m128i)(mask), (s))) #define _mm_mask_i32gather_epi64(a, m, i, mask, s) \ - (__m128i)__builtin_ia32_gatherd_q((__v2di)(__m128i)(a), \ - (long long const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v2di)(__m128i)(mask), (s)) + ((__m128i)__builtin_ia32_gatherd_q((__v2di)(__m128i)(a), \ + (long long const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v2di)(__m128i)(mask), (s))) #define _mm256_mask_i32gather_epi64(a, m, i, mask, s) \ - (__m256i)__builtin_ia32_gatherd_q256((__v4di)(__m256i)(a), \ - (long long const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4di)(__m256i)(mask), (s)) + ((__m256i)__builtin_ia32_gatherd_q256((__v4di)(__m256i)(a), \ + (long long const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4di)(__m256i)(mask), (s))) #define _mm_mask_i64gather_epi64(a, m, i, mask, s) \ - (__m128i)__builtin_ia32_gatherq_q((__v2di)(__m128i)(a), \ - (long long const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v2di)(__m128i)(mask), (s)) + ((__m128i)__builtin_ia32_gatherq_q((__v2di)(__m128i)(a), \ + (long long const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v2di)(__m128i)(mask), (s))) #define _mm256_mask_i64gather_epi64(a, m, i, mask, s) \ - (__m256i)__builtin_ia32_gatherq_q256((__v4di)(__m256i)(a), \ - (long long const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4di)(__m256i)(mask), (s)) + ((__m256i)__builtin_ia32_gatherq_q256((__v4di)(__m256i)(a), \ + (long long const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4di)(__m256i)(mask), (s))) #define _mm_i32gather_pd(m, i, s) \ - (__m128d)__builtin_ia32_gatherd_pd((__v2df)_mm_undefined_pd(), \ - (double const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \ - _mm_setzero_pd()), \ - (s)) + ((__m128d)__builtin_ia32_gatherd_pd((__v2df)_mm_undefined_pd(), \ + (double const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \ + _mm_setzero_pd()), \ + (s))) #define _mm256_i32gather_pd(m, i, s) \ - (__m256d)__builtin_ia32_gatherd_pd256((__v4df)_mm256_undefined_pd(), \ - (double const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \ - _mm256_setzero_pd(), \ - _CMP_EQ_OQ), \ - (s)) + ((__m256d)__builtin_ia32_gatherd_pd256((__v4df)_mm256_undefined_pd(), \ + (double const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \ + _mm256_setzero_pd(), \ + _CMP_EQ_OQ), \ + (s))) #define _mm_i64gather_pd(m, i, s) \ - (__m128d)__builtin_ia32_gatherq_pd((__v2df)_mm_undefined_pd(), \ - (double const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \ - _mm_setzero_pd()), \ - (s)) + ((__m128d)__builtin_ia32_gatherq_pd((__v2df)_mm_undefined_pd(), \ + (double const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v2df)_mm_cmpeq_pd(_mm_setzero_pd(), \ + _mm_setzero_pd()), \ + (s))) #define _mm256_i64gather_pd(m, i, s) \ - (__m256d)__builtin_ia32_gatherq_pd256((__v4df)_mm256_undefined_pd(), \ - (double const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \ - _mm256_setzero_pd(), \ - _CMP_EQ_OQ), \ - (s)) + ((__m256d)__builtin_ia32_gatherq_pd256((__v4df)_mm256_undefined_pd(), \ + (double const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4df)_mm256_cmp_pd(_mm256_setzero_pd(), \ + _mm256_setzero_pd(), \ + _CMP_EQ_OQ), \ + (s))) #define _mm_i32gather_ps(m, i, s) \ - (__m128)__builtin_ia32_gatherd_ps((__v4sf)_mm_undefined_ps(), \ - (float const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ - _mm_setzero_ps()), \ - (s)) + ((__m128)__builtin_ia32_gatherd_ps((__v4sf)_mm_undefined_ps(), \ + (float const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ + _mm_setzero_ps()), \ + (s))) #define _mm256_i32gather_ps(m, i, s) \ - (__m256)__builtin_ia32_gatherd_ps256((__v8sf)_mm256_undefined_ps(), \ - (float const *)(m), \ - (__v8si)(__m256i)(i), \ - (__v8sf)_mm256_cmp_ps(_mm256_setzero_ps(), \ - _mm256_setzero_ps(), \ - _CMP_EQ_OQ), \ - (s)) + ((__m256)__builtin_ia32_gatherd_ps256((__v8sf)_mm256_undefined_ps(), \ + (float const *)(m), \ + (__v8si)(__m256i)(i), \ + (__v8sf)_mm256_cmp_ps(_mm256_setzero_ps(), \ + _mm256_setzero_ps(), \ + _CMP_EQ_OQ), \ + (s))) #define _mm_i64gather_ps(m, i, s) \ - (__m128)__builtin_ia32_gatherq_ps((__v4sf)_mm_undefined_ps(), \ - (float const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ - _mm_setzero_ps()), \ - (s)) + ((__m128)__builtin_ia32_gatherq_ps((__v4sf)_mm_undefined_ps(), \ + (float const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ + _mm_setzero_ps()), \ + (s))) #define _mm256_i64gather_ps(m, i, s) \ - (__m128)__builtin_ia32_gatherq_ps256((__v4sf)_mm_undefined_ps(), \ - (float const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ - _mm_setzero_ps()), \ - (s)) + ((__m128)__builtin_ia32_gatherq_ps256((__v4sf)_mm_undefined_ps(), \ + (float const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4sf)_mm_cmpeq_ps(_mm_setzero_ps(), \ + _mm_setzero_ps()), \ + (s))) #define _mm_i32gather_epi32(m, i, s) \ - (__m128i)__builtin_ia32_gatherd_d((__v4si)_mm_undefined_si128(), \ - (int const *)(m), (__v4si)(__m128i)(i), \ - (__v4si)_mm_set1_epi32(-1), (s)) + ((__m128i)__builtin_ia32_gatherd_d((__v4si)_mm_undefined_si128(), \ + (int const *)(m), (__v4si)(__m128i)(i), \ + (__v4si)_mm_set1_epi32(-1), (s))) #define _mm256_i32gather_epi32(m, i, s) \ - (__m256i)__builtin_ia32_gatherd_d256((__v8si)_mm256_undefined_si256(), \ - (int const *)(m), (__v8si)(__m256i)(i), \ - (__v8si)_mm256_set1_epi32(-1), (s)) + ((__m256i)__builtin_ia32_gatherd_d256((__v8si)_mm256_undefined_si256(), \ + (int const *)(m), (__v8si)(__m256i)(i), \ + (__v8si)_mm256_set1_epi32(-1), (s))) #define _mm_i64gather_epi32(m, i, s) \ - (__m128i)__builtin_ia32_gatherq_d((__v4si)_mm_undefined_si128(), \ - (int const *)(m), (__v2di)(__m128i)(i), \ - (__v4si)_mm_set1_epi32(-1), (s)) + ((__m128i)__builtin_ia32_gatherq_d((__v4si)_mm_undefined_si128(), \ + (int const *)(m), (__v2di)(__m128i)(i), \ + (__v4si)_mm_set1_epi32(-1), (s))) #define _mm256_i64gather_epi32(m, i, s) \ - (__m128i)__builtin_ia32_gatherq_d256((__v4si)_mm_undefined_si128(), \ - (int const *)(m), (__v4di)(__m256i)(i), \ - (__v4si)_mm_set1_epi32(-1), (s)) + ((__m128i)__builtin_ia32_gatherq_d256((__v4si)_mm_undefined_si128(), \ + (int const *)(m), (__v4di)(__m256i)(i), \ + (__v4si)_mm_set1_epi32(-1), (s))) #define _mm_i32gather_epi64(m, i, s) \ - (__m128i)__builtin_ia32_gatherd_q((__v2di)_mm_undefined_si128(), \ - (long long const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v2di)_mm_set1_epi64x(-1), (s)) + ((__m128i)__builtin_ia32_gatherd_q((__v2di)_mm_undefined_si128(), \ + (long long const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v2di)_mm_set1_epi64x(-1), (s))) #define _mm256_i32gather_epi64(m, i, s) \ - (__m256i)__builtin_ia32_gatherd_q256((__v4di)_mm256_undefined_si256(), \ - (long long const *)(m), \ - (__v4si)(__m128i)(i), \ - (__v4di)_mm256_set1_epi64x(-1), (s)) + ((__m256i)__builtin_ia32_gatherd_q256((__v4di)_mm256_undefined_si256(), \ + (long long const *)(m), \ + (__v4si)(__m128i)(i), \ + (__v4di)_mm256_set1_epi64x(-1), (s))) #define _mm_i64gather_epi64(m, i, s) \ - (__m128i)__builtin_ia32_gatherq_q((__v2di)_mm_undefined_si128(), \ - (long long const *)(m), \ - (__v2di)(__m128i)(i), \ - (__v2di)_mm_set1_epi64x(-1), (s)) + ((__m128i)__builtin_ia32_gatherq_q((__v2di)_mm_undefined_si128(), \ + (long long const *)(m), \ + (__v2di)(__m128i)(i), \ + (__v2di)_mm_set1_epi64x(-1), (s))) #define _mm256_i64gather_epi64(m, i, s) \ - (__m256i)__builtin_ia32_gatherq_q256((__v4di)_mm256_undefined_si256(), \ - (long long const *)(m), \ - (__v4di)(__m256i)(i), \ - (__v4di)_mm256_set1_epi64x(-1), (s)) + ((__m256i)__builtin_ia32_gatherq_q256((__v4di)_mm256_undefined_si256(), \ + (long long const *)(m), \ + (__v4di)(__m256i)(i), \ + (__v4di)_mm256_set1_epi64x(-1), (s))) #undef __DEFAULT_FN_ATTRS256 #undef __DEFAULT_FN_ATTRS128 diff --git a/clang/lib/Headers/avx512bf16intrin.h b/clang/lib/Headers/avx512bf16intrin.h index d1d87e72f14..09653738d40 100644 --- a/clang/lib/Headers/avx512bf16intrin.h +++ b/clang/lib/Headers/avx512bf16intrin.h @@ -232,7 +232,7 @@ _mm512_maskz_dpbf16_ps(__mmask16 __U, __m512 __D, __m512bh __A, __m512bh __B) { /// /// \param __A /// A 256-bit vector of [16 x bfloat]. -/// \returns A 512-bit vector of [16 x float] come from convertion of __A +/// \returns A 512-bit vector of [16 x float] come from conversion of __A static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_cvtpbh_ps(__m256bh __A) { return _mm512_castsi512_ps((__m512i)_mm512_slli_epi32( (__m512i)_mm512_cvtepi16_epi32((__m256i)__A), 16)); @@ -247,7 +247,7 @@ static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_cvtpbh_ps(__m256bh __A) { /// bit is not set. /// \param __A /// A 256-bit vector of [16 x bfloat]. -/// \returns A 512-bit vector of [16 x float] come from convertion of __A +/// \returns A 512-bit vector of [16 x float] come from conversion of __A static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_maskz_cvtpbh_ps(__mmask16 __U, __m256bh __A) { return _mm512_castsi512_ps((__m512i)_mm512_slli_epi32( @@ -265,7 +265,7 @@ _mm512_maskz_cvtpbh_ps(__mmask16 __U, __m256bh __A) { /// A 16-bit mask. /// \param __A /// A 256-bit vector of [16 x bfloat]. -/// \returns A 512-bit vector of [16 x float] come from convertion of __A +/// \returns A 512-bit vector of [16 x float] come from conversion of __A static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_mask_cvtpbh_ps(__m512 __S, __mmask16 __U, __m256bh __A) { return _mm512_castsi512_ps((__m512i)_mm512_mask_slli_epi32( diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index 4281a33d375..6aee8aed848 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -178,16 +178,16 @@ _kadd_mask64(__mmask64 __A, __mmask64 __B) } #define _kshiftli_mask32(A, I) \ - (__mmask32)__builtin_ia32_kshiftlisi((__mmask32)(A), (unsigned int)(I)) + ((__mmask32)__builtin_ia32_kshiftlisi((__mmask32)(A), (unsigned int)(I))) #define _kshiftri_mask32(A, I) \ - (__mmask32)__builtin_ia32_kshiftrisi((__mmask32)(A), (unsigned int)(I)) + ((__mmask32)__builtin_ia32_kshiftrisi((__mmask32)(A), (unsigned int)(I))) #define _kshiftli_mask64(A, I) \ - (__mmask64)__builtin_ia32_kshiftlidi((__mmask64)(A), (unsigned int)(I)) + ((__mmask64)__builtin_ia32_kshiftlidi((__mmask64)(A), (unsigned int)(I))) #define _kshiftri_mask64(A, I) \ - (__mmask64)__builtin_ia32_kshiftridi((__mmask64)(A), (unsigned int)(I)) + ((__mmask64)__builtin_ia32_kshiftridi((__mmask64)(A), (unsigned int)(I))) static __inline__ unsigned int __DEFAULT_FN_ATTRS _cvtmask32_u32(__mmask32 __A) { @@ -232,44 +232,44 @@ _store_mask64(__mmask64 *__A, __mmask64 __B) { /* Integer compare */ #define _mm512_cmp_epi8_mask(a, b, p) \ - (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)-1) + ((__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)-1)) #define _mm512_mask_cmp_epi8_mask(m, a, b, p) \ - (__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)(m)) + ((__mmask64)__builtin_ia32_cmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)(m))) #define _mm512_cmp_epu8_mask(a, b, p) \ - (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)-1) + ((__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)-1)) #define _mm512_mask_cmp_epu8_mask(m, a, b, p) \ - (__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ - (__v64qi)(__m512i)(b), (int)(p), \ - (__mmask64)(m)) + ((__mmask64)__builtin_ia32_ucmpb512_mask((__v64qi)(__m512i)(a), \ + (__v64qi)(__m512i)(b), (int)(p), \ + (__mmask64)(m))) #define _mm512_cmp_epi16_mask(a, b, p) \ - (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)-1) + ((__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)-1)) #define _mm512_mask_cmp_epi16_mask(m, a, b, p) \ - (__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)(m)) + ((__mmask32)__builtin_ia32_cmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)(m))) #define _mm512_cmp_epu16_mask(a, b, p) \ - (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)-1) + ((__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)-1)) #define _mm512_mask_cmp_epu16_mask(m, a, b, p) \ - (__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ - (__v32hi)(__m512i)(b), (int)(p), \ - (__mmask32)(m)) + ((__mmask32)__builtin_ia32_ucmpw512_mask((__v32hi)(__m512i)(a), \ + (__v32hi)(__m512i)(b), (int)(p), \ + (__mmask32)(m))) #define _mm512_cmpeq_epi8_mask(A, B) \ _mm512_cmp_epi8_mask((A), (B), _MM_CMPINT_EQ) @@ -1428,36 +1428,36 @@ _mm512_maskz_cvtepu8_epi16(__mmask32 __U, __m256i __A) #define _mm512_shufflehi_epi16(A, imm) \ - (__m512i)__builtin_ia32_pshufhw512((__v32hi)(__m512i)(A), (int)(imm)) + ((__m512i)__builtin_ia32_pshufhw512((__v32hi)(__m512i)(A), (int)(imm))) #define _mm512_mask_shufflehi_epi16(W, U, A, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shufflehi_epi16((A), \ - (imm)), \ - (__v32hi)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shufflehi_epi16((A), \ + (imm)), \ + (__v32hi)(__m512i)(W))) #define _mm512_maskz_shufflehi_epi16(U, A, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shufflehi_epi16((A), \ - (imm)), \ - (__v32hi)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shufflehi_epi16((A), \ + (imm)), \ + (__v32hi)_mm512_setzero_si512())) #define _mm512_shufflelo_epi16(A, imm) \ - (__m512i)__builtin_ia32_pshuflw512((__v32hi)(__m512i)(A), (int)(imm)) + ((__m512i)__builtin_ia32_pshuflw512((__v32hi)(__m512i)(A), (int)(imm))) #define _mm512_mask_shufflelo_epi16(W, U, A, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shufflelo_epi16((A), \ - (imm)), \ - (__v32hi)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shufflelo_epi16((A), \ + (imm)), \ + (__v32hi)(__m512i)(W))) #define _mm512_maskz_shufflelo_epi16(U, A, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shufflelo_epi16((A), \ - (imm)), \ - (__v32hi)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shufflelo_epi16((A), \ + (imm)), \ + (__v32hi)_mm512_setzero_si512())) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_sllv_epi16(__m512i __A, __m512i __B) @@ -1527,7 +1527,7 @@ _mm512_maskz_slli_epi16(__mmask32 __U, __m512i __A, unsigned int __B) } #define _mm512_bslli_epi128(a, imm) \ - (__m512i)__builtin_ia32_pslldqi512_byteshift((__v8di)(__m512i)(a), (int)(imm)) + ((__m512i)__builtin_ia32_pslldqi512_byteshift((__v8di)(__m512i)(a), (int)(imm))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_srlv_epi16(__m512i __A, __m512i __B) @@ -1664,7 +1664,7 @@ _mm512_maskz_srli_epi16(__mmask32 __U, __m512i __A, int __B) } #define _mm512_bsrli_epi128(a, imm) \ - (__m512i)__builtin_ia32_psrldqi512_byteshift((__v8di)(__m512i)(a), (int)(imm)) + ((__m512i)__builtin_ia32_psrldqi512_byteshift((__v8di)(__m512i)(a), (int)(imm))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_mask_mov_epi16 (__m512i __W, __mmask32 __U, __m512i __A) @@ -1984,32 +1984,32 @@ _mm512_mask_permutexvar_epi16 (__m512i __W, __mmask32 __M, __m512i __A, } #define _mm512_alignr_epi8(A, B, N) \ - (__m512i)__builtin_ia32_palignr512((__v64qi)(__m512i)(A), \ - (__v64qi)(__m512i)(B), (int)(N)) + ((__m512i)__builtin_ia32_palignr512((__v64qi)(__m512i)(A), \ + (__v64qi)(__m512i)(B), (int)(N))) #define _mm512_mask_alignr_epi8(W, U, A, B, N) \ - (__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ - (__v64qi)_mm512_alignr_epi8((A), (B), (int)(N)), \ - (__v64qi)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ + (__v64qi)_mm512_alignr_epi8((A), (B), (int)(N)), \ + (__v64qi)(__m512i)(W))) #define _mm512_maskz_alignr_epi8(U, A, B, N) \ - (__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ + ((__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ (__v64qi)_mm512_alignr_epi8((A), (B), (int)(N)), \ - (__v64qi)(__m512i)_mm512_setzero_si512()) + (__v64qi)(__m512i)_mm512_setzero_si512())) #define _mm512_dbsad_epu8(A, B, imm) \ - (__m512i)__builtin_ia32_dbpsadbw512((__v64qi)(__m512i)(A), \ - (__v64qi)(__m512i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_dbpsadbw512((__v64qi)(__m512i)(A), \ + (__v64qi)(__m512i)(B), (int)(imm))) #define _mm512_mask_dbsad_epu8(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ (__v32hi)_mm512_dbsad_epu8((A), (B), (imm)), \ - (__v32hi)(__m512i)(W)) + (__v32hi)(__m512i)(W))) #define _mm512_maskz_dbsad_epu8(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ (__v32hi)_mm512_dbsad_epu8((A), (B), (imm)), \ - (__v32hi)_mm512_setzero_si512()) + (__v32hi)_mm512_setzero_si512())) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_sad_epu8 (__m512i __A, __m512i __B) diff --git a/clang/lib/Headers/avx512dqintrin.h b/clang/lib/Headers/avx512dqintrin.h index 337256c50f5..3ba0a0cfd5f 100644 --- a/clang/lib/Headers/avx512dqintrin.h +++ b/clang/lib/Headers/avx512dqintrin.h @@ -121,10 +121,10 @@ _kadd_mask16(__mmask16 __A, __mmask16 __B) } #define _kshiftli_mask8(A, I) \ - (__mmask8)__builtin_ia32_kshiftliqi((__mmask8)(A), (unsigned int)(I)) + ((__mmask8)__builtin_ia32_kshiftliqi((__mmask8)(A), (unsigned int)(I))) #define _kshiftri_mask8(A, I) \ - (__mmask8)__builtin_ia32_kshiftriqi((__mmask8)(A), (unsigned int)(I)) + ((__mmask8)__builtin_ia32_kshiftriqi((__mmask8)(A), (unsigned int)(I))) static __inline__ unsigned int __DEFAULT_FN_ATTRS _cvtmask8_u32(__mmask8 __A) { @@ -342,19 +342,19 @@ _mm512_maskz_cvtpd_epi64 (__mmask8 __U, __m512d __A) { } #define _mm512_cvt_roundpd_epi64(A, R) \ - (__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundpd_epi64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundpd_epi64(U, A, R) \ - (__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvtpd_epu64 (__m512d __A) { @@ -381,19 +381,19 @@ _mm512_maskz_cvtpd_epu64 (__mmask8 __U, __m512d __A) { } #define _mm512_cvt_roundpd_epu64(A, R) \ - (__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundpd_epu64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundpd_epu64(U, A, R) \ - (__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvtps_epi64 (__m256 __A) { @@ -420,19 +420,19 @@ _mm512_maskz_cvtps_epi64 (__mmask8 __U, __m256 __A) { } #define _mm512_cvt_roundps_epi64(A, R) \ - (__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundps_epi64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundps_epi64(U, A, R) \ - (__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvtps_epu64 (__m256 __A) { @@ -459,19 +459,19 @@ _mm512_maskz_cvtps_epu64 (__mmask8 __U, __m256 __A) { } #define _mm512_cvt_roundps_epu64(A, R) \ - (__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundps_epu64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundps_epu64(U, A, R) \ - (__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -494,19 +494,19 @@ _mm512_maskz_cvtepi64_pd (__mmask8 __U, __m512i __A) { } #define _mm512_cvt_roundepi64_pd(A, R) \ - (__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundepi64_pd(W, U, A, R) \ - (__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundepi64_pd(U, A, R) \ - (__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256 __DEFAULT_FN_ATTRS512 _mm512_cvtepi64_ps (__m512i __A) { @@ -533,19 +533,19 @@ _mm512_maskz_cvtepi64_ps (__mmask8 __U, __m512i __A) { } #define _mm512_cvt_roundepi64_ps(A, R) \ - (__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundepi64_ps(W, U, A, R) \ - (__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)(__m256)(W), (__mmask8)(U), \ - (int)(R)) + ((__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)(__m256)(W), (__mmask8)(U), \ + (int)(R))) #define _mm512_maskz_cvt_roundepi64_ps(U, A, R) \ - (__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m256)__builtin_ia32_cvtqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -573,19 +573,19 @@ _mm512_maskz_cvttpd_epi64 (__mmask8 __U, __m512d __A) { } #define _mm512_cvtt_roundpd_epi64(A, R) \ - (__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundpd_epi64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundpd_epi64(U, A, R) \ - (__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2qq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvttpd_epu64 (__m512d __A) { @@ -612,19 +612,19 @@ _mm512_maskz_cvttpd_epu64 (__mmask8 __U, __m512d __A) { } #define _mm512_cvtt_roundpd_epu64(A, R) \ - (__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundpd_epu64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundpd_epu64(U, A, R) \ - (__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttpd2uqq512_mask((__v8df)(__m512d)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvttps_epi64 (__m256 __A) { @@ -651,19 +651,19 @@ _mm512_maskz_cvttps_epi64 (__mmask8 __U, __m256 __A) { } #define _mm512_cvtt_roundps_epi64(A, R) \ - (__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundps_epi64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundps_epi64(U, A, R) \ - (__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2qq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvttps_epu64 (__m256 __A) { @@ -690,19 +690,19 @@ _mm512_maskz_cvttps_epu64 (__mmask8 __U, __m256 __A) { } #define _mm512_cvtt_roundps_epu64(A, R) \ - (__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundps_epu64(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)(__m512i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)(__m512i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundps_epu64(U, A, R) \ - (__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ - (__v8di)_mm512_setzero_si512(), \ - (__mmask8)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2uqq512_mask((__v8sf)(__m256)(A), \ + (__v8di)_mm512_setzero_si512(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_cvtepu64_pd (__m512i __A) { @@ -724,20 +724,20 @@ _mm512_maskz_cvtepu64_pd (__mmask8 __U, __m512i __A) { } #define _mm512_cvt_roundepu64_pd(A, R) \ - (__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundepu64_pd(W, U, A, R) \ - (__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundepu64_pd(U, A, R) \ - (__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtuqq2pd512_mask((__v8di)(__m512i)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256 __DEFAULT_FN_ATTRS512 @@ -765,290 +765,290 @@ _mm512_maskz_cvtepu64_ps (__mmask8 __U, __m512i __A) { } #define _mm512_cvt_roundepu64_ps(A, R) \ - (__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundepu64_ps(W, U, A, R) \ - (__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)(__m256)(W), (__mmask8)(U), \ - (int)(R)) + ((__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)(__m256)(W), (__mmask8)(U), \ + (int)(R))) #define _mm512_maskz_cvt_roundepu64_ps(U, A, R) \ - (__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m256)__builtin_ia32_cvtuqq2ps512_mask((__v8di)(__m512i)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U), (int)(R))) #define _mm512_range_pd(A, B, C) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_range_pd(W, U, A, B, C) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)(__m512d)(W), (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)(__m512d)(W), (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_range_pd(U, A, B, C) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_range_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_range_round_pd(W, U, A, B, C, R) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)(__m512d)(W), (__mmask8)(U), \ - (int)(R)) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)(__m512d)(W), (__mmask8)(U), \ + (int)(R))) #define _mm512_maskz_range_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(C), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_rangepd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(C), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm512_range_ps(A, B, C) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_range_ps(W, U, A, B, C) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)(__m512)(W), (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)(__m512)(W), (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_range_ps(U, A, B, C) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_range_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_range_round_ps(W, U, A, B, C, R) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)(__m512)(W), (__mmask16)(U), \ - (int)(R)) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)(__m512)(W), (__mmask16)(U), \ + (int)(R))) #define _mm512_maskz_range_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(C), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_rangeps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(C), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) #define _mm_range_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8) -1, (int)(C),\ - (int)(R)) + ((__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8) -1, (int)(C),\ + (int)(R))) #define _mm_range_ss(A ,B , C) _mm_range_round_ss(A, B, C ,_MM_FROUND_CUR_DIRECTION) #define _mm_mask_range_round_ss(W, U, A, B, C, R) \ - (__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W),\ - (__mmask8)(U), (int)(C),\ - (int)(R)) + ((__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W),\ + (__mmask8)(U), (int)(C),\ + (int)(R))) #define _mm_mask_range_ss(W , U, A, B, C) _mm_mask_range_round_ss(W, U, A, B, C , _MM_FROUND_CUR_DIRECTION) #define _mm_maskz_range_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(C),\ - (int)(R)) + ((__m128)__builtin_ia32_rangess128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(C),\ + (int)(R))) #define _mm_maskz_range_ss(U, A ,B , C) _mm_maskz_range_round_ss(U, A, B, C ,_MM_FROUND_CUR_DIRECTION) #define _mm_range_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8) -1, (int)(C),\ - (int)(R)) + ((__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8) -1, (int)(C),\ + (int)(R))) #define _mm_range_sd(A ,B , C) _mm_range_round_sd(A, B, C ,_MM_FROUND_CUR_DIRECTION) #define _mm_mask_range_round_sd(W, U, A, B, C, R) \ - (__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W),\ - (__mmask8)(U), (int)(C),\ - (int)(R)) + ((__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W),\ + (__mmask8)(U), (int)(C),\ + (int)(R))) #define _mm_mask_range_sd(W, U, A, B, C) _mm_mask_range_round_sd(W, U, A, B, C ,_MM_FROUND_CUR_DIRECTION) #define _mm_maskz_range_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(C),\ - (int)(R)) + ((__m128d)__builtin_ia32_rangesd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(C),\ + (int)(R))) #define _mm_maskz_range_sd(U, A, B, C) _mm_maskz_range_round_sd(U, A, B, C ,_MM_FROUND_CUR_DIRECTION) #define _mm512_reduce_pd(A, B) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_reduce_pd(W, U, A, B) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_reduce_pd(U, A, B) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_reduce_ps(A, B) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_reduce_ps(W, U, A, B) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_reduce_ps(U, A, B) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_reduce_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_reduce_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_reduce_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_reducepd512_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm512_reduce_round_ps(A, B, R) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_reduce_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_reduce_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_reduceps512_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) #define _mm_reduce_ss(A, B, C) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), (__mmask8)-1, \ - (int)(C), _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), (__mmask8)-1, \ + (int)(C), _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_reduce_ss(W, U, A, B, C) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(C), _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(C), _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_reduce_ss(U, A, B, C) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(C), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(C), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_reduce_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), (__mmask8)-1, \ - (int)(C), (int)(R)) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), (__mmask8)-1, \ + (int)(C), (int)(R))) #define _mm_mask_reduce_round_ss(W, U, A, B, C, R) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(C), (int)(R)) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(C), (int)(R))) #define _mm_maskz_reduce_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(C), (int)(R)) + ((__m128)__builtin_ia32_reducess_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(C), (int)(R))) #define _mm_reduce_sd(A, B, C) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(C), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(C), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_reduce_sd(W, U, A, B, C) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), (__mmask8)(U), \ - (int)(C), _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), (__mmask8)(U), \ + (int)(C), _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_reduce_sd(U, A, B, C) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(C), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(C), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_reduce_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(C), (int)(R)) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(C), (int)(R))) #define _mm_mask_reduce_round_sd(W, U, A, B, C, R) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), (__mmask8)(U), \ - (int)(C), (int)(R)) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), (__mmask8)(U), \ + (int)(C), (int)(R))) #define _mm_maskz_reduce_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(C), (int)(R)) + ((__m128d)__builtin_ia32_reducesd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(C), (int)(R))) static __inline__ __mmask16 __DEFAULT_FN_ATTRS512 _mm512_movepi32_mask (__m512i __A) @@ -1218,158 +1218,158 @@ _mm512_maskz_broadcast_i64x2(__mmask8 __M, __m128i __A) } #define _mm512_extractf32x8_ps(A, imm) \ - (__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v8sf)_mm256_undefined_ps(), \ - (__mmask8)-1) + ((__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v8sf)_mm256_undefined_ps(), \ + (__mmask8)-1)) #define _mm512_mask_extractf32x8_ps(W, U, A, imm) \ - (__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v8sf)(__m256)(W), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v8sf)(__m256)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extractf32x8_ps(U, A, imm) \ - (__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_extractf32x8_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U))) #define _mm512_extractf64x2_pd(A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ - (int)(imm), \ - (__v2df)_mm_undefined_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ + (int)(imm), \ + (__v2df)_mm_undefined_pd(), \ + (__mmask8)-1)) #define _mm512_mask_extractf64x2_pd(W, U, A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ - (int)(imm), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ + (int)(imm), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extractf64x2_pd(U, A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ - (int)(imm), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_extractf64x2_512_mask((__v8df)(__m512d)(A), \ + (int)(imm), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm512_extracti32x8_epi32(A, imm) \ - (__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v8si)_mm256_undefined_si256(), \ - (__mmask8)-1) + ((__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v8si)_mm256_undefined_si256(), \ + (__mmask8)-1)) #define _mm512_mask_extracti32x8_epi32(W, U, A, imm) \ - (__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U)) + ((__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v8si)(__m256i)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extracti32x8_epi32(U, A, imm) \ - (__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U)) + ((__m256i)__builtin_ia32_extracti32x8_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)(U))) #define _mm512_extracti64x2_epi64(A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ + ((__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ (int)(imm), \ (__v2di)_mm_undefined_si128(), \ - (__mmask8)-1) + (__mmask8)-1)) #define _mm512_mask_extracti64x2_epi64(W, U, A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ - (int)(imm), \ - (__v2di)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ + (int)(imm), \ + (__v2di)(__m128i)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extracti64x2_epi64(U, A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ - (int)(imm), \ - (__v2di)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti64x2_512_mask((__v8di)(__m512i)(A), \ + (int)(imm), \ + (__v2di)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm512_insertf32x8(A, B, imm) \ - (__m512)__builtin_ia32_insertf32x8((__v16sf)(__m512)(A), \ - (__v8sf)(__m256)(B), (int)(imm)) + ((__m512)__builtin_ia32_insertf32x8((__v16sf)(__m512)(A), \ + (__v8sf)(__m256)(B), (int)(imm))) #define _mm512_mask_insertf32x8(W, U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_insertf32x8((A), (B), (imm)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_insertf32x8(U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_insertf32x8((A), (B), (imm)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) #define _mm512_insertf64x2(A, B, imm) \ - (__m512d)__builtin_ia32_insertf64x2_512((__v8df)(__m512d)(A), \ - (__v2df)(__m128d)(B), (int)(imm)) + ((__m512d)__builtin_ia32_insertf64x2_512((__v8df)(__m512d)(A), \ + (__v2df)(__m128d)(B), (int)(imm))) #define _mm512_mask_insertf64x2(W, U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_insertf64x2((A), (B), (imm)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_insertf64x2(U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_insertf64x2((A), (B), (imm)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) #define _mm512_inserti32x8(A, B, imm) \ - (__m512i)__builtin_ia32_inserti32x8((__v16si)(__m512i)(A), \ - (__v8si)(__m256i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_inserti32x8((__v16si)(__m512i)(A), \ + (__v8si)(__m256i)(B), (int)(imm))) #define _mm512_mask_inserti32x8(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ (__v16si)_mm512_inserti32x8((A), (B), (imm)), \ - (__v16si)(__m512i)(W)) + (__v16si)(__m512i)(W))) #define _mm512_maskz_inserti32x8(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ (__v16si)_mm512_inserti32x8((A), (B), (imm)), \ - (__v16si)_mm512_setzero_si512()) + (__v16si)_mm512_setzero_si512())) #define _mm512_inserti64x2(A, B, imm) \ - (__m512i)__builtin_ia32_inserti64x2_512((__v8di)(__m512i)(A), \ - (__v2di)(__m128i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_inserti64x2_512((__v8di)(__m512i)(A), \ + (__v2di)(__m128i)(B), (int)(imm))) #define _mm512_mask_inserti64x2(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ (__v8di)_mm512_inserti64x2((A), (B), (imm)), \ - (__v8di)(__m512i)(W)) + (__v8di)(__m512i)(W))) #define _mm512_maskz_inserti64x2(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ (__v8di)_mm512_inserti64x2((A), (B), (imm)), \ - (__v8di)_mm512_setzero_si512()) + (__v8di)_mm512_setzero_si512())) #define _mm512_mask_fpclass_ps_mask(U, A, imm) \ - (__mmask16)__builtin_ia32_fpclassps512_mask((__v16sf)(__m512)(A), \ - (int)(imm), (__mmask16)(U)) + ((__mmask16)__builtin_ia32_fpclassps512_mask((__v16sf)(__m512)(A), \ + (int)(imm), (__mmask16)(U))) #define _mm512_fpclass_ps_mask(A, imm) \ - (__mmask16)__builtin_ia32_fpclassps512_mask((__v16sf)(__m512)(A), \ - (int)(imm), (__mmask16)-1) + ((__mmask16)__builtin_ia32_fpclassps512_mask((__v16sf)(__m512)(A), \ + (int)(imm), (__mmask16)-1)) #define _mm512_mask_fpclass_pd_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd512_mask((__v8df)(__m512d)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclasspd512_mask((__v8df)(__m512d)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm512_fpclass_pd_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd512_mask((__v8df)(__m512d)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclasspd512_mask((__v8df)(__m512d)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm_fpclass_sd_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclasssd_mask((__v2df)(__m128d)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclasssd_mask((__v2df)(__m128d)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm_mask_fpclass_sd_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclasssd_mask((__v2df)(__m128d)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclasssd_mask((__v2df)(__m128d)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm_fpclass_ss_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclassss_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclassss_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm_mask_fpclass_ss_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclassss_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclassss_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__mmask8)(U))) #undef __DEFAULT_FN_ATTRS512 #undef __DEFAULT_FN_ATTRS diff --git a/clang/lib/Headers/avx512erintrin.h b/clang/lib/Headers/avx512erintrin.h index 85700616990..1c5a2d2d208 100644 --- a/clang/lib/Headers/avx512erintrin.h +++ b/clang/lib/Headers/avx512erintrin.h @@ -15,19 +15,19 @@ /* exp2a23 */ #define _mm512_exp2a23_round_pd(A, R) \ - (__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_exp2a23_round_pd(S, M, A, R) \ - (__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R)) + ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(S), (__mmask8)(M), \ + (int)(R))) #define _mm512_maskz_exp2a23_round_pd(M, A, R) \ - (__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R)) + ((__m512d)__builtin_ia32_exp2pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(M), (int)(R))) #define _mm512_exp2a23_pd(A) \ _mm512_exp2a23_round_pd((A), _MM_FROUND_CUR_DIRECTION) @@ -39,19 +39,19 @@ _mm512_maskz_exp2a23_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) #define _mm512_exp2a23_round_ps(A, R) \ - (__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_exp2a23_round_ps(S, M, A, R) \ - (__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R)) + ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(S), (__mmask16)(M), \ + (int)(R))) #define _mm512_maskz_exp2a23_round_ps(M, A, R) \ - (__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R)) + ((__m512)__builtin_ia32_exp2ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(M), (int)(R))) #define _mm512_exp2a23_ps(A) \ _mm512_exp2a23_round_ps((A), _MM_FROUND_CUR_DIRECTION) @@ -64,19 +64,19 @@ /* rsqrt28 */ #define _mm512_rsqrt28_round_pd(A, R) \ - (__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_rsqrt28_round_pd(S, M, A, R) \ - (__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R)) + ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(S), (__mmask8)(M), \ + (int)(R))) #define _mm512_maskz_rsqrt28_round_pd(M, A, R) \ - (__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R)) + ((__m512d)__builtin_ia32_rsqrt28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(M), (int)(R))) #define _mm512_rsqrt28_pd(A) \ _mm512_rsqrt28_round_pd((A), _MM_FROUND_CUR_DIRECTION) @@ -88,19 +88,19 @@ _mm512_maskz_rsqrt28_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) #define _mm512_rsqrt28_round_ps(A, R) \ - (__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_rsqrt28_round_ps(S, M, A, R) \ - (__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R)) + ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(S), (__mmask16)(M), \ + (int)(R))) #define _mm512_maskz_rsqrt28_round_ps(M, A, R) \ - (__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R)) + ((__m512)__builtin_ia32_rsqrt28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(M), (int)(R))) #define _mm512_rsqrt28_ps(A) \ _mm512_rsqrt28_round_ps((A), _MM_FROUND_CUR_DIRECTION) @@ -112,22 +112,22 @@ _mm512_maskz_rsqrt28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION) #define _mm_rsqrt28_round_ss(A, B, R) \ - (__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_rsqrt28_round_ss(S, M, A, B, R) \ - (__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(S), \ - (__mmask8)(M), (int)(R)) + ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(S), \ + (__mmask8)(M), (int)(R))) #define _mm_maskz_rsqrt28_round_ss(M, A, B, R) \ - (__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(M), (int)(R)) + ((__m128)__builtin_ia32_rsqrt28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(M), (int)(R))) #define _mm_rsqrt28_ss(A, B) \ _mm_rsqrt28_round_ss((A), (B), _MM_FROUND_CUR_DIRECTION) @@ -139,22 +139,22 @@ _mm_maskz_rsqrt28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION) #define _mm_rsqrt28_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_rsqrt28_round_sd(S, M, A, B, R) \ - (__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(S), \ - (__mmask8)(M), (int)(R)) + ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(S), \ + (__mmask8)(M), (int)(R))) #define _mm_maskz_rsqrt28_round_sd(M, A, B, R) \ - (__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(M), (int)(R)) + ((__m128d)__builtin_ia32_rsqrt28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(M), (int)(R))) #define _mm_rsqrt28_sd(A, B) \ _mm_rsqrt28_round_sd((A), (B), _MM_FROUND_CUR_DIRECTION) @@ -167,19 +167,19 @@ /* rcp28 */ #define _mm512_rcp28_round_pd(A, R) \ - (__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_rcp28_round_pd(S, M, A, R) \ - (__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(S), (__mmask8)(M), \ - (int)(R)) + ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(S), (__mmask8)(M), \ + (int)(R))) #define _mm512_maskz_rcp28_round_pd(M, A, R) \ - (__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(M), (int)(R)) + ((__m512d)__builtin_ia32_rcp28pd_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(M), (int)(R))) #define _mm512_rcp28_pd(A) \ _mm512_rcp28_round_pd((A), _MM_FROUND_CUR_DIRECTION) @@ -191,19 +191,19 @@ _mm512_maskz_rcp28_round_pd((M), (A), _MM_FROUND_CUR_DIRECTION) #define _mm512_rcp28_round_ps(A, R) \ - (__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_rcp28_round_ps(S, M, A, R) \ - (__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(S), (__mmask16)(M), \ - (int)(R)) + ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(S), (__mmask16)(M), \ + (int)(R))) #define _mm512_maskz_rcp28_round_ps(M, A, R) \ - (__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(M), (int)(R)) + ((__m512)__builtin_ia32_rcp28ps_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(M), (int)(R))) #define _mm512_rcp28_ps(A) \ _mm512_rcp28_round_ps((A), _MM_FROUND_CUR_DIRECTION) @@ -215,22 +215,22 @@ _mm512_maskz_rcp28_round_ps((M), (A), _MM_FROUND_CUR_DIRECTION) #define _mm_rcp28_round_ss(A, B, R) \ - (__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_rcp28_round_ss(S, M, A, B, R) \ - (__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(S), \ - (__mmask8)(M), (int)(R)) + ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(S), \ + (__mmask8)(M), (int)(R))) #define _mm_maskz_rcp28_round_ss(M, A, B, R) \ - (__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(M), (int)(R)) + ((__m128)__builtin_ia32_rcp28ss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(M), (int)(R))) #define _mm_rcp28_ss(A, B) \ _mm_rcp28_round_ss((A), (B), _MM_FROUND_CUR_DIRECTION) @@ -242,22 +242,22 @@ _mm_maskz_rcp28_round_ss((M), (A), (B), _MM_FROUND_CUR_DIRECTION) #define _mm_rcp28_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_rcp28_round_sd(S, M, A, B, R) \ - (__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(S), \ - (__mmask8)(M), (int)(R)) + ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(S), \ + (__mmask8)(M), (int)(R))) #define _mm_maskz_rcp28_round_sd(M, A, B, R) \ - (__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(M), (int)(R)) + ((__m128d)__builtin_ia32_rcp28sd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(M), (int)(R))) #define _mm_rcp28_sd(A, B) \ _mm_rcp28_round_sd((A), (B), _MM_FROUND_CUR_DIRECTION) diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h index 010bcadab01..df298640523 100644 --- a/clang/lib/Headers/avx512fintrin.h +++ b/clang/lib/Headers/avx512fintrin.h @@ -937,18 +937,18 @@ _mm512_maskz_sub_epi32(__mmask16 __U, __m512i __A, __m512i __B) } #define _mm512_max_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_maxpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_maxpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_max_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_max_round_pd((A), (B), (R)), \ - (__v8df)(W)) + (__v8df)(W))) #define _mm512_maskz_max_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_max_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_max_pd(__m512d __A, __m512d __B) @@ -974,18 +974,18 @@ _mm512_maskz_max_pd (__mmask8 __U, __m512d __A, __m512d __B) } #define _mm512_max_round_ps(A, B, R) \ - (__m512)__builtin_ia32_maxps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_maxps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_max_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_max_round_ps((A), (B), (R)), \ - (__v16sf)(W)) + (__v16sf)(W))) #define _mm512_maskz_max_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_max_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_max_ps(__m512 __A, __m512 __B) @@ -1029,22 +1029,22 @@ _mm_maskz_max_ss(__mmask8 __U,__m128 __A, __m128 __B) { } #define _mm_max_round_ss(A, B, R) \ - (__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_max_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_max_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_maxss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_max_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -1065,22 +1065,22 @@ _mm_maskz_max_sd(__mmask8 __U,__m128d __A, __m128d __B) { } #define _mm_max_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_max_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_max_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_maxsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -1172,18 +1172,18 @@ _mm512_maskz_max_epu64 (__mmask8 __M, __m512i __A, __m512i __B) } #define _mm512_min_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_minpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_minpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_min_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_min_round_pd((A), (B), (R)), \ - (__v8df)(W)) + (__v8df)(W))) #define _mm512_maskz_min_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_min_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_min_pd(__m512d __A, __m512d __B) @@ -1209,18 +1209,18 @@ _mm512_maskz_min_pd (__mmask8 __U, __m512d __A, __m512d __B) } #define _mm512_min_round_ps(A, B, R) \ - (__m512)__builtin_ia32_minps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_minps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_min_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_min_round_ps((A), (B), (R)), \ - (__v16sf)(W)) + (__v16sf)(W))) #define _mm512_maskz_min_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_min_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_min_ps(__m512 __A, __m512 __B) @@ -1264,22 +1264,22 @@ _mm_maskz_min_ss(__mmask8 __U,__m128 __A, __m128 __B) { } #define _mm_min_round_ss(A, B, R) \ - (__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_min_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_min_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_minss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_min_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -1300,22 +1300,22 @@ _mm_maskz_min_sd(__mmask8 __U,__m128d __A, __m128d __B) { } #define _mm_min_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_min_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_min_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_minsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -1485,17 +1485,17 @@ _mm512_mask_mullox_epi64(__m512i __W, __mmask8 __U, __m512i __A, __m512i __B) { } #define _mm512_sqrt_round_pd(A, R) \ - (__m512d)__builtin_ia32_sqrtpd512((__v8df)(__m512d)(A), (int)(R)) + ((__m512d)__builtin_ia32_sqrtpd512((__v8df)(__m512d)(A), (int)(R))) #define _mm512_mask_sqrt_round_pd(W, U, A, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_sqrt_round_pd((A), (R)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_sqrt_round_pd(U, A, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_sqrt_round_pd((A), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_sqrt_pd(__m512d __A) @@ -1521,17 +1521,17 @@ _mm512_maskz_sqrt_pd (__mmask8 __U, __m512d __A) } #define _mm512_sqrt_round_ps(A, R) \ - (__m512)__builtin_ia32_sqrtps512((__v16sf)(__m512)(A), (int)(R)) + ((__m512)__builtin_ia32_sqrtps512((__v16sf)(__m512)(A), (int)(R))) #define _mm512_mask_sqrt_round_ps(W, U, A, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_sqrt_round_ps((A), (R)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_sqrt_round_ps(U, A, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_sqrt_round_ps((A), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_sqrt_ps(__m512 __A) @@ -1900,22 +1900,22 @@ _mm_maskz_add_ss(__mmask8 __U,__m128 __A, __m128 __B) { } #define _mm_add_round_ss(A, B, R) \ - (__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_add_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_add_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_addss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_add_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -1929,22 +1929,22 @@ _mm_maskz_add_sd(__mmask8 __U,__m128d __A, __m128d __B) { return __builtin_ia32_selectsd_128(__U, __A, _mm_setzero_pd()); } #define _mm_add_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_add_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_add_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_addsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_mask_add_pd(__m512d __W, __mmask8 __U, __m512d __A, __m512d __B) { @@ -1975,32 +1975,32 @@ _mm512_maskz_add_ps(__mmask16 __U, __m512 __A, __m512 __B) { } #define _mm512_add_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_addpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_addpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_add_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_add_round_pd((A), (B), (R)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_add_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_add_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) #define _mm512_add_round_ps(A, B, R) \ - (__m512)__builtin_ia32_addps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_addps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_add_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_add_round_ps((A), (B), (R)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_add_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_add_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_sub_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) { @@ -2014,22 +2014,22 @@ _mm_maskz_sub_ss(__mmask8 __U,__m128 __A, __m128 __B) { return __builtin_ia32_selectss_128(__U, __A, _mm_setzero_ps()); } #define _mm_sub_round_ss(A, B, R) \ - (__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_sub_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_sub_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_subss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_sub_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -2044,22 +2044,22 @@ _mm_maskz_sub_sd(__mmask8 __U,__m128d __A, __m128d __B) { } #define _mm_sub_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_sub_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_sub_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_subsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_mask_sub_pd(__m512d __W, __mmask8 __U, __m512d __A, __m512d __B) { @@ -2090,32 +2090,32 @@ _mm512_maskz_sub_ps(__mmask16 __U, __m512 __A, __m512 __B) { } #define _mm512_sub_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_subpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_subpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_sub_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_sub_round_pd((A), (B), (R)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_sub_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_sub_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) #define _mm512_sub_round_ps(A, B, R) \ - (__m512)__builtin_ia32_subps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_subps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_sub_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_sub_round_ps((A), (B), (R)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_sub_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_sub_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_mul_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) { @@ -2129,22 +2129,22 @@ _mm_maskz_mul_ss(__mmask8 __U,__m128 __A, __m128 __B) { return __builtin_ia32_selectss_128(__U, __A, _mm_setzero_ps()); } #define _mm_mul_round_ss(A, B, R) \ - (__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_mul_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_mul_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_mulss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_mul_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -2159,22 +2159,22 @@ _mm_maskz_mul_sd(__mmask8 __U,__m128d __A, __m128d __B) { } #define _mm_mul_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_mul_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_mul_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_mulsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_mask_mul_pd(__m512d __W, __mmask8 __U, __m512d __A, __m512d __B) { @@ -2205,32 +2205,32 @@ _mm512_maskz_mul_ps(__mmask16 __U, __m512 __A, __m512 __B) { } #define _mm512_mul_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_mulpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_mulpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_mul_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_mul_round_pd((A), (B), (R)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_mul_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_mul_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) #define _mm512_mul_round_ps(A, B, R) \ - (__m512)__builtin_ia32_mulps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_mulps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_mul_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_mul_round_ps((A), (B), (R)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_mul_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_mul_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_div_ss(__m128 __W, __mmask8 __U,__m128 __A, __m128 __B) { @@ -2245,22 +2245,22 @@ _mm_maskz_div_ss(__mmask8 __U,__m128 __A, __m128 __B) { } #define _mm_div_round_ss(A, B, R) \ - (__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_div_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) #define _mm_maskz_div_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_divss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_div_sd(__m128d __W, __mmask8 __U,__m128d __A, __m128d __B) { @@ -2275,22 +2275,22 @@ _mm_maskz_div_sd(__mmask8 __U,__m128d __A, __m128d __B) { } #define _mm_div_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_div_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_div_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_divsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline __m512d __DEFAULT_FN_ATTRS512 _mm512_div_pd(__m512d __a, __m512d __b) @@ -2333,179 +2333,179 @@ _mm512_maskz_div_ps(__mmask16 __U, __m512 __A, __m512 __B) { } #define _mm512_div_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_divpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(R)) + ((__m512d)__builtin_ia32_divpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(R))) #define _mm512_mask_div_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_div_round_pd((A), (B), (R)), \ - (__v8df)(__m512d)(W)) + (__v8df)(__m512d)(W))) #define _mm512_maskz_div_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ (__v8df)_mm512_div_round_pd((A), (B), (R)), \ - (__v8df)_mm512_setzero_pd()) + (__v8df)_mm512_setzero_pd())) #define _mm512_div_round_ps(A, B, R) \ - (__m512)__builtin_ia32_divps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(R)) + ((__m512)__builtin_ia32_divps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(R))) #define _mm512_mask_div_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_div_round_ps((A), (B), (R)), \ - (__v16sf)(__m512)(W)) + (__v16sf)(__m512)(W))) #define _mm512_maskz_div_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ (__v16sf)_mm512_div_round_ps((A), (B), (R)), \ - (__v16sf)_mm512_setzero_ps()) + (__v16sf)_mm512_setzero_ps())) #define _mm512_roundscale_ps(A, B) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(A), (int)(B), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(A), (int)(B), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_roundscale_ps(A, B, C, imm) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(C), (int)(imm), \ + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(C), (int)(imm), \ (__v16sf)(__m512)(A), (__mmask16)(B), \ - _MM_FROUND_CUR_DIRECTION) + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_roundscale_ps(A, B, imm) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(B), (int)(imm), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(A), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(B), (int)(imm), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(A), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_roundscale_round_ps(A, B, C, imm, R) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(C), (int)(imm), \ + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(C), (int)(imm), \ (__v16sf)(__m512)(A), (__mmask16)(B), \ - (int)(R)) + (int)(R))) #define _mm512_maskz_roundscale_round_ps(A, B, imm, R) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(B), (int)(imm), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(A), (int)(R)) + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(B), (int)(imm), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(A), (int)(R))) #define _mm512_roundscale_round_ps(A, imm, R) \ - (__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_rndscaleps_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_roundscale_pd(A, B) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(A), (int)(B), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(A), (int)(B), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_roundscale_pd(A, B, C, imm) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(C), (int)(imm), \ + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(C), (int)(imm), \ (__v8df)(__m512d)(A), (__mmask8)(B), \ - _MM_FROUND_CUR_DIRECTION) + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_roundscale_pd(A, B, imm) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(B), (int)(imm), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(A), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(B), (int)(imm), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(A), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_roundscale_round_pd(A, B, C, imm, R) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(C), (int)(imm), \ + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(C), (int)(imm), \ (__v8df)(__m512d)(A), (__mmask8)(B), \ - (int)(R)) + (int)(R))) #define _mm512_maskz_roundscale_round_pd(A, B, imm, R) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(B), (int)(imm), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(A), (int)(R)) + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(B), (int)(imm), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(A), (int)(R))) #define _mm512_roundscale_round_pd(A, imm, R) \ - (__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(A), (int)(imm), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_rndscalepd_mask((__v8df)(__m512d)(A), (int)(imm), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_fmadd_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_fmadd_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_mask3_fmadd_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask3((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask3((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_fmadd_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_fmsub_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_fmsub_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_fmsub_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_fnmadd_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask3_fnmadd_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask3(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask3(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_fnmadd_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_maskz(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_maskz(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_fnmsub_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_maskz_fnmsub_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_maskz(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_maskz(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -2629,87 +2629,87 @@ _mm512_maskz_fnmsub_pd(__mmask8 __U, __m512d __A, __m512d __B, __m512d __C) } #define _mm512_fmadd_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_fmadd_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_mask3_fmadd_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask3((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask3((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_fmadd_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_fmsub_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_fmsub_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_fmsub_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_fnmadd_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - -(__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + -(__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask3_fnmadd_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask3(-(__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask3(-(__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_fnmadd_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_maskz(-(__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_maskz(-(__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_fnmsub_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - -(__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + -(__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_maskz_fnmsub_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_maskz(-(__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_maskz(-(__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 @@ -2833,52 +2833,52 @@ _mm512_maskz_fnmsub_ps(__mmask16 __U, __m512 __A, __m512 __B, __m512 __C) } #define _mm512_fmaddsub_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_fmaddsub_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_mask3_fmaddsub_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_mask3((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_mask3((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_fmaddsub_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_fmsubadd_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_fmsubadd_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_fmsubadd_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddsubpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddsubpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -2952,52 +2952,52 @@ _mm512_maskz_fmsubadd_pd(__mmask8 __U, __m512d __A, __m512d __B, __m512d __C) } #define _mm512_fmaddsub_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_fmaddsub_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_mask3_fmaddsub_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_mask3((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_mask3((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_fmaddsub_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_fmsubadd_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_fmsubadd_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_fmsubadd_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_vfmaddsubps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddsubps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 @@ -3071,10 +3071,10 @@ _mm512_maskz_fmsubadd_ps(__mmask16 __U, __m512 __A, __m512 __B, __m512 __C) } #define _mm512_mask3_fmsub_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmsubpd512_mask3((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmsubpd512_mask3((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -3088,10 +3088,10 @@ _mm512_mask3_fmsub_pd(__m512d __A, __m512d __B, __m512d __C, __mmask8 __U) } #define _mm512_mask3_fmsub_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmsubps512_mask3((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmsubps512_mask3((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_mask3_fmsub_ps(__m512 __A, __m512 __B, __m512 __C, __mmask16 __U) @@ -3104,10 +3104,10 @@ _mm512_mask3_fmsub_ps(__m512 __A, __m512 __B, __m512 __C, __mmask16 __U) } #define _mm512_mask3_fmsubadd_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmsubaddpd512_mask3((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmsubaddpd512_mask3((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -3121,10 +3121,10 @@ _mm512_mask3_fmsubadd_pd(__m512d __A, __m512d __B, __m512d __C, __mmask8 __U) } #define _mm512_mask3_fmsubadd_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmsubaddps512_mask3((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmsubaddps512_mask3((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 @@ -3138,10 +3138,10 @@ _mm512_mask3_fmsubadd_ps(__m512 __A, __m512 __B, __m512 __C, __mmask16 __U) } #define _mm512_mask_fnmadd_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - -(__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + -(__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -3155,10 +3155,10 @@ _mm512_mask_fnmadd_pd(__m512d __A, __mmask8 __U, __m512d __B, __m512d __C) } #define _mm512_mask_fnmadd_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - -(__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + -(__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 @@ -3172,17 +3172,17 @@ _mm512_mask_fnmadd_ps(__m512 __A, __mmask16 __U, __m512 __B, __m512 __C) } #define _mm512_mask_fnmsub_round_pd(A, U, B, C, R) \ - (__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ - -(__v8df)(__m512d)(B), \ - -(__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmaddpd512_mask((__v8df)(__m512d)(A), \ + -(__v8df)(__m512d)(B), \ + -(__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) #define _mm512_mask3_fnmsub_round_pd(A, B, C, U, R) \ - (__m512d)__builtin_ia32_vfmsubpd512_mask3(-(__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_vfmsubpd512_mask3(-(__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 @@ -3206,17 +3206,17 @@ _mm512_mask3_fnmsub_pd(__m512d __A, __m512d __B, __m512d __C, __mmask8 __U) } #define _mm512_mask_fnmsub_round_ps(A, U, B, C, R) \ - (__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ - -(__v16sf)(__m512)(B), \ - -(__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmaddps512_mask((__v16sf)(__m512)(A), \ + -(__v16sf)(__m512)(B), \ + -(__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) #define _mm512_mask3_fnmsub_round_ps(A, B, C, U, R) \ - (__m512)__builtin_ia32_vfmsubps512_mask3(-(__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(C), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vfmsubps512_mask3(-(__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(C), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 @@ -3312,63 +3312,63 @@ _mm512_maskz_permutex2var_epi64(__mmask8 __U, __m512i __A, __m512i __I, } #define _mm512_alignr_epi64(A, B, I) \ - (__m512i)__builtin_ia32_alignq512((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_alignq512((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), (int)(I))) #define _mm512_mask_alignr_epi64(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_alignr_epi64((A), (B), (imm)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_alignr_epi64((A), (B), (imm)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_alignr_epi64(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_alignr_epi64((A), (B), (imm)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_alignr_epi64((A), (B), (imm)), \ + (__v8di)_mm512_setzero_si512())) #define _mm512_alignr_epi32(A, B, I) \ - (__m512i)__builtin_ia32_alignd512((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_alignd512((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), (int)(I))) #define _mm512_mask_alignr_epi32(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_alignr_epi32((A), (B), (imm)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_alignr_epi32((A), (B), (imm)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_alignr_epi32(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_alignr_epi32((A), (B), (imm)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_alignr_epi32((A), (B), (imm)), \ + (__v16si)_mm512_setzero_si512())) /* Vector Extract */ #define _mm512_extractf64x4_pd(A, I) \ - (__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(I), \ - (__v4df)_mm256_undefined_pd(), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(I), \ + (__v4df)_mm256_undefined_pd(), \ + (__mmask8)-1)) #define _mm512_mask_extractf64x4_pd(W, U, A, imm) \ - (__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(imm), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(imm), \ + (__v4df)(__m256d)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extractf64x4_pd(U, A, imm) \ - (__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(imm), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_extractf64x4_mask((__v8df)(__m512d)(A), (int)(imm), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)(U))) #define _mm512_extractf32x4_ps(A, I) \ - (__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(I), \ - (__v4sf)_mm_undefined_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(I), \ + (__v4sf)_mm_undefined_ps(), \ + (__mmask8)-1)) #define _mm512_mask_extractf32x4_ps(W, U, A, imm) \ - (__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extractf32x4_ps(U, A, imm) \ - (__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(imm), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_extractf32x4_mask((__v16sf)(__m512)(A), (int)(imm), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) /* Vector Blend */ @@ -3407,14 +3407,14 @@ _mm512_mask_blend_epi32(__mmask16 __U, __m512i __A, __m512i __W) /* Compare */ #define _mm512_cmp_round_ps_mask(A, B, P, R) \ - (__mmask16)__builtin_ia32_cmpps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(P), \ - (__mmask16)-1, (int)(R)) + ((__mmask16)__builtin_ia32_cmpps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(P), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cmp_round_ps_mask(U, A, B, P, R) \ - (__mmask16)__builtin_ia32_cmpps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(P), \ - (__mmask16)(U), (int)(R)) + ((__mmask16)__builtin_ia32_cmpps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(P), \ + (__mmask16)(U), (int)(R))) #define _mm512_cmp_ps_mask(A, B, P) \ _mm512_cmp_round_ps_mask((A), (B), (P), _MM_FROUND_CUR_DIRECTION) @@ -3462,14 +3462,14 @@ _mm512_mask_blend_epi32(__mmask16 __U, __m512i __A, __m512i __W) _mm512_mask_cmp_ps_mask((k), (A), (B), _CMP_ORD_Q) #define _mm512_cmp_round_pd_mask(A, B, P, R) \ - (__mmask8)__builtin_ia32_cmppd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(P), \ - (__mmask8)-1, (int)(R)) + ((__mmask8)__builtin_ia32_cmppd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(P), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cmp_round_pd_mask(U, A, B, P, R) \ - (__mmask8)__builtin_ia32_cmppd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(P), \ - (__mmask8)(U), (int)(R)) + ((__mmask8)__builtin_ia32_cmppd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(P), \ + (__mmask8)(U), (int)(R))) #define _mm512_cmp_pd_mask(A, B, P) \ _mm512_cmp_round_pd_mask((A), (B), (P), _MM_FROUND_CUR_DIRECTION) @@ -3519,19 +3519,19 @@ _mm512_mask_blend_epi32(__mmask16 __U, __m512i __A, __m512i __W) /* Conversion */ #define _mm512_cvtt_roundps_epu32(A, R) \ - (__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_undefined_epi32(), \ - (__mmask16)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_undefined_epi32(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvtt_roundps_epu32(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)(__m512i)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)(__m512i)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvtt_roundps_epu32(U, A, R) \ - (__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)(U), (int)(R))) static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -3563,34 +3563,34 @@ _mm512_maskz_cvttps_epu32 (__mmask16 __U, __m512 __A) } #define _mm512_cvt_roundepi32_ps(A, R) \ - (__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvt_roundepi32_ps(W, U, A, R) \ - (__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvt_roundepi32_ps(U, A, R) \ - (__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_cvtdq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) #define _mm512_cvt_roundepu32_ps(A, R) \ - (__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvt_roundepu32_ps(W, U, A, R) \ - (__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvt_roundepu32_ps(U, A, R) \ - (__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_cvtudq2ps512_mask((__v16si)(__m512i)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_cvtepu32_ps (__m512i __A) @@ -3705,19 +3705,19 @@ _mm512_mask_cvtepu32lo_pd(__m512d __W, __mmask8 __U,__m512i __A) } #define _mm512_cvt_roundpd_ps(A, R) \ - (__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundpd_ps(W, U, A, R) \ - (__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ - (__v8sf)(__m256)(W), (__mmask8)(U), \ - (int)(R)) + ((__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ + (__v8sf)(__m256)(W), (__mmask8)(U), \ + (int)(R))) #define _mm512_maskz_cvt_roundpd_ps(U, A, R) \ - (__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m256)__builtin_ia32_cvtpd2ps512_mask((__v8df)(__m512d)(A), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256 __DEFAULT_FN_ATTRS512 _mm512_cvtpd_ps (__m512d __A) @@ -3765,38 +3765,38 @@ _mm512_mask_cvtpd_pslo (__m512 __W, __mmask8 __U,__m512d __A) } #define _mm512_cvt_roundps_ph(A, I) \ - (__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ - (__v16hi)_mm256_undefined_si256(), \ - (__mmask16)-1) + ((__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ + (__v16hi)_mm256_undefined_si256(), \ + (__mmask16)-1)) #define _mm512_mask_cvt_roundps_ph(U, W, A, I) \ - (__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ - (__v16hi)(__m256i)(U), \ - (__mmask16)(W)) + ((__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ + (__v16hi)(__m256i)(U), \ + (__mmask16)(W))) #define _mm512_maskz_cvt_roundps_ph(W, A, I) \ - (__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ - (__v16hi)_mm256_setzero_si256(), \ - (__mmask16)(W)) + ((__m256i)__builtin_ia32_vcvtps2ph512_mask((__v16sf)(__m512)(A), (int)(I), \ + (__v16hi)_mm256_setzero_si256(), \ + (__mmask16)(W))) #define _mm512_cvtps_ph _mm512_cvt_roundps_ph #define _mm512_mask_cvtps_ph _mm512_mask_cvt_roundps_ph #define _mm512_maskz_cvtps_ph _mm512_maskz_cvt_roundps_ph #define _mm512_cvt_roundph_ps(A, R) \ - (__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvt_roundph_ps(W, U, A, R) \ - (__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvt_roundph_ps(U, A, R) \ - (__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_vcvtph2ps512_mask((__v16hi)(__m256i)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) static __inline __m512 __DEFAULT_FN_ATTRS512 @@ -3828,19 +3828,19 @@ _mm512_maskz_cvtph_ps (__mmask16 __U, __m256i __A) } #define _mm512_cvtt_roundpd_epi32(A, R) \ - (__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)-1, (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundpd_epi32(W, U, A, R) \ - (__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)(__m256i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundpd_epi32(U, A, R) \ - (__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)(U), (int)(R))) static __inline __m256i __DEFAULT_FN_ATTRS512 _mm512_cvttpd_epi32(__m512d __a) @@ -3870,19 +3870,19 @@ _mm512_maskz_cvttpd_epi32 (__mmask8 __U, __m512d __A) } #define _mm512_cvtt_roundps_epi32(A, R) \ - (__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvtt_roundps_epi32(W, U, A, R) \ - (__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)(__m512i)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)(__m512i)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvtt_roundps_epi32(U, A, R) \ - (__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvttps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)(U), (int)(R))) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_cvttps_epi32(__m512 __a) @@ -3912,19 +3912,19 @@ _mm512_maskz_cvttps_epi32 (__mmask16 __U, __m512 __A) } #define _mm512_cvt_roundps_epi32(A, R) \ - (__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvt_roundps_epi32(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)(__m512i)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)(__m512i)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvt_roundps_epi32(U, A, R) \ - (__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2dq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvtps_epi32 (__m512 __A) @@ -3955,19 +3955,19 @@ _mm512_maskz_cvtps_epi32 (__mmask16 __U, __m512 __A) } #define _mm512_cvt_roundpd_epi32(A, R) \ - (__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)-1, (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundpd_epi32(W, U, A, R) \ - (__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)(__m256i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundpd_epi32(U, A, R) \ - (__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2dq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256i __DEFAULT_FN_ATTRS512 _mm512_cvtpd_epi32 (__m512d __A) @@ -3999,19 +3999,19 @@ _mm512_maskz_cvtpd_epi32 (__mmask8 __U, __m512d __A) } #define _mm512_cvt_roundps_epu32(A, R) \ - (__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)-1, (int)(R)) + ((__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_cvt_roundps_epu32(W, U, A, R) \ - (__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)(__m512i)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)(__m512i)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_cvt_roundps_epu32(U, A, R) \ - (__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ - (__v16si)_mm512_setzero_si512(), \ - (__mmask16)(U), (int)(R)) + ((__m512i)__builtin_ia32_cvtps2udq512_mask((__v16sf)(__m512)(A), \ + (__v16si)_mm512_setzero_si512(), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_cvtps_epu32 ( __m512 __A) @@ -4043,19 +4043,19 @@ _mm512_maskz_cvtps_epu32 ( __mmask16 __U, __m512 __A) } #define _mm512_cvt_roundpd_epu32(A, R) \ - (__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)-1, (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundpd_epu32(W, U, A, R) \ - (__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)(__m256i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundpd_epu32(U, A, R) \ - (__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvtpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256i __DEFAULT_FN_ATTRS512 _mm512_cvtpd_epu32 (__m512d __A) @@ -4975,70 +4975,70 @@ _mm512_maskz_rorv_epi64 (__mmask8 __U, __m512i __A, __m512i __B) #define _mm512_cmp_epi32_mask(a, b, p) \ - (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \ - (__v16si)(__m512i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \ + (__v16si)(__m512i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm512_cmp_epu32_mask(a, b, p) \ - (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \ - (__v16si)(__m512i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \ + (__v16si)(__m512i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm512_cmp_epi64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \ - (__v8di)(__m512i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \ + (__v8di)(__m512i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm512_cmp_epu64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \ - (__v8di)(__m512i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \ + (__v8di)(__m512i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm512_mask_cmp_epi32_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \ - (__v16si)(__m512i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_cmpd512_mask((__v16si)(__m512i)(a), \ + (__v16si)(__m512i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm512_mask_cmp_epu32_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \ - (__v16si)(__m512i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)(__m512i)(a), \ + (__v16si)(__m512i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm512_mask_cmp_epi64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \ - (__v8di)(__m512i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpq512_mask((__v8di)(__m512i)(a), \ + (__v8di)(__m512i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm512_mask_cmp_epu64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \ - (__v8di)(__m512i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)(__m512i)(a), \ + (__v8di)(__m512i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm512_rol_epi32(a, b) \ - (__m512i)__builtin_ia32_prold512((__v16si)(__m512i)(a), (int)(b)) + ((__m512i)__builtin_ia32_prold512((__v16si)(__m512i)(a), (int)(b))) #define _mm512_mask_rol_epi32(W, U, a, b) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_rol_epi32((a), (b)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_rol_epi32((a), (b)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_rol_epi32(U, a, b) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_rol_epi32((a), (b)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_rol_epi32((a), (b)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_rol_epi64(a, b) \ - (__m512i)__builtin_ia32_prolq512((__v8di)(__m512i)(a), (int)(b)) + ((__m512i)__builtin_ia32_prolq512((__v8di)(__m512i)(a), (int)(b))) #define _mm512_mask_rol_epi64(W, U, a, b) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_rol_epi64((a), (b)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_rol_epi64((a), (b)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_rol_epi64(U, a, b) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_rol_epi64((a), (b)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_rol_epi64((a), (b)), \ + (__v8di)_mm512_setzero_si512())) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_rolv_epi32 (__m512i __A, __m512i __B) @@ -5085,30 +5085,30 @@ _mm512_maskz_rolv_epi64 (__mmask8 __U, __m512i __A, __m512i __B) } #define _mm512_ror_epi32(A, B) \ - (__m512i)__builtin_ia32_prord512((__v16si)(__m512i)(A), (int)(B)) + ((__m512i)__builtin_ia32_prord512((__v16si)(__m512i)(A), (int)(B))) #define _mm512_mask_ror_epi32(W, U, A, B) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_ror_epi32((A), (B)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_ror_epi32((A), (B)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_ror_epi32(U, A, B) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_ror_epi32((A), (B)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_ror_epi32((A), (B)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_ror_epi64(A, B) \ - (__m512i)__builtin_ia32_prorq512((__v8di)(__m512i)(A), (int)(B)) + ((__m512i)__builtin_ia32_prorq512((__v8di)(__m512i)(A), (int)(B))) #define _mm512_mask_ror_epi64(W, U, A, B) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_ror_epi64((A), (B)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_ror_epi64((A), (B)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_ror_epi64(U, A, B) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_ror_epi64((A), (B)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_ror_epi64((A), (B)), \ + (__v8di)_mm512_setzero_si512())) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_slli_epi32(__m512i __A, unsigned int __B) @@ -5304,168 +5304,168 @@ _mm512_maskz_movedup_pd (__mmask8 __U, __m512d __A) } #define _mm512_fixupimm_round_pd(A, B, C, imm, R) \ - (__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_fixupimm_round_pd(A, U, B, C, imm, R) \ - (__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)(U), (int)(R))) #define _mm512_fixupimm_pd(A, B, C, imm) \ - (__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_fixupimm_pd(A, U, B, C, imm) \ - (__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_fixupimmpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_fixupimm_round_pd(U, A, B, C, imm, R) \ - (__m512d)__builtin_ia32_fixupimmpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), \ - (int)(imm), (__mmask8)(U), \ - (int)(R)) + ((__m512d)__builtin_ia32_fixupimmpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), \ + (int)(imm), (__mmask8)(U), \ + (int)(R))) #define _mm512_maskz_fixupimm_pd(U, A, B, C, imm) \ - (__m512d)__builtin_ia32_fixupimmpd512_maskz((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8di)(__m512i)(C), \ - (int)(imm), (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_fixupimmpd512_maskz((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8di)(__m512i)(C), \ + (int)(imm), (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_fixupimm_round_ps(A, B, C, imm, R) \ - (__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_fixupimm_round_ps(A, U, B, C, imm, R) \ - (__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)(U), (int)(R))) #define _mm512_fixupimm_ps(A, B, C, imm) \ - (__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_fixupimm_ps(A, U, B, C, imm) \ - (__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_fixupimmps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_fixupimm_round_ps(U, A, B, C, imm, R) \ - (__m512)__builtin_ia32_fixupimmps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), \ - (int)(imm), (__mmask16)(U), \ - (int)(R)) + ((__m512)__builtin_ia32_fixupimmps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), \ + (int)(imm), (__mmask16)(U), \ + (int)(R))) #define _mm512_maskz_fixupimm_ps(U, A, B, C, imm) \ - (__m512)__builtin_ia32_fixupimmps512_maskz((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16si)(__m512i)(C), \ - (int)(imm), (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_fixupimmps512_maskz((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16si)(__m512i)(C), \ + (int)(imm), (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_fixupimm_round_sd(A, B, C, imm, R) \ - (__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)-1, (int)(R)) - -#define _mm_mask_fixupimm_round_sd(A, U, B, C, imm, R) \ - (__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), (int)(R)) - -#define _mm_fixupimm_sd(A, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_fixupimm_sd(A, U, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_fixupimm_round_sd(U, A, B, C, imm, R) \ - (__m128d)__builtin_ia32_fixupimmsd_maskz((__v2df)(__m128d)(A), \ + ((__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ (__v2df)(__m128d)(B), \ (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), (int)(R)) + (__mmask8)-1, (int)(R))) -#define _mm_maskz_fixupimm_sd(U, A, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmsd_maskz((__v2df)(__m128d)(A), \ +#define _mm_mask_fixupimm_round_sd(A, U, B, C, imm, R) \ + ((__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), (int)(R))) + +#define _mm_fixupimm_sd(A, B, C, imm) \ + ((__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_fixupimm_sd(A, U, B, C, imm) \ + ((__m128d)__builtin_ia32_fixupimmsd_mask((__v2df)(__m128d)(A), \ (__v2df)(__m128d)(B), \ (__v2di)(__m128i)(C), (int)(imm), \ (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + _MM_FROUND_CUR_DIRECTION)) + +#define _mm_maskz_fixupimm_round_sd(U, A, B, C, imm, R) \ + ((__m128d)__builtin_ia32_fixupimmsd_maskz((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fixupimm_sd(U, A, B, C, imm) \ + ((__m128d)__builtin_ia32_fixupimmsd_maskz((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_fixupimm_round_ss(A, B, C, imm, R) \ - (__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)-1, (int)(R)) - -#define _mm_mask_fixupimm_round_ss(A, U, B, C, imm, R) \ - (__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), (int)(R)) - -#define _mm_fixupimm_ss(A, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) - -#define _mm_mask_fixupimm_ss(A, U, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) - -#define _mm_maskz_fixupimm_round_ss(U, A, B, C, imm, R) \ - (__m128)__builtin_ia32_fixupimmss_maskz((__v4sf)(__m128)(A), \ + ((__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ (__v4sf)(__m128)(B), \ (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U), (int)(R)) + (__mmask8)-1, (int)(R))) -#define _mm_maskz_fixupimm_ss(U, A, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmss_maskz((__v4sf)(__m128)(A), \ +#define _mm_mask_fixupimm_round_ss(A, U, B, C, imm, R) \ + ((__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), (int)(R))) + +#define _mm_fixupimm_ss(A, B, C, imm) \ + ((__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_fixupimm_ss(A, U, B, C, imm) \ + ((__m128)__builtin_ia32_fixupimmss_mask((__v4sf)(__m128)(A), \ (__v4sf)(__m128)(B), \ (__v4si)(__m128i)(C), (int)(imm), \ (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + _MM_FROUND_CUR_DIRECTION)) + +#define _mm_maskz_fixupimm_round_ss(U, A, B, C, imm, R) \ + ((__m128)__builtin_ia32_fixupimmss_maskz((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fixupimm_ss(U, A, B, C, imm) \ + ((__m128)__builtin_ia32_fixupimmss_maskz((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_getexp_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 @@ -5486,10 +5486,10 @@ _mm_mask_getexp_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_mask_getexp_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_getexp_sd (__mmask8 __U, __m128d __A, __m128d __B) @@ -5502,16 +5502,16 @@ _mm_maskz_getexp_sd (__mmask8 __U, __m128d __A, __m128d __B) } #define _mm_maskz_getexp_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_getexpsd128_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm_getexp_round_ss(A, B, R) \ - (__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_getexp_ss (__m128 __A, __m128 __B) @@ -5531,10 +5531,10 @@ _mm_mask_getexp_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_mask_getexp_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_getexp_ss (__mmask8 __U, __m128 __A, __m128 __B) @@ -5547,100 +5547,100 @@ _mm_maskz_getexp_ss (__mmask8 __U, __m128 __A, __m128 __B) } #define _mm_maskz_getexp_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_getexpss128_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) #define _mm_getmant_round_sd(A, B, C, D, R) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_getmant_sd(A, B, C, D) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_getmant_sd(W, U, A, B, C, D) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_getmant_round_sd(W, U, A, B, C, D, R) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_getmant_sd(U, A, B, C, D) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_getmant_round_sd(U, A, B, C, D, R) \ - (__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (int)(((D)<<2) | (C)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_getmantsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (int)(((D)<<2) | (C)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm_getmant_round_ss(A, B, C, D, R) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_getmant_ss(A, B, C, D) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_getmant_ss(W, U, A, B, C, D) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_getmant_round_ss(W, U, A, B, C, D, R) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_getmant_ss(U, A, B, C, D) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_getmant_round_ss(U, A, B, C, D, R) \ - (__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (int)(((D)<<2) | (C)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_getmantss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (int)(((D)<<2) | (C)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __mmask16 __DEFAULT_FN_ATTRS _mm512_kmov (__mmask16 __A) @@ -5649,16 +5649,16 @@ _mm512_kmov (__mmask16 __A) } #define _mm_comi_round_sd(A, B, P, R) \ - (int)__builtin_ia32_vcomisd((__v2df)(__m128d)(A), (__v2df)(__m128d)(B), \ - (int)(P), (int)(R)) + ((int)__builtin_ia32_vcomisd((__v2df)(__m128d)(A), (__v2df)(__m128d)(B), \ + (int)(P), (int)(R))) #define _mm_comi_round_ss(A, B, P, R) \ - (int)__builtin_ia32_vcomiss((__v4sf)(__m128)(A), (__v4sf)(__m128)(B), \ - (int)(P), (int)(R)) + ((int)__builtin_ia32_vcomiss((__v4sf)(__m128)(A), (__v4sf)(__m128)(B), \ + (int)(P), (int)(R))) #ifdef __x86_64__ #define _mm_cvt_roundsd_si64(A, R) \ - (long long)__builtin_ia32_vcvtsd2si64((__v2df)(__m128d)(A), (int)(R)) + ((long long)__builtin_ia32_vcvtsd2si64((__v2df)(__m128d)(A), (int)(R))) #endif static __inline__ __m512i __DEFAULT_FN_ATTRS512 @@ -5926,54 +5926,54 @@ _mm512_maskz_srlv_epi64(__mmask8 __U, __m512i __X, __m512i __Y) } #define _mm512_ternarylogic_epi32(A, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogd512_mask((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)-1) + ((__m512i)__builtin_ia32_pternlogd512_mask((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)-1)) #define _mm512_mask_ternarylogic_epi32(A, U, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogd512_mask((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), \ - (__v16si)(__m512i)(C), (int)(imm), \ - (__mmask16)(U)) + ((__m512i)__builtin_ia32_pternlogd512_mask((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), \ + (__v16si)(__m512i)(C), (int)(imm), \ + (__mmask16)(U))) #define _mm512_maskz_ternarylogic_epi32(U, A, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogd512_maskz((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), \ - (__v16si)(__m512i)(C), \ - (int)(imm), (__mmask16)(U)) + ((__m512i)__builtin_ia32_pternlogd512_maskz((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), \ + (__v16si)(__m512i)(C), \ + (int)(imm), (__mmask16)(U))) #define _mm512_ternarylogic_epi64(A, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogq512_mask((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm512_mask_ternarylogic_epi64(A, U, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogq512_mask((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), \ - (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm512_maskz_ternarylogic_epi64(U, A, B, C, imm) \ - (__m512i)__builtin_ia32_pternlogq512_maskz((__v8di)(__m512i)(A), \ + ((__m512i)__builtin_ia32_pternlogq512_mask((__v8di)(__m512i)(A), \ (__v8di)(__m512i)(B), \ (__v8di)(__m512i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm512_mask_ternarylogic_epi64(A, U, B, C, imm) \ + ((__m512i)__builtin_ia32_pternlogq512_mask((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm512_maskz_ternarylogic_epi64(U, A, B, C, imm) \ + ((__m512i)__builtin_ia32_pternlogq512_maskz((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), \ + (__v8di)(__m512i)(C), (int)(imm), \ + (__mmask8)(U))) #ifdef __x86_64__ #define _mm_cvt_roundsd_i64(A, R) \ - (long long)__builtin_ia32_vcvtsd2si64((__v2df)(__m128d)(A), (int)(R)) + ((long long)__builtin_ia32_vcvtsd2si64((__v2df)(__m128d)(A), (int)(R))) #endif #define _mm_cvt_roundsd_si32(A, R) \ - (int)__builtin_ia32_vcvtsd2si32((__v2df)(__m128d)(A), (int)(R)) + ((int)__builtin_ia32_vcvtsd2si32((__v2df)(__m128d)(A), (int)(R))) #define _mm_cvt_roundsd_i32(A, R) \ - (int)__builtin_ia32_vcvtsd2si32((__v2df)(__m128d)(A), (int)(R)) + ((int)__builtin_ia32_vcvtsd2si32((__v2df)(__m128d)(A), (int)(R))) #define _mm_cvt_roundsd_u32(A, R) \ - (unsigned int)__builtin_ia32_vcvtsd2usi32((__v2df)(__m128d)(A), (int)(R)) + ((unsigned int)__builtin_ia32_vcvtsd2usi32((__v2df)(__m128d)(A), (int)(R))) static __inline__ unsigned __DEFAULT_FN_ATTRS128 _mm_cvtsd_u32 (__m128d __A) @@ -5984,8 +5984,8 @@ _mm_cvtsd_u32 (__m128d __A) #ifdef __x86_64__ #define _mm_cvt_roundsd_u64(A, R) \ - (unsigned long long)__builtin_ia32_vcvtsd2usi64((__v2df)(__m128d)(A), \ - (int)(R)) + ((unsigned long long)__builtin_ia32_vcvtsd2usi64((__v2df)(__m128d)(A), \ + (int)(R))) static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 _mm_cvtsd_u64 (__m128d __A) @@ -5997,21 +5997,21 @@ _mm_cvtsd_u64 (__m128d __A) #endif #define _mm_cvt_roundss_si32(A, R) \ - (int)__builtin_ia32_vcvtss2si32((__v4sf)(__m128)(A), (int)(R)) + ((int)__builtin_ia32_vcvtss2si32((__v4sf)(__m128)(A), (int)(R))) #define _mm_cvt_roundss_i32(A, R) \ - (int)__builtin_ia32_vcvtss2si32((__v4sf)(__m128)(A), (int)(R)) + ((int)__builtin_ia32_vcvtss2si32((__v4sf)(__m128)(A), (int)(R))) #ifdef __x86_64__ #define _mm_cvt_roundss_si64(A, R) \ - (long long)__builtin_ia32_vcvtss2si64((__v4sf)(__m128)(A), (int)(R)) + ((long long)__builtin_ia32_vcvtss2si64((__v4sf)(__m128)(A), (int)(R))) #define _mm_cvt_roundss_i64(A, R) \ - (long long)__builtin_ia32_vcvtss2si64((__v4sf)(__m128)(A), (int)(R)) + ((long long)__builtin_ia32_vcvtss2si64((__v4sf)(__m128)(A), (int)(R))) #endif #define _mm_cvt_roundss_u32(A, R) \ - (unsigned int)__builtin_ia32_vcvtss2usi32((__v4sf)(__m128)(A), (int)(R)) + ((unsigned int)__builtin_ia32_vcvtss2usi32((__v4sf)(__m128)(A), (int)(R))) static __inline__ unsigned __DEFAULT_FN_ATTRS128 _mm_cvtss_u32 (__m128 __A) @@ -6022,8 +6022,8 @@ _mm_cvtss_u32 (__m128 __A) #ifdef __x86_64__ #define _mm_cvt_roundss_u64(A, R) \ - (unsigned long long)__builtin_ia32_vcvtss2usi64((__v4sf)(__m128)(A), \ - (int)(R)) + ((unsigned long long)__builtin_ia32_vcvtss2usi64((__v4sf)(__m128)(A), \ + (int)(R))) static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 _mm_cvtss_u64 (__m128 __A) @@ -6035,10 +6035,10 @@ _mm_cvtss_u64 (__m128 __A) #endif #define _mm_cvtt_roundsd_i32(A, R) \ - (int)__builtin_ia32_vcvttsd2si32((__v2df)(__m128d)(A), (int)(R)) + ((int)__builtin_ia32_vcvttsd2si32((__v2df)(__m128d)(A), (int)(R))) #define _mm_cvtt_roundsd_si32(A, R) \ - (int)__builtin_ia32_vcvttsd2si32((__v2df)(__m128d)(A), (int)(R)) + ((int)__builtin_ia32_vcvttsd2si32((__v2df)(__m128d)(A), (int)(R))) static __inline__ int __DEFAULT_FN_ATTRS128 _mm_cvttsd_i32 (__m128d __A) @@ -6049,10 +6049,10 @@ _mm_cvttsd_i32 (__m128d __A) #ifdef __x86_64__ #define _mm_cvtt_roundsd_si64(A, R) \ - (long long)__builtin_ia32_vcvttsd2si64((__v2df)(__m128d)(A), (int)(R)) + ((long long)__builtin_ia32_vcvttsd2si64((__v2df)(__m128d)(A), (int)(R))) #define _mm_cvtt_roundsd_i64(A, R) \ - (long long)__builtin_ia32_vcvttsd2si64((__v2df)(__m128d)(A), (int)(R)) + ((long long)__builtin_ia32_vcvttsd2si64((__v2df)(__m128d)(A), (int)(R))) static __inline__ long long __DEFAULT_FN_ATTRS128 _mm_cvttsd_i64 (__m128d __A) @@ -6063,7 +6063,7 @@ _mm_cvttsd_i64 (__m128d __A) #endif #define _mm_cvtt_roundsd_u32(A, R) \ - (unsigned int)__builtin_ia32_vcvttsd2usi32((__v2df)(__m128d)(A), (int)(R)) + ((unsigned int)__builtin_ia32_vcvttsd2usi32((__v2df)(__m128d)(A), (int)(R))) static __inline__ unsigned __DEFAULT_FN_ATTRS128 _mm_cvttsd_u32 (__m128d __A) @@ -6074,8 +6074,8 @@ _mm_cvttsd_u32 (__m128d __A) #ifdef __x86_64__ #define _mm_cvtt_roundsd_u64(A, R) \ - (unsigned long long)__builtin_ia32_vcvttsd2usi64((__v2df)(__m128d)(A), \ - (int)(R)) + ((unsigned long long)__builtin_ia32_vcvttsd2usi64((__v2df)(__m128d)(A), \ + (int)(R))) static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 _mm_cvttsd_u64 (__m128d __A) @@ -6087,10 +6087,10 @@ _mm_cvttsd_u64 (__m128d __A) #endif #define _mm_cvtt_roundss_i32(A, R) \ - (int)__builtin_ia32_vcvttss2si32((__v4sf)(__m128)(A), (int)(R)) + ((int)__builtin_ia32_vcvttss2si32((__v4sf)(__m128)(A), (int)(R))) #define _mm_cvtt_roundss_si32(A, R) \ - (int)__builtin_ia32_vcvttss2si32((__v4sf)(__m128)(A), (int)(R)) + ((int)__builtin_ia32_vcvttss2si32((__v4sf)(__m128)(A), (int)(R))) static __inline__ int __DEFAULT_FN_ATTRS128 _mm_cvttss_i32 (__m128 __A) @@ -6101,10 +6101,10 @@ _mm_cvttss_i32 (__m128 __A) #ifdef __x86_64__ #define _mm_cvtt_roundss_i64(A, R) \ - (long long)__builtin_ia32_vcvttss2si64((__v4sf)(__m128)(A), (int)(R)) + ((long long)__builtin_ia32_vcvttss2si64((__v4sf)(__m128)(A), (int)(R))) #define _mm_cvtt_roundss_si64(A, R) \ - (long long)__builtin_ia32_vcvttss2si64((__v4sf)(__m128)(A), (int)(R)) + ((long long)__builtin_ia32_vcvttss2si64((__v4sf)(__m128)(A), (int)(R))) static __inline__ long long __DEFAULT_FN_ATTRS128 _mm_cvttss_i64 (__m128 __A) @@ -6115,7 +6115,7 @@ _mm_cvttss_i64 (__m128 __A) #endif #define _mm_cvtt_roundss_u32(A, R) \ - (unsigned int)__builtin_ia32_vcvttss2usi32((__v4sf)(__m128)(A), (int)(R)) + ((unsigned int)__builtin_ia32_vcvttss2usi32((__v4sf)(__m128)(A), (int)(R))) static __inline__ unsigned __DEFAULT_FN_ATTRS128 _mm_cvttss_u32 (__m128 __A) @@ -6126,8 +6126,8 @@ _mm_cvttss_u32 (__m128 __A) #ifdef __x86_64__ #define _mm_cvtt_roundss_u64(A, R) \ - (unsigned long long)__builtin_ia32_vcvttss2usi64((__v4sf)(__m128)(A), \ - (int)(R)) + ((unsigned long long)__builtin_ia32_vcvttss2usi64((__v4sf)(__m128)(A), \ + (int)(R))) static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 _mm_cvttss_u64 (__m128 __A) @@ -6139,30 +6139,30 @@ _mm_cvttss_u64 (__m128 __A) #endif #define _mm512_permute_pd(X, C) \ - (__m512d)__builtin_ia32_vpermilpd512((__v8df)(__m512d)(X), (int)(C)) + ((__m512d)__builtin_ia32_vpermilpd512((__v8df)(__m512d)(X), (int)(C))) #define _mm512_mask_permute_pd(W, U, X, C) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_permute_pd((X), (C)), \ - (__v8df)(__m512d)(W)) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_permute_pd((X), (C)), \ + (__v8df)(__m512d)(W))) #define _mm512_maskz_permute_pd(U, X, C) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_permute_pd((X), (C)), \ - (__v8df)_mm512_setzero_pd()) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_permute_pd((X), (C)), \ + (__v8df)_mm512_setzero_pd())) #define _mm512_permute_ps(X, C) \ - (__m512)__builtin_ia32_vpermilps512((__v16sf)(__m512)(X), (int)(C)) + ((__m512)__builtin_ia32_vpermilps512((__v16sf)(__m512)(X), (int)(C))) #define _mm512_mask_permute_ps(W, U, X, C) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_permute_ps((X), (C)), \ - (__v16sf)(__m512)(W)) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_permute_ps((X), (C)), \ + (__v16sf)(__m512)(W))) #define _mm512_maskz_permute_ps(U, X, C) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_permute_ps((X), (C)), \ - (__v16sf)_mm512_setzero_ps()) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_permute_ps((X), (C)), \ + (__v16sf)_mm512_setzero_ps())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_permutevar_pd(__m512d __A, __m512i __C) @@ -6274,19 +6274,19 @@ _mm512_maskz_permutex2var_ps(__mmask16 __U, __m512 __A, __m512i __I, __m512 __B) #define _mm512_cvtt_roundpd_epu32(A, R) \ - (__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_undefined_si256(), \ - (__mmask8)-1, (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_undefined_si256(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvtt_roundpd_epu32(W, U, A, R) \ - (__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)(__m256i)(W), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)(__m256i)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvtt_roundpd_epu32(U, A, R) \ - (__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ - (__v8si)_mm256_setzero_si256(), \ - (__mmask8)(U), (int)(R)) + ((__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ + (__v8si)_mm256_setzero_si256(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m256i __DEFAULT_FN_ATTRS512 _mm512_cvttpd_epu32 (__m512d __A) @@ -6318,106 +6318,106 @@ _mm512_maskz_cvttpd_epu32 (__mmask8 __U, __m512d __A) } #define _mm_roundscale_round_sd(A, B, imm, R) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(imm), \ - (int)(R)) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(imm), \ + (int)(R))) #define _mm_roundscale_sd(A, B, imm) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(imm), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(imm), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_roundscale_sd(W, U, A, B, imm) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(imm), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(imm), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_roundscale_round_sd(W, U, A, B, I, R) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(I), \ - (int)(R)) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(I), \ + (int)(R))) #define _mm_maskz_roundscale_sd(U, A, B, I) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(I), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(I), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_roundscale_round_sd(U, A, B, I, R) \ - (__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(I), \ - (int)(R)) + ((__m128d)__builtin_ia32_rndscalesd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(I), \ + (int)(R))) #define _mm_roundscale_round_ss(A, B, imm, R) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(imm), \ - (int)(R)) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(imm), \ + (int)(R))) #define _mm_roundscale_ss(A, B, imm) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(imm), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(imm), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_roundscale_ss(W, U, A, B, I) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(I), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(I), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_roundscale_round_ss(W, U, A, B, I, R) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(I), \ - (int)(R)) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(I), \ + (int)(R))) #define _mm_maskz_roundscale_ss(U, A, B, I) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(I), \ - _MM_FROUND_CUR_DIRECTION) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(I), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_maskz_roundscale_round_ss(U, A, B, I, R) \ - (__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(I), \ - (int)(R)) + ((__m128)__builtin_ia32_rndscaless_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(I), \ + (int)(R))) #define _mm512_scalef_round_pd(A, B, R) \ - (__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_scalef_round_pd(W, U, A, B, R) \ - (__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_scalef_round_pd(U, A, B, R) \ - (__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_scalefpd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_scalef_pd (__m512d __A, __m512d __B) @@ -6452,22 +6452,22 @@ _mm512_maskz_scalef_pd (__mmask8 __U, __m512d __A, __m512d __B) } #define _mm512_scalef_round_ps(A, B, R) \ - (__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_scalef_round_ps(W, U, A, B, R) \ - (__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_scalef_round_ps(U, A, B, R) \ - (__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_scalefps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_scalef_ps (__m512 __A, __m512 __B) @@ -6502,10 +6502,10 @@ _mm512_maskz_scalef_ps (__mmask16 __U, __m512 __A, __m512 __B) } #define _mm_scalef_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_scalef_sd (__m128d __A, __m128d __B) @@ -6527,10 +6527,10 @@ _mm_mask_scalef_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_mask_scalef_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_scalef_sd (__mmask8 __U, __m128d __A, __m128d __B) @@ -6543,16 +6543,16 @@ _mm_maskz_scalef_sd (__mmask8 __U, __m128d __A, __m128d __B) } #define _mm_maskz_scalef_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_scalefsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm_scalef_round_ss(A, B, R) \ - (__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_scalef_ss (__m128 __A, __m128 __B) @@ -6574,10 +6574,10 @@ _mm_mask_scalef_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_mask_scalef_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_scalef_ss (__mmask8 __U, __m128 __A, __m128 __B) @@ -6590,11 +6590,11 @@ _mm_maskz_scalef_ss (__mmask8 __U, __m128 __A, __m128 __B) } #define _mm_maskz_scalef_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_scalefss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), \ + (int)(R))) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_srai_epi32(__m512i __A, unsigned int __B) @@ -6642,94 +6642,94 @@ _mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, unsigned int __B) } #define _mm512_shuffle_f32x4(A, B, imm) \ - (__m512)__builtin_ia32_shuf_f32x4((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(imm)) + ((__m512)__builtin_ia32_shuf_f32x4((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(imm))) #define _mm512_mask_shuffle_f32x4(W, U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ - (__v16sf)(__m512)(W)) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ + (__v16sf)(__m512)(W))) #define _mm512_maskz_shuffle_f32x4(U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ - (__v16sf)_mm512_setzero_ps()) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ + (__v16sf)_mm512_setzero_ps())) #define _mm512_shuffle_f64x2(A, B, imm) \ - (__m512d)__builtin_ia32_shuf_f64x2((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(imm)) + ((__m512d)__builtin_ia32_shuf_f64x2((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(imm))) #define _mm512_mask_shuffle_f64x2(W, U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ - (__v8df)(__m512d)(W)) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ + (__v8df)(__m512d)(W))) #define _mm512_maskz_shuffle_f64x2(U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ - (__v8df)_mm512_setzero_pd()) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ + (__v8df)_mm512_setzero_pd())) #define _mm512_shuffle_i32x4(A, B, imm) \ - (__m512i)__builtin_ia32_shuf_i32x4((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_shuf_i32x4((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), (int)(imm))) #define _mm512_mask_shuffle_i32x4(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_shuffle_i32x4(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_shuffle_i64x2(A, B, imm) \ - (__m512i)__builtin_ia32_shuf_i64x2((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_shuf_i64x2((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), (int)(imm))) #define _mm512_mask_shuffle_i64x2(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_shuffle_i64x2(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ + (__v8di)_mm512_setzero_si512())) #define _mm512_shuffle_pd(A, B, M) \ - (__m512d)__builtin_ia32_shufpd512((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(B), (int)(M)) + ((__m512d)__builtin_ia32_shufpd512((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(B), (int)(M))) #define _mm512_mask_shuffle_pd(W, U, A, B, M) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_shuffle_pd((A), (B), (M)), \ - (__v8df)(__m512d)(W)) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_pd((A), (B), (M)), \ + (__v8df)(__m512d)(W))) #define _mm512_maskz_shuffle_pd(U, A, B, M) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_shuffle_pd((A), (B), (M)), \ - (__v8df)_mm512_setzero_pd()) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_shuffle_pd((A), (B), (M)), \ + (__v8df)_mm512_setzero_pd())) #define _mm512_shuffle_ps(A, B, M) \ - (__m512)__builtin_ia32_shufps512((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(B), (int)(M)) + ((__m512)__builtin_ia32_shufps512((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(B), (int)(M))) #define _mm512_mask_shuffle_ps(W, U, A, B, M) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_shuffle_ps((A), (B), (M)), \ - (__v16sf)(__m512)(W)) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_ps((A), (B), (M)), \ + (__v16sf)(__m512)(W))) #define _mm512_maskz_shuffle_ps(U, A, B, M) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_shuffle_ps((A), (B), (M)), \ - (__v16sf)_mm512_setzero_ps()) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_shuffle_ps((A), (B), (M)), \ + (__v16sf)_mm512_setzero_ps())) #define _mm_sqrt_round_sd(A, B, R) \ - (__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_sqrt_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) @@ -6742,10 +6742,10 @@ _mm_mask_sqrt_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_mask_sqrt_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_sqrt_sd (__mmask8 __U, __m128d __A, __m128d __B) @@ -6758,16 +6758,16 @@ _mm_maskz_sqrt_sd (__mmask8 __U, __m128d __A, __m128d __B) } #define _mm_maskz_sqrt_round_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_sqrtsd_round_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm_sqrt_round_ss(A, B, R) \ - (__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1, (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_sqrt_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) @@ -6780,10 +6780,10 @@ _mm_mask_sqrt_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_mask_sqrt_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(W), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(W), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_sqrt_ss (__mmask8 __U, __m128 __A, __m128 __B) @@ -6796,10 +6796,10 @@ _mm_maskz_sqrt_ss (__mmask8 __U, __m128 __A, __m128 __B) } #define _mm_maskz_sqrt_round_ss(U, A, B, R) \ - (__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_sqrtss_round_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_broadcast_f32x4(__m128 __A) @@ -7366,183 +7366,183 @@ _mm512_mask_cvtepi64_storeu_epi16 (void *__P, __mmask8 __M, __m512i __A) } #define _mm512_extracti32x4_epi32(A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v4si)_mm_undefined_si128(), \ - (__mmask8)-1) + ((__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v4si)_mm_undefined_si128(), \ + (__mmask8)-1)) #define _mm512_mask_extracti32x4_epi32(W, U, A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v4si)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v4si)(__m128i)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extracti32x4_epi32(U, A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ - (__v4si)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti32x4_mask((__v16si)(__m512i)(A), (int)(imm), \ + (__v4si)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm512_extracti64x4_epi64(A, imm) \ - (__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ - (__v4di)_mm256_undefined_si256(), \ - (__mmask8)-1) + ((__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ + (__v4di)_mm256_undefined_si256(), \ + (__mmask8)-1)) #define _mm512_mask_extracti64x4_epi64(W, U, A, imm) \ - (__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ - (__v4di)(__m256i)(W), \ - (__mmask8)(U)) + ((__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ + (__v4di)(__m256i)(W), \ + (__mmask8)(U))) #define _mm512_maskz_extracti64x4_epi64(U, A, imm) \ - (__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ - (__v4di)_mm256_setzero_si256(), \ - (__mmask8)(U)) + ((__m256i)__builtin_ia32_extracti64x4_mask((__v8di)(__m512i)(A), (int)(imm), \ + (__v4di)_mm256_setzero_si256(), \ + (__mmask8)(U))) #define _mm512_insertf64x4(A, B, imm) \ - (__m512d)__builtin_ia32_insertf64x4((__v8df)(__m512d)(A), \ - (__v4df)(__m256d)(B), (int)(imm)) + ((__m512d)__builtin_ia32_insertf64x4((__v8df)(__m512d)(A), \ + (__v4df)(__m256d)(B), (int)(imm))) #define _mm512_mask_insertf64x4(W, U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_insertf64x4((A), (B), (imm)), \ - (__v8df)(__m512d)(W)) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_insertf64x4((A), (B), (imm)), \ + (__v8df)(__m512d)(W))) #define _mm512_maskz_insertf64x4(U, A, B, imm) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_insertf64x4((A), (B), (imm)), \ - (__v8df)_mm512_setzero_pd()) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_insertf64x4((A), (B), (imm)), \ + (__v8df)_mm512_setzero_pd())) #define _mm512_inserti64x4(A, B, imm) \ - (__m512i)__builtin_ia32_inserti64x4((__v8di)(__m512i)(A), \ - (__v4di)(__m256i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_inserti64x4((__v8di)(__m512i)(A), \ + (__v4di)(__m256i)(B), (int)(imm))) #define _mm512_mask_inserti64x4(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_inserti64x4((A), (B), (imm)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_inserti64x4((A), (B), (imm)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_inserti64x4(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_inserti64x4((A), (B), (imm)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_inserti64x4((A), (B), (imm)), \ + (__v8di)_mm512_setzero_si512())) #define _mm512_insertf32x4(A, B, imm) \ - (__m512)__builtin_ia32_insertf32x4((__v16sf)(__m512)(A), \ - (__v4sf)(__m128)(B), (int)(imm)) + ((__m512)__builtin_ia32_insertf32x4((__v16sf)(__m512)(A), \ + (__v4sf)(__m128)(B), (int)(imm))) #define _mm512_mask_insertf32x4(W, U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_insertf32x4((A), (B), (imm)), \ - (__v16sf)(__m512)(W)) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_insertf32x4((A), (B), (imm)), \ + (__v16sf)(__m512)(W))) #define _mm512_maskz_insertf32x4(U, A, B, imm) \ - (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ - (__v16sf)_mm512_insertf32x4((A), (B), (imm)), \ - (__v16sf)_mm512_setzero_ps()) + ((__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ + (__v16sf)_mm512_insertf32x4((A), (B), (imm)), \ + (__v16sf)_mm512_setzero_ps())) #define _mm512_inserti32x4(A, B, imm) \ - (__m512i)__builtin_ia32_inserti32x4((__v16si)(__m512i)(A), \ - (__v4si)(__m128i)(B), (int)(imm)) + ((__m512i)__builtin_ia32_inserti32x4((__v16si)(__m512i)(A), \ + (__v4si)(__m128i)(B), (int)(imm))) #define _mm512_mask_inserti32x4(W, U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_inserti32x4((A), (B), (imm)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_inserti32x4((A), (B), (imm)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_inserti32x4(U, A, B, imm) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_inserti32x4((A), (B), (imm)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_inserti32x4((A), (B), (imm)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_getmant_round_pd(A, B, C, R) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_getmant_round_pd(W, U, A, B, C, R) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_getmant_round_pd(U, A, B, C, R) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) #define _mm512_getmant_pd(A, B, C) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_getmant_pd(W, U, A, B, C) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_getmant_pd(U, A, B, C) \ - (__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512d)__builtin_ia32_getmantpd512_mask((__v8df)(__m512d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_getmant_round_ps(A, B, C, R) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2) | (B)), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2) | (B)), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_getmant_round_ps(W, U, A, B, C, R) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2) | (B)), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2) | (B)), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_getmant_round_ps(U, A, B, C, R) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2) | (B)), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2) | (B)), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) #define _mm512_getmant_ps(A, B, C) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2)|(B)), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2)|(B)), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_mask_getmant_ps(W, U, A, B, C) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2)|(B)), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2)|(B)), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_maskz_getmant_ps(U, A, B, C) \ - (__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ - (int)(((C)<<2)|(B)), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), \ - _MM_FROUND_CUR_DIRECTION) + ((__m512)__builtin_ia32_getmantps512_mask((__v16sf)(__m512)(A), \ + (int)(((C)<<2)|(B)), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm512_getexp_round_pd(A, R) \ - (__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_getexp_round_pd(W, U, A, R) \ - (__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_getexp_round_pd(U, A, R) \ - (__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_getexppd512_mask((__v8df)(__m512d)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_getexp_pd (__m512d __A) @@ -7572,19 +7572,19 @@ _mm512_maskz_getexp_pd (__mmask8 __U, __m512d __A) } #define _mm512_getexp_round_ps(A, R) \ - (__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_undefined_ps(), \ - (__mmask16)-1, (int)(R)) + ((__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)-1, (int)(R))) #define _mm512_mask_getexp_round_ps(W, U, A, R) \ - (__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)(__m512)(W), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)(__m512)(W), \ + (__mmask16)(U), (int)(R))) #define _mm512_maskz_getexp_round_ps(U, A, R) \ - (__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ - (__v16sf)_mm512_setzero_ps(), \ - (__mmask16)(U), (int)(R)) + ((__m512)__builtin_ia32_getexpps512_mask((__v16sf)(__m512)(A), \ + (__v16sf)_mm512_setzero_ps(), \ + (__mmask16)(U), (int)(R))) static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_getexp_ps (__m512 __A) @@ -7614,100 +7614,100 @@ _mm512_maskz_getexp_ps (__mmask16 __U, __m512 __A) } #define _mm512_i64gather_ps(index, addr, scale) \ - (__m256)__builtin_ia32_gatherdiv16sf((__v8sf)_mm256_undefined_ps(), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), (__mmask8)-1, \ - (int)(scale)) + ((__m256)__builtin_ia32_gatherdiv16sf((__v8sf)_mm256_undefined_ps(), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), (__mmask8)-1, \ + (int)(scale))) #define _mm512_mask_i64gather_ps(v1_old, mask, index, addr, scale) \ - (__m256)__builtin_ia32_gatherdiv16sf((__v8sf)(__m256)(v1_old),\ - (void const *)(addr), \ - (__v8di)(__m512i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256)__builtin_ia32_gatherdiv16sf((__v8sf)(__m256)(v1_old),\ + (void const *)(addr), \ + (__v8di)(__m512i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i64gather_epi32(index, addr, scale) \ - (__m256i)__builtin_ia32_gatherdiv16si((__v8si)_mm256_undefined_si256(), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), \ - (__mmask8)-1, (int)(scale)) + ((__m256i)__builtin_ia32_gatherdiv16si((__v8si)_mm256_undefined_si256(), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), \ + (__mmask8)-1, (int)(scale))) #define _mm512_mask_i64gather_epi32(v1_old, mask, index, addr, scale) \ - (__m256i)__builtin_ia32_gatherdiv16si((__v8si)(__m256i)(v1_old), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256i)__builtin_ia32_gatherdiv16si((__v8si)(__m256i)(v1_old), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i64gather_pd(index, addr, scale) \ - (__m512d)__builtin_ia32_gatherdiv8df((__v8df)_mm512_undefined_pd(), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), (__mmask8)-1, \ - (int)(scale)) + ((__m512d)__builtin_ia32_gatherdiv8df((__v8df)_mm512_undefined_pd(), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), (__mmask8)-1, \ + (int)(scale))) #define _mm512_mask_i64gather_pd(v1_old, mask, index, addr, scale) \ - (__m512d)__builtin_ia32_gatherdiv8df((__v8df)(__m512d)(v1_old), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m512d)__builtin_ia32_gatherdiv8df((__v8df)(__m512d)(v1_old), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i64gather_epi64(index, addr, scale) \ - (__m512i)__builtin_ia32_gatherdiv8di((__v8di)_mm512_undefined_epi32(), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), (__mmask8)-1, \ - (int)(scale)) + ((__m512i)__builtin_ia32_gatherdiv8di((__v8di)_mm512_undefined_epi32(), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), (__mmask8)-1, \ + (int)(scale))) #define _mm512_mask_i64gather_epi64(v1_old, mask, index, addr, scale) \ - (__m512i)__builtin_ia32_gatherdiv8di((__v8di)(__m512i)(v1_old), \ - (void const *)(addr), \ - (__v8di)(__m512i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m512i)__builtin_ia32_gatherdiv8di((__v8di)(__m512i)(v1_old), \ + (void const *)(addr), \ + (__v8di)(__m512i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i32gather_ps(index, addr, scale) \ - (__m512)__builtin_ia32_gathersiv16sf((__v16sf)_mm512_undefined_ps(), \ - (void const *)(addr), \ - (__v16si)(__m512)(index), \ - (__mmask16)-1, (int)(scale)) + ((__m512)__builtin_ia32_gathersiv16sf((__v16sf)_mm512_undefined_ps(), \ + (void const *)(addr), \ + (__v16si)(__m512)(index), \ + (__mmask16)-1, (int)(scale))) #define _mm512_mask_i32gather_ps(v1_old, mask, index, addr, scale) \ - (__m512)__builtin_ia32_gathersiv16sf((__v16sf)(__m512)(v1_old), \ - (void const *)(addr), \ - (__v16si)(__m512)(index), \ - (__mmask16)(mask), (int)(scale)) + ((__m512)__builtin_ia32_gathersiv16sf((__v16sf)(__m512)(v1_old), \ + (void const *)(addr), \ + (__v16si)(__m512)(index), \ + (__mmask16)(mask), (int)(scale))) #define _mm512_i32gather_epi32(index, addr, scale) \ - (__m512i)__builtin_ia32_gathersiv16si((__v16si)_mm512_undefined_epi32(), \ - (void const *)(addr), \ - (__v16si)(__m512i)(index), \ - (__mmask16)-1, (int)(scale)) + ((__m512i)__builtin_ia32_gathersiv16si((__v16si)_mm512_undefined_epi32(), \ + (void const *)(addr), \ + (__v16si)(__m512i)(index), \ + (__mmask16)-1, (int)(scale))) #define _mm512_mask_i32gather_epi32(v1_old, mask, index, addr, scale) \ - (__m512i)__builtin_ia32_gathersiv16si((__v16si)(__m512i)(v1_old), \ - (void const *)(addr), \ - (__v16si)(__m512i)(index), \ - (__mmask16)(mask), (int)(scale)) + ((__m512i)__builtin_ia32_gathersiv16si((__v16si)(__m512i)(v1_old), \ + (void const *)(addr), \ + (__v16si)(__m512i)(index), \ + (__mmask16)(mask), (int)(scale))) #define _mm512_i32gather_pd(index, addr, scale) \ - (__m512d)__builtin_ia32_gathersiv8df((__v8df)_mm512_undefined_pd(), \ - (void const *)(addr), \ - (__v8si)(__m256i)(index), (__mmask8)-1, \ - (int)(scale)) + ((__m512d)__builtin_ia32_gathersiv8df((__v8df)_mm512_undefined_pd(), \ + (void const *)(addr), \ + (__v8si)(__m256i)(index), (__mmask8)-1, \ + (int)(scale))) #define _mm512_mask_i32gather_pd(v1_old, mask, index, addr, scale) \ - (__m512d)__builtin_ia32_gathersiv8df((__v8df)(__m512d)(v1_old), \ - (void const *)(addr), \ - (__v8si)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m512d)__builtin_ia32_gathersiv8df((__v8df)(__m512d)(v1_old), \ + (void const *)(addr), \ + (__v8si)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i32gather_epi64(index, addr, scale) \ - (__m512i)__builtin_ia32_gathersiv8di((__v8di)_mm512_undefined_epi32(), \ - (void const *)(addr), \ - (__v8si)(__m256i)(index), (__mmask8)-1, \ - (int)(scale)) + ((__m512i)__builtin_ia32_gathersiv8di((__v8di)_mm512_undefined_epi32(), \ + (void const *)(addr), \ + (__v8si)(__m256i)(index), (__mmask8)-1, \ + (int)(scale))) #define _mm512_mask_i32gather_epi64(v1_old, mask, index, addr, scale) \ - (__m512i)__builtin_ia32_gathersiv8di((__v8di)(__m512i)(v1_old), \ - (void const *)(addr), \ - (__v8si)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m512i)__builtin_ia32_gathersiv8di((__v8di)(__m512i)(v1_old), \ + (void const *)(addr), \ + (__v8si)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm512_i64scatter_ps(addr, index, v1, scale) \ __builtin_ia32_scatterdiv16sf((void *)(addr), (__mmask8)-1, \ @@ -7800,16 +7800,16 @@ _mm_mask_fmadd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_fmadd_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fmadd_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ - (__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ + (__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_fmadd_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) @@ -7822,10 +7822,10 @@ _mm_maskz_fmadd_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) } #define _mm_maskz_fmadd_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask3_fmadd_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) @@ -7838,10 +7838,10 @@ _mm_mask3_fmadd_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) } #define _mm_mask3_fmadd_round_ss(W, X, Y, U, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask3((__v4sf)(__m128)(W), \ - (__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask3((__v4sf)(__m128)(W), \ + (__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_fmsub_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) @@ -7854,16 +7854,16 @@ _mm_mask_fmsub_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_fmsub_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - -(__v4sf)(__m128)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + -(__v4sf)(__m128)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fmsub_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ - (__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ + (__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_fmsub_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) @@ -7876,10 +7876,10 @@ _mm_maskz_fmsub_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) } #define _mm_maskz_fmsub_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - -(__v4sf)(__m128)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + -(__v4sf)(__m128)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask3_fmsub_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) @@ -7892,10 +7892,10 @@ _mm_mask3_fmsub_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) } #define _mm_mask3_fmsub_round_ss(W, X, Y, U, R) \ - (__m128)__builtin_ia32_vfmsubss3_mask3((__v4sf)(__m128)(W), \ - (__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmsubss3_mask3((__v4sf)(__m128)(W), \ + (__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_fnmadd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) @@ -7908,16 +7908,16 @@ _mm_mask_fnmadd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_fnmadd_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fnmadd_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ - -(__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ + -(__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_fnmadd_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) @@ -7930,10 +7930,10 @@ _mm_maskz_fnmadd_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) } #define _mm_maskz_fnmadd_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), \ - (__v4sf)(__m128)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), \ + (__v4sf)(__m128)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask3_fnmadd_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) @@ -7946,10 +7946,10 @@ _mm_mask3_fnmadd_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) } #define _mm_mask3_fnmadd_round_ss(W, X, Y, U, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask3((__v4sf)(__m128)(W), \ - -(__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask3((__v4sf)(__m128)(W), \ + -(__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_fnmsub_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) @@ -7962,16 +7962,16 @@ _mm_mask_fnmsub_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128 __B) } #define _mm_fnmsub_round_ss(A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), \ - -(__v4sf)(__m128)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), \ + -(__v4sf)(__m128)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fnmsub_round_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ - -(__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_mask((__v4sf)(__m128)(W), \ + -(__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_fnmsub_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) @@ -7984,10 +7984,10 @@ _mm_maskz_fnmsub_ss (__mmask8 __U, __m128 __A, __m128 __B, __m128 __C) } #define _mm_maskz_fnmsub_round_ss(U, A, B, C, R) \ - (__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ - -(__v4sf)(__m128)(B), \ - -(__v4sf)(__m128)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmaddss3_maskz((__v4sf)(__m128)(A), \ + -(__v4sf)(__m128)(B), \ + -(__v4sf)(__m128)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask3_fnmsub_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) @@ -8000,10 +8000,10 @@ _mm_mask3_fnmsub_ss (__m128 __W, __m128 __X, __m128 __Y, __mmask8 __U) } #define _mm_mask3_fnmsub_round_ss(W, X, Y, U, R) \ - (__m128)__builtin_ia32_vfmsubss3_mask3((__v4sf)(__m128)(W), \ - -(__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128)__builtin_ia32_vfmsubss3_mask3((__v4sf)(__m128)(W), \ + -(__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_fmadd_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) @@ -8016,16 +8016,16 @@ _mm_mask_fmadd_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_fmadd_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fmadd_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ - (__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ + (__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_fmadd_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) @@ -8038,10 +8038,10 @@ _mm_maskz_fmadd_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) } #define _mm_maskz_fmadd_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask3_fmadd_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) @@ -8054,10 +8054,10 @@ _mm_mask3_fmadd_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) } #define _mm_mask3_fmadd_round_sd(W, X, Y, U, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask3((__v2df)(__m128d)(W), \ - (__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask3((__v2df)(__m128d)(W), \ + (__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_fmsub_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) @@ -8070,16 +8070,16 @@ _mm_mask_fmsub_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_fmsub_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - -(__v2df)(__m128d)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + -(__v2df)(__m128d)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fmsub_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ - (__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ + (__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_fmsub_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) @@ -8092,10 +8092,10 @@ _mm_maskz_fmsub_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) } #define _mm_maskz_fmsub_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - -(__v2df)(__m128d)(C), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + -(__v2df)(__m128d)(C), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask3_fmsub_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) @@ -8108,10 +8108,10 @@ _mm_mask3_fmsub_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) } #define _mm_mask3_fmsub_round_sd(W, X, Y, U, R) \ - (__m128d)__builtin_ia32_vfmsubsd3_mask3((__v2df)(__m128d)(W), \ - (__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_vfmsubsd3_mask3((__v2df)(__m128d)(W), \ + (__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_fnmadd_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) @@ -8124,16 +8124,16 @@ _mm_mask_fnmadd_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_fnmadd_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fnmadd_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ - -(__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ + -(__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_fnmadd_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) @@ -8146,10 +8146,10 @@ _mm_maskz_fnmadd_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) } #define _mm_maskz_fnmadd_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), \ - (__v2df)(__m128d)(C), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), \ + (__v2df)(__m128d)(C), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask3_fnmadd_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) @@ -8162,10 +8162,10 @@ _mm_mask3_fnmadd_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) } #define _mm_mask3_fnmadd_round_sd(W, X, Y, U, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask3((__v2df)(__m128d)(W), \ - -(__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask3((__v2df)(__m128d)(W), \ + -(__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_fnmsub_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) @@ -8178,16 +8178,16 @@ _mm_mask_fnmsub_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128d __B) } #define _mm_fnmsub_round_sd(A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), \ - -(__v2df)(__m128d)(C), (__mmask8)-1, \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), \ + -(__v2df)(__m128d)(C), (__mmask8)-1, \ + (int)(R))) #define _mm_mask_fnmsub_round_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ - -(__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_mask((__v2df)(__m128d)(W), \ + -(__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_fnmsub_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) @@ -8200,11 +8200,11 @@ _mm_maskz_fnmsub_sd (__mmask8 __U, __m128d __A, __m128d __B, __m128d __C) } #define _mm_maskz_fnmsub_round_sd(U, A, B, C, R) \ - (__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ - -(__v2df)(__m128d)(B), \ - -(__v2df)(__m128d)(C), \ - (__mmask8)(U), \ - (int)(R)) + ((__m128d)__builtin_ia32_vfmaddsd3_maskz((__v2df)(__m128d)(A), \ + -(__v2df)(__m128d)(B), \ + -(__v2df)(__m128d)(C), \ + (__mmask8)(U), \ + (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask3_fnmsub_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) @@ -8217,36 +8217,36 @@ _mm_mask3_fnmsub_sd (__m128d __W, __m128d __X, __m128d __Y, __mmask8 __U) } #define _mm_mask3_fnmsub_round_sd(W, X, Y, U, R) \ - (__m128d)__builtin_ia32_vfmsubsd3_mask3((__v2df)(__m128d)(W), \ - -(__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_vfmsubsd3_mask3((__v2df)(__m128d)(W), \ + -(__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), \ + (__mmask8)(U), (int)(R))) #define _mm512_permutex_pd(X, C) \ - (__m512d)__builtin_ia32_permdf512((__v8df)(__m512d)(X), (int)(C)) + ((__m512d)__builtin_ia32_permdf512((__v8df)(__m512d)(X), (int)(C))) #define _mm512_mask_permutex_pd(W, U, X, C) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_permutex_pd((X), (C)), \ - (__v8df)(__m512d)(W)) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_permutex_pd((X), (C)), \ + (__v8df)(__m512d)(W))) #define _mm512_maskz_permutex_pd(U, X, C) \ - (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ - (__v8df)_mm512_permutex_pd((X), (C)), \ - (__v8df)_mm512_setzero_pd()) + ((__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ + (__v8df)_mm512_permutex_pd((X), (C)), \ + (__v8df)_mm512_setzero_pd())) #define _mm512_permutex_epi64(X, C) \ - (__m512i)__builtin_ia32_permdi512((__v8di)(__m512i)(X), (int)(C)) + ((__m512i)__builtin_ia32_permdi512((__v8di)(__m512i)(X), (int)(C))) #define _mm512_mask_permutex_epi64(W, U, X, C) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_permutex_epi64((X), (C)), \ - (__v8di)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_permutex_epi64((X), (C)), \ + (__v8di)(__m512i)(W))) #define _mm512_maskz_permutex_epi64(U, X, C) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_permutex_epi64((X), (C)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_permutex_epi64((X), (C)), \ + (__v8di)_mm512_setzero_si512())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_permutexvar_pd (__m512i __X, __m512d __Y) @@ -8416,10 +8416,10 @@ _mm512_kxor (__mmask16 __A, __mmask16 __B) #define _kxor_mask16 _mm512_kxor #define _kshiftli_mask16(A, I) \ - (__mmask16)__builtin_ia32_kshiftlihi((__mmask16)(A), (unsigned int)(I)) + ((__mmask16)__builtin_ia32_kshiftlihi((__mmask16)(A), (unsigned int)(I))) #define _kshiftri_mask16(A, I) \ - (__mmask16)__builtin_ia32_kshiftrihi((__mmask16)(A), (unsigned int)(I)) + ((__mmask16)__builtin_ia32_kshiftrihi((__mmask16)(A), (unsigned int)(I))) static __inline__ unsigned int __DEFAULT_FN_ATTRS _cvtmask16_u32(__mmask16 __A) { @@ -8538,48 +8538,48 @@ _mm512_maskz_compress_epi32 (__mmask16 __U, __m512i __A) } #define _mm_cmp_round_ss_mask(X, Y, P, R) \ - (__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (int)(P), \ - (__mmask8)-1, (int)(R)) + ((__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (int)(P), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_cmp_round_ss_mask(M, X, Y, P, R) \ - (__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (int)(P), \ - (__mmask8)(M), (int)(R)) + ((__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (int)(P), \ + (__mmask8)(M), (int)(R))) #define _mm_cmp_ss_mask(X, Y, P) \ - (__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (int)(P), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (int)(P), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_cmp_ss_mask(M, X, Y, P) \ - (__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (int)(P), \ - (__mmask8)(M), \ - _MM_FROUND_CUR_DIRECTION) + ((__mmask8)__builtin_ia32_cmpss_mask((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (int)(P), \ + (__mmask8)(M), \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_cmp_round_sd_mask(X, Y, P, R) \ - (__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (int)(P), \ - (__mmask8)-1, (int)(R)) + ((__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (int)(P), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_cmp_round_sd_mask(M, X, Y, P, R) \ - (__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (int)(P), \ - (__mmask8)(M), (int)(R)) + ((__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (int)(P), \ + (__mmask8)(M), (int)(R))) #define _mm_cmp_sd_mask(X, Y, P) \ - (__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (int)(P), \ - (__mmask8)-1, \ - _MM_FROUND_CUR_DIRECTION) + ((__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (int)(P), \ + (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) #define _mm_mask_cmp_sd_mask(M, X, Y, P) \ - (__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (int)(P), \ - (__mmask8)(M), \ - _MM_FROUND_CUR_DIRECTION) + ((__mmask8)__builtin_ia32_cmpsd_mask((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (int)(P), \ + (__mmask8)(M), \ + _MM_FROUND_CUR_DIRECTION)) /* Bit Test */ @@ -8760,17 +8760,17 @@ _mm_maskz_load_sd (__mmask8 __U, const double* __A) } #define _mm512_shuffle_epi32(A, I) \ - (__m512i)__builtin_ia32_pshufd512((__v16si)(__m512i)(A), (int)(I)) + ((__m512i)__builtin_ia32_pshufd512((__v16si)(__m512i)(A), (int)(I))) #define _mm512_mask_shuffle_epi32(W, U, A, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shuffle_epi32((A), (I)), \ - (__v16si)(__m512i)(W)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_epi32((A), (I)), \ + (__v16si)(__m512i)(W))) #define _mm512_maskz_shuffle_epi32(U, A, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shuffle_epi32((A), (I)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shuffle_epi32((A), (I)), \ + (__v16si)_mm512_setzero_si512())) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_mask_expand_pd (__m512d __W, __mmask8 __U, __m512d __A) @@ -8901,19 +8901,19 @@ _mm512_maskz_expand_epi32 (__mmask16 __U, __m512i __A) } #define _mm512_cvt_roundps_pd(A, R) \ - (__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ - (__v8df)_mm512_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ + (__v8df)_mm512_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm512_mask_cvt_roundps_pd(W, U, A, R) \ - (__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ - (__v8df)(__m512d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ + (__v8df)(__m512d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm512_maskz_cvt_roundps_pd(U, A, R) \ - (__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ - (__v8df)_mm512_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m512d)__builtin_ia32_cvtps2pd512_mask((__v8sf)(__m256)(A), \ + (__v8df)_mm512_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_cvtps_pd (__m256 __A) @@ -9010,22 +9010,22 @@ _mm512_mask_compressstoreu_epi32 (void *__P, __mmask16 __U, __m512i __A) } #define _mm_cvt_roundsd_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ - (__v2df)(__m128d)(B), \ - (__v4sf)_mm_undefined_ps(), \ - (__mmask8)-1, (int)(R)) + ((__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ + (__v2df)(__m128d)(B), \ + (__v4sf)_mm_undefined_ps(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_cvt_roundsd_ss(W, U, A, B, R) \ - (__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ - (__v2df)(__m128d)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ + (__v2df)(__m128d)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_cvt_roundsd_ss(U, A, B, R) \ - (__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ - (__v2df)(__m128d)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U), (int)(R)) + ((__m128)__builtin_ia32_cvtsd2ss_round_mask((__v4sf)(__m128)(A), \ + (__v2df)(__m128d)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_cvtsd_ss (__m128 __W, __mmask8 __U, __m128 __A, __m128d __B) @@ -9058,47 +9058,47 @@ _mm_maskz_cvtsd_ss (__mmask8 __U, __m128 __A, __m128d __B) #ifdef __x86_64__ #define _mm_cvt_roundi64_sd(A, B, R) \ - (__m128d)__builtin_ia32_cvtsi2sd64((__v2df)(__m128d)(A), (long long)(B), \ - (int)(R)) + ((__m128d)__builtin_ia32_cvtsi2sd64((__v2df)(__m128d)(A), (long long)(B), \ + (int)(R))) #define _mm_cvt_roundsi64_sd(A, B, R) \ - (__m128d)__builtin_ia32_cvtsi2sd64((__v2df)(__m128d)(A), (long long)(B), \ - (int)(R)) + ((__m128d)__builtin_ia32_cvtsi2sd64((__v2df)(__m128d)(A), (long long)(B), \ + (int)(R))) #endif #define _mm_cvt_roundsi32_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtsi2ss32((__v4sf)(__m128)(A), (int)(B), (int)(R)) + ((__m128)__builtin_ia32_cvtsi2ss32((__v4sf)(__m128)(A), (int)(B), (int)(R))) #define _mm_cvt_roundi32_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtsi2ss32((__v4sf)(__m128)(A), (int)(B), (int)(R)) + ((__m128)__builtin_ia32_cvtsi2ss32((__v4sf)(__m128)(A), (int)(B), (int)(R))) #ifdef __x86_64__ #define _mm_cvt_roundsi64_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtsi2ss64((__v4sf)(__m128)(A), (long long)(B), \ - (int)(R)) + ((__m128)__builtin_ia32_cvtsi2ss64((__v4sf)(__m128)(A), (long long)(B), \ + (int)(R))) #define _mm_cvt_roundi64_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtsi2ss64((__v4sf)(__m128)(A), (long long)(B), \ - (int)(R)) + ((__m128)__builtin_ia32_cvtsi2ss64((__v4sf)(__m128)(A), (long long)(B), \ + (int)(R))) #endif #define _mm_cvt_roundss_sd(A, B, R) \ - (__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ - (__v4sf)(__m128)(B), \ - (__v2df)_mm_undefined_pd(), \ - (__mmask8)-1, (int)(R)) + ((__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ + (__v4sf)(__m128)(B), \ + (__v2df)_mm_undefined_pd(), \ + (__mmask8)-1, (int)(R))) #define _mm_mask_cvt_roundss_sd(W, U, A, B, R) \ - (__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ - (__v4sf)(__m128)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ + (__v4sf)(__m128)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U), (int)(R))) #define _mm_maskz_cvt_roundss_sd(U, A, B, R) \ - (__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ - (__v4sf)(__m128)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U), (int)(R)) + ((__m128d)__builtin_ia32_cvtss2sd_round_mask((__v2df)(__m128d)(A), \ + (__v4sf)(__m128)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_cvtss_sd (__m128d __W, __mmask8 __U, __m128d __A, __m128 __B) @@ -9127,8 +9127,8 @@ _mm_cvtu32_sd (__m128d __A, unsigned __B) #ifdef __x86_64__ #define _mm_cvt_roundu64_sd(A, B, R) \ - (__m128d)__builtin_ia32_cvtusi2sd64((__v2df)(__m128d)(A), \ - (unsigned long long)(B), (int)(R)) + ((__m128d)__builtin_ia32_cvtusi2sd64((__v2df)(__m128d)(A), \ + (unsigned long long)(B), (int)(R))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_cvtu64_sd (__m128d __A, unsigned long long __B) @@ -9139,8 +9139,8 @@ _mm_cvtu64_sd (__m128d __A, unsigned long long __B) #endif #define _mm_cvt_roundu32_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtusi2ss32((__v4sf)(__m128)(A), (unsigned int)(B), \ - (int)(R)) + ((__m128)__builtin_ia32_cvtusi2ss32((__v4sf)(__m128)(A), (unsigned int)(B), \ + (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_cvtu32_ss (__m128 __A, unsigned __B) @@ -9151,8 +9151,8 @@ _mm_cvtu32_ss (__m128 __A, unsigned __B) #ifdef __x86_64__ #define _mm_cvt_roundu64_ss(A, B, R) \ - (__m128)__builtin_ia32_cvtusi2ss64((__v4sf)(__m128)(A), \ - (unsigned long long)(B), (int)(R)) + ((__m128)__builtin_ia32_cvtusi2ss64((__v4sf)(__m128)(A), \ + (unsigned long long)(B), (int)(R))) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_cvtu64_ss (__m128 __A, unsigned long long __B) diff --git a/clang/lib/Headers/avx512fp16intrin.h b/clang/lib/Headers/avx512fp16intrin.h new file mode 100644 index 00000000000..99409a31b32 --- /dev/null +++ b/clang/lib/Headers/avx512fp16intrin.h @@ -0,0 +1,3349 @@ +/*===----------- avx512fp16intrin.h - AVX512-FP16 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 __IMMINTRIN_H +#error "Never use directly; include instead." +#endif + +#ifndef __AVX512FP16INTRIN_H +#define __AVX512FP16INTRIN_H + +/* Define the default attributes for the functions in this file. */ +typedef _Float16 __v32hf __attribute__((__vector_size__(64), __aligned__(64))); +typedef _Float16 __m512h __attribute__((__vector_size__(64), __aligned__(64))); +typedef _Float16 __m512h_u __attribute__((__vector_size__(64), __aligned__(1))); +typedef _Float16 __v8hf __attribute__((__vector_size__(16), __aligned__(16))); +typedef _Float16 __m128h __attribute__((__vector_size__(16), __aligned__(16))); +typedef _Float16 __m128h_u __attribute__((__vector_size__(16), __aligned__(1))); +typedef _Float16 __v16hf __attribute__((__vector_size__(32), __aligned__(32))); +typedef _Float16 __m256h __attribute__((__vector_size__(32), __aligned__(32))); +typedef _Float16 __m256h_u __attribute__((__vector_size__(32), __aligned__(1))); + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS512 \ + __attribute__((__always_inline__, __nodebug__, __target__("avx512fp16"), \ + __min_vector_width__(512))) +#define __DEFAULT_FN_ATTRS256 \ + __attribute__((__always_inline__, __nodebug__, __target__("avx512fp16"), \ + __min_vector_width__(256))) +#define __DEFAULT_FN_ATTRS128 \ + __attribute__((__always_inline__, __nodebug__, __target__("avx512fp16"), \ + __min_vector_width__(128))) + +static __inline__ _Float16 __DEFAULT_FN_ATTRS512 _mm512_cvtsh_h(__m512h __a) { + return __a[0]; +} + +static __inline __m128h __DEFAULT_FN_ATTRS128 _mm_setzero_ph(void) { + return (__m128h){0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +} + +static __inline __m256h __DEFAULT_FN_ATTRS256 _mm256_setzero_ph(void) { + return (__m256h){0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_undefined_ph(void) { + return (__m256h)__builtin_ia32_undef256(); +} + +static __inline __m512h __DEFAULT_FN_ATTRS512 _mm512_setzero_ph(void) { + return (__m512h){0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_undefined_ph(void) { + return (__m128h)__builtin_ia32_undef128(); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_undefined_ph(void) { + return (__m512h)__builtin_ia32_undef512(); +} + +static __inline __m512h __DEFAULT_FN_ATTRS512 _mm512_set1_ph(_Float16 __h) { + return (__m512h)(__v32hf){__h, __h, __h, __h, __h, __h, __h, __h, + __h, __h, __h, __h, __h, __h, __h, __h, + __h, __h, __h, __h, __h, __h, __h, __h, + __h, __h, __h, __h, __h, __h, __h, __h}; +} + +static __inline __m512h __DEFAULT_FN_ATTRS512 +_mm512_set_ph(_Float16 __h1, _Float16 __h2, _Float16 __h3, _Float16 __h4, + _Float16 __h5, _Float16 __h6, _Float16 __h7, _Float16 __h8, + _Float16 __h9, _Float16 __h10, _Float16 __h11, _Float16 __h12, + _Float16 __h13, _Float16 __h14, _Float16 __h15, _Float16 __h16, + _Float16 __h17, _Float16 __h18, _Float16 __h19, _Float16 __h20, + _Float16 __h21, _Float16 __h22, _Float16 __h23, _Float16 __h24, + _Float16 __h25, _Float16 __h26, _Float16 __h27, _Float16 __h28, + _Float16 __h29, _Float16 __h30, _Float16 __h31, _Float16 __h32) { + return (__m512h)(__v32hf){__h32, __h31, __h30, __h29, __h28, __h27, __h26, + __h25, __h24, __h23, __h22, __h21, __h20, __h19, + __h18, __h17, __h16, __h15, __h14, __h13, __h12, + __h11, __h10, __h9, __h8, __h7, __h6, __h5, + __h4, __h3, __h2, __h1}; +} + +#define _mm512_setr_ph(h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, \ + h14, h15, h16, h17, h18, h19, h20, h21, h22, h23, h24, \ + h25, h26, h27, h28, h29, h30, h31, h32) \ + _mm512_set_ph((h32), (h31), (h30), (h29), (h28), (h27), (h26), (h25), (h24), \ + (h23), (h22), (h21), (h20), (h19), (h18), (h17), (h16), (h15), \ + (h14), (h13), (h12), (h11), (h10), (h9), (h8), (h7), (h6), \ + (h5), (h4), (h3), (h2), (h1)) + +static __inline __m512h __DEFAULT_FN_ATTRS512 +_mm512_set1_pch(_Float16 _Complex h) { + return (__m512h)_mm512_set1_ps(__builtin_bit_cast(float, h)); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_castph_ps(__m128h __a) { + return (__m128)__a; +} + +static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_castph_ps(__m256h __a) { + return (__m256)__a; +} + +static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_castph_ps(__m512h __a) { + return (__m512)__a; +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_castph_pd(__m128h __a) { + return (__m128d)__a; +} + +static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_castph_pd(__m256h __a) { + return (__m256d)__a; +} + +static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_castph_pd(__m512h __a) { + return (__m512d)__a; +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_castph_si128(__m128h __a) { + return (__m128i)__a; +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_castph_si256(__m256h __a) { + return (__m256i)__a; +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_castph_si512(__m512h __a) { + return (__m512i)__a; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_castps_ph(__m128 __a) { + return (__m128h)__a; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_castps_ph(__m256 __a) { + return (__m256h)__a; +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_castps_ph(__m512 __a) { + return (__m512h)__a; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_castpd_ph(__m128d __a) { + return (__m128h)__a; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_castpd_ph(__m256d __a) { + return (__m256h)__a; +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_castpd_ph(__m512d __a) { + return (__m512h)__a; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_castsi128_ph(__m128i __a) { + return (__m128h)__a; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_castsi256_ph(__m256i __a) { + return (__m256h)__a; +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_castsi512_ph(__m512i __a) { + return (__m512h)__a; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_castph256_ph128(__m256h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_castph512_ph128(__m512h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_castph512_ph256(__m512h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_castph128_ph256(__m128h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, + -1, -1, -1, -1, -1); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_castph128_ph512(__m128h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_castph256_ph512(__m256h __a) { + return __builtin_shufflevector(__a, __a, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1); +} + +/// Constructs a 256-bit floating-point vector of [16 x half] from a +/// 128-bit floating-point vector of [8 x half]. The lower 128 bits +/// contain the value of the source vector. The upper 384 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [8 x half]. +/// \returns A 512-bit floating-point vector of [16 x half]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_zextph128_ph256(__m128h __a) { + return __builtin_shufflevector(__a, (__v8hf)_mm_setzero_ph(), 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); +} + +/// Constructs a 512-bit floating-point vector of [32 x half] from a +/// 128-bit floating-point vector of [8 x half]. The lower 128 bits +/// contain the value of the source vector. The upper 384 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 128-bit vector of [8 x half]. +/// \returns A 512-bit floating-point vector of [32 x half]. The lower 128 bits +/// contain the value of the parameter. The upper 384 bits are set to zero. +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_zextph128_ph512(__m128h __a) { + return __builtin_shufflevector( + __a, (__v8hf)_mm_setzero_ph(), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15, 8, 9, 10, 11, 12, 13, 14, 15); +} + +/// Constructs a 512-bit floating-point vector of [32 x half] from a +/// 256-bit floating-point vector of [16 x half]. The lower 256 bits +/// contain the value of the source vector. The upper 256 bits are set +/// to zero. +/// +/// \headerfile +/// +/// This intrinsic has no corresponding instruction. +/// +/// \param __a +/// A 256-bit vector of [16 x half]. +/// \returns A 512-bit floating-point vector of [32 x half]. The lower 256 bits +/// contain the value of the parameter. The upper 256 bits are set to zero. +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_zextph256_ph512(__m256h __a) { + return __builtin_shufflevector(__a, (__v16hf)_mm256_setzero_ph(), 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, + 29, 30, 31); +} + +#define _mm_comi_round_sh(A, B, P, R) \ + __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, (int)(P), (int)(R)) + +#define _mm_comi_sh(A, B, pred) \ + _mm_comi_round_sh((A), (B), (pred), _MM_FROUND_CUR_DIRECTION) + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comieq_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_EQ_OS, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comilt_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_LT_OS, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comile_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_LE_OS, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comigt_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_GT_OS, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comige_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_GE_OS, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_comineq_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_NEQ_US, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomieq_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_EQ_OQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomilt_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_LT_OQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomile_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_LE_OQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomigt_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_GT_OQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomige_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_GE_OQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_ucomineq_sh(__m128h A, + __m128h B) { + return __builtin_ia32_vcomish((__v8hf)A, (__v8hf)B, _CMP_NEQ_UQ, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_add_ph(__m512h __A, + __m512h __B) { + return (__m512h)((__v32hf)__A + (__v32hf)__B); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_add_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_add_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_add_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_add_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_add_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_addph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_add_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_add_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_add_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_add_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_sub_ph(__m512h __A, + __m512h __B) { + return (__m512h)((__v32hf)__A - (__v32hf)__B); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_sub_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_sub_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_sub_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_sub_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_sub_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_subph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_sub_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_sub_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_sub_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_sub_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_mul_ph(__m512h __A, + __m512h __B) { + return (__m512h)((__v32hf)__A * (__v32hf)__B); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_mul_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_mul_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_mul_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_mul_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_mul_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_mulph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_mul_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_mul_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_mul_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_mul_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_div_ph(__m512h __A, + __m512h __B) { + return (__m512h)((__v32hf)__A / (__v32hf)__B); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_div_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_div_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_div_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_div_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_div_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_divph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_div_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_div_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_div_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_div_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_min_ph(__m512h __A, + __m512h __B) { + return (__m512h)__builtin_ia32_minph512((__v32hf)__A, (__v32hf)__B, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_min_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_min_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_min_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_min_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_min_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_minph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_min_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_min_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_min_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_min_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_max_ph(__m512h __A, + __m512h __B) { + return (__m512h)__builtin_ia32_maxph512((__v32hf)__A, (__v32hf)__B, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_max_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)__U, (__v32hf)_mm512_max_ph(__A, __B), (__v32hf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_max_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, + (__v32hf)_mm512_max_ph(__A, __B), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm512_max_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_maxph512((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(R))) + +#define _mm512_mask_max_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_max_round_ph((A), (B), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_max_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_max_round_ph((A), (B), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_abs_ph(__m512h __A) { + return (__m512h)_mm512_and_epi32(_mm512_set1_epi32(0x7FFF7FFF), (__m512i)__A); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_conj_pch(__m512h __A) { + return (__m512h)_mm512_xor_ps((__m512)__A, _mm512_set1_ps(-0.0f)); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_conj_pch(__m512h __W, __mmask16 __U, __m512h __A) { + return (__m512h)__builtin_ia32_selectps_512( + (__mmask16)__U, (__v16sf)_mm512_conj_pch(__A), (__v16sf)__W); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_conj_pch(__mmask16 __U, __m512h __A) { + return (__m512h)__builtin_ia32_selectps_512((__mmask16)__U, + (__v16sf)_mm512_conj_pch(__A), + (__v16sf)_mm512_setzero_ps()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_add_sh(__m128h __A, + __m128h __B) { + __A[0] += __B[0]; + return __A; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_add_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_add_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, __W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_add_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_add_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, _mm_setzero_ph()); +} + +#define _mm_add_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_addsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_add_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_addsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_add_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_addsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_sub_sh(__m128h __A, + __m128h __B) { + __A[0] -= __B[0]; + return __A; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_sub_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_sub_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, __W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_sub_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_sub_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, _mm_setzero_ph()); +} + +#define _mm_sub_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_subsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_sub_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_subsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_sub_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_subsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mul_sh(__m128h __A, + __m128h __B) { + __A[0] *= __B[0]; + return __A; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_mul_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_mul_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, __W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_mul_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_mul_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, _mm_setzero_ph()); +} + +#define _mm_mul_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_mulsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_mul_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_mulsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_mul_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_mulsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_div_sh(__m128h __A, + __m128h __B) { + __A[0] /= __B[0]; + return __A; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_div_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_div_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, __W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_div_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + __A = _mm_div_sh(__A, __B); + return __builtin_ia32_selectsh_128(__U, __A, _mm_setzero_ph()); +} + +#define _mm_div_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_divsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_div_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_divsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_div_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_divsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_min_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_minsh_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_min_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_minsh_round_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_min_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_minsh_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_min_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_minsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_min_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_minsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_min_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_minsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_max_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_maxsh_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_max_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_maxsh_round_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_max_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_maxsh_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_max_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_maxsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_max_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_maxsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_max_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_maxsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_cmp_round_ph_mask(A, B, P, R) \ + ((__mmask32)__builtin_ia32_cmpph512_mask((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(P), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_cmp_round_ph_mask(U, A, B, P, R) \ + ((__mmask32)__builtin_ia32_cmpph512_mask((__v32hf)(__m512h)(A), \ + (__v32hf)(__m512h)(B), (int)(P), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_cmp_ph_mask(A, B, P) \ + _mm512_cmp_round_ph_mask((A), (B), (P), _MM_FROUND_CUR_DIRECTION) + +#define _mm512_mask_cmp_ph_mask(U, A, B, P) \ + _mm512_mask_cmp_round_ph_mask((U), (A), (B), (P), _MM_FROUND_CUR_DIRECTION) + +#define _mm_cmp_round_sh_mask(X, Y, P, R) \ + ((__mmask8)__builtin_ia32_cmpsh_mask((__v8hf)(__m128h)(X), \ + (__v8hf)(__m128h)(Y), (int)(P), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_cmp_round_sh_mask(M, X, Y, P, R) \ + ((__mmask8)__builtin_ia32_cmpsh_mask((__v8hf)(__m128h)(X), \ + (__v8hf)(__m128h)(Y), (int)(P), \ + (__mmask8)(M), (int)(R))) + +#define _mm_cmp_sh_mask(X, Y, P) \ + ((__mmask8)__builtin_ia32_cmpsh_mask( \ + (__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), (int)(P), (__mmask8)-1, \ + _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_cmp_sh_mask(M, X, Y, P) \ + ((__mmask8)__builtin_ia32_cmpsh_mask( \ + (__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), (int)(P), (__mmask8)(M), \ + _MM_FROUND_CUR_DIRECTION)) +// loads with vmovsh: +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_load_sh(void const *__dp) { + struct __mm_load_sh_struct { + _Float16 __u; + } __attribute__((__packed__, __may_alias__)); + _Float16 __u = ((struct __mm_load_sh_struct *)__dp)->__u; + return (__m128h){__u, 0, 0, 0, 0, 0, 0, 0}; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_load_sh(__m128h __W, __mmask8 __U, const void *__A) { + __m128h src = (__v8hf)__builtin_shufflevector( + (__v8hf)__W, (__v8hf)_mm_setzero_ph(), 0, 8, 8, 8, 8, 8, 8, 8); + + return (__m128h)__builtin_ia32_loadsh128_mask((__v8hf *)__A, src, __U & 1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_load_sh(__mmask8 __U, const void *__A) { + return (__m128h)__builtin_ia32_loadsh128_mask( + (__v8hf *)__A, (__v8hf)_mm_setzero_ph(), __U & 1); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_load_ph(void const *__p) { + return *(const __m512h *)__p; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_load_ph(void const *__p) { + return *(const __m256h *)__p; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_load_ph(void const *__p) { + return *(const __m128h *)__p; +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_loadu_ph(void const *__p) { + struct __loadu_ph { + __m512h_u __v; + } __attribute__((__packed__, __may_alias__)); + return ((const struct __loadu_ph *)__p)->__v; +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_loadu_ph(void const *__p) { + struct __loadu_ph { + __m256h_u __v; + } __attribute__((__packed__, __may_alias__)); + return ((const struct __loadu_ph *)__p)->__v; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_loadu_ph(void const *__p) { + struct __loadu_ph { + __m128h_u __v; + } __attribute__((__packed__, __may_alias__)); + return ((const struct __loadu_ph *)__p)->__v; +} + +// stores with vmovsh: +static __inline__ void __DEFAULT_FN_ATTRS128 _mm_store_sh(void *__dp, + __m128h __a) { + struct __mm_store_sh_struct { + _Float16 __u; + } __attribute__((__packed__, __may_alias__)); + ((struct __mm_store_sh_struct *)__dp)->__u = __a[0]; +} + +static __inline__ void __DEFAULT_FN_ATTRS128 _mm_mask_store_sh(void *__W, + __mmask8 __U, + __m128h __A) { + __builtin_ia32_storesh128_mask((__v8hf *)__W, __A, __U & 1); +} + +static __inline__ void __DEFAULT_FN_ATTRS512 _mm512_store_ph(void *__P, + __m512h __A) { + *(__m512h *)__P = __A; +} + +static __inline__ void __DEFAULT_FN_ATTRS256 _mm256_store_ph(void *__P, + __m256h __A) { + *(__m256h *)__P = __A; +} + +static __inline__ void __DEFAULT_FN_ATTRS128 _mm_store_ph(void *__P, + __m128h __A) { + *(__m128h *)__P = __A; +} + +static __inline__ void __DEFAULT_FN_ATTRS512 _mm512_storeu_ph(void *__P, + __m512h __A) { + struct __storeu_ph { + __m512h_u __v; + } __attribute__((__packed__, __may_alias__)); + ((struct __storeu_ph *)__P)->__v = __A; +} + +static __inline__ void __DEFAULT_FN_ATTRS256 _mm256_storeu_ph(void *__P, + __m256h __A) { + struct __storeu_ph { + __m256h_u __v; + } __attribute__((__packed__, __may_alias__)); + ((struct __storeu_ph *)__P)->__v = __A; +} + +static __inline__ void __DEFAULT_FN_ATTRS128 _mm_storeu_ph(void *__P, + __m128h __A) { + struct __storeu_ph { + __m128h_u __v; + } __attribute__((__packed__, __may_alias__)); + ((struct __storeu_ph *)__P)->__v = __A; +} + +// moves with vmovsh: +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_move_sh(__m128h __a, + __m128h __b) { + __a[0] = __b[0]; + return __a; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_move_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return __builtin_ia32_selectsh_128(__U, _mm_move_sh(__A, __B), __W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_move_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + return __builtin_ia32_selectsh_128(__U, _mm_move_sh(__A, __B), + _mm_setzero_ph()); +} + +// vmovw: +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtsi16_si128(short __a) { + return (__m128i)(__v8hi){__a, 0, 0, 0, 0, 0, 0, 0}; +} + +static __inline__ short __DEFAULT_FN_ATTRS128 _mm_cvtsi128_si16(__m128i __a) { + __v8hi __b = (__v8hi)__a; + return __b[0]; +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_rcp_ph(__m512h __A) { + return (__m512h)__builtin_ia32_rcpph512_mask( + (__v32hf)__A, (__v32hf)_mm512_undefined_ph(), (__mmask32)-1); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_rcp_ph(__m512h __W, __mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_rcpph512_mask((__v32hf)__A, (__v32hf)__W, + (__mmask32)__U); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_rcp_ph(__mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_rcpph512_mask( + (__v32hf)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_rsqrt_ph(__m512h __A) { + return (__m512h)__builtin_ia32_rsqrtph512_mask( + (__v32hf)__A, (__v32hf)_mm512_undefined_ph(), (__mmask32)-1); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_rsqrt_ph(__m512h __W, __mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_rsqrtph512_mask((__v32hf)__A, (__v32hf)__W, + (__mmask32)__U); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_rsqrt_ph(__mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_rsqrtph512_mask( + (__v32hf)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U); +} + +#define _mm512_getmant_ph(A, B, C) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), \ + (__v32hf)_mm512_undefined_ph(), (__mmask32)-1, \ + _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_mask_getmant_ph(W, U, A, B, C) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), (__v32hf)(__m512h)(W), \ + (__mmask32)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_maskz_getmant_ph(U, A, B, C) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), \ + (__v32hf)_mm512_setzero_ph(), (__mmask32)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_getmant_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), \ + (__v32hf)_mm512_undefined_ph(), (__mmask32)-1, (int)(R))) + +#define _mm512_mask_getmant_round_ph(W, U, A, B, C, R) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), (__v32hf)(__m512h)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_getmant_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_getmantph512_mask( \ + (__v32hf)(__m512h)(A), (int)(((C) << 2) | (B)), \ + (__v32hf)_mm512_setzero_ph(), (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_getexp_ph(__m512h __A) { + return (__m512h)__builtin_ia32_getexpph512_mask( + (__v32hf)__A, (__v32hf)_mm512_undefined_ph(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_getexp_ph(__m512h __W, __mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_getexpph512_mask( + (__v32hf)__A, (__v32hf)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_getexp_ph(__mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_getexpph512_mask( + (__v32hf)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_getexp_round_ph(A, R) \ + ((__m512h)__builtin_ia32_getexpph512_mask((__v32hf)(__m512h)(A), \ + (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_getexp_round_ph(W, U, A, R) \ + ((__m512h)__builtin_ia32_getexpph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(W), (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_getexp_round_ph(U, A, R) \ + ((__m512h)__builtin_ia32_getexpph512_mask((__v32hf)(__m512h)(A), \ + (__v32hf)_mm512_setzero_ph(), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_scalef_ph(__m512h __A, + __m512h __B) { + return (__m512h)__builtin_ia32_scalefph512_mask( + (__v32hf)__A, (__v32hf)__B, (__v32hf)_mm512_undefined_ph(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_scalef_ph(__m512h __W, __mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_scalefph512_mask((__v32hf)__A, (__v32hf)__B, + (__v32hf)__W, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_scalef_ph(__mmask32 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_scalefph512_mask( + (__v32hf)__A, (__v32hf)__B, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_scalef_round_ph(A, B, R) \ + ((__m512h)__builtin_ia32_scalefph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), \ + (__v32hf)_mm512_undefined_ph(), (__mmask32)-1, (int)(R))) + +#define _mm512_mask_scalef_round_ph(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_scalefph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_scalef_round_ph(U, A, B, R) \ + ((__m512h)__builtin_ia32_scalefph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), \ + (__v32hf)_mm512_setzero_ph(), (__mmask32)(U), (int)(R))) + +#define _mm512_roundscale_ph(A, B) \ + ((__m512h)__builtin_ia32_rndscaleph_mask( \ + (__v32hf)(__m512h)(A), (int)(B), (__v32hf)(__m512h)(A), (__mmask32)-1, \ + _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_mask_roundscale_ph(A, B, C, imm) \ + ((__m512h)__builtin_ia32_rndscaleph_mask( \ + (__v32hf)(__m512h)(C), (int)(imm), (__v32hf)(__m512h)(A), \ + (__mmask32)(B), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_maskz_roundscale_ph(A, B, imm) \ + ((__m512h)__builtin_ia32_rndscaleph_mask( \ + (__v32hf)(__m512h)(B), (int)(imm), (__v32hf)_mm512_setzero_ph(), \ + (__mmask32)(A), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_mask_roundscale_round_ph(A, B, C, imm, R) \ + ((__m512h)__builtin_ia32_rndscaleph_mask((__v32hf)(__m512h)(C), (int)(imm), \ + (__v32hf)(__m512h)(A), \ + (__mmask32)(B), (int)(R))) + +#define _mm512_maskz_roundscale_round_ph(A, B, imm, R) \ + ((__m512h)__builtin_ia32_rndscaleph_mask((__v32hf)(__m512h)(B), (int)(imm), \ + (__v32hf)_mm512_setzero_ph(), \ + (__mmask32)(A), (int)(R))) + +#define _mm512_roundscale_round_ph(A, imm, R) \ + ((__m512h)__builtin_ia32_rndscaleph_mask((__v32hf)(__m512h)(A), (int)(imm), \ + (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_reduce_ph(A, imm) \ + ((__m512h)__builtin_ia32_reduceph512_mask( \ + (__v32hf)(__m512h)(A), (int)(imm), (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)-1, _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_mask_reduce_ph(W, U, A, imm) \ + ((__m512h)__builtin_ia32_reduceph512_mask( \ + (__v32hf)(__m512h)(A), (int)(imm), (__v32hf)(__m512h)(W), \ + (__mmask32)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_maskz_reduce_ph(U, A, imm) \ + ((__m512h)__builtin_ia32_reduceph512_mask( \ + (__v32hf)(__m512h)(A), (int)(imm), (__v32hf)_mm512_setzero_ph(), \ + (__mmask32)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm512_mask_reduce_round_ph(W, U, A, imm, R) \ + ((__m512h)__builtin_ia32_reduceph512_mask((__v32hf)(__m512h)(A), (int)(imm), \ + (__v32hf)(__m512h)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_reduce_round_ph(U, A, imm, R) \ + ((__m512h)__builtin_ia32_reduceph512_mask((__v32hf)(__m512h)(A), (int)(imm), \ + (__v32hf)_mm512_setzero_ph(), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_reduce_round_ph(A, imm, R) \ + ((__m512h)__builtin_ia32_reduceph512_mask((__v32hf)(__m512h)(A), (int)(imm), \ + (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)-1, (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_rcp_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_rcpsh_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_rcp_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_rcpsh_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_rcp_sh(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_rcpsh_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_rsqrt_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_rsqrtsh_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_rsqrt_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_rsqrtsh_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_rsqrt_sh(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_rsqrtsh_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +#define _mm_getmant_round_sh(A, B, C, D, R) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)_mm_setzero_ph(), (__mmask8)-1, (int)(R))) + +#define _mm_getmant_sh(A, B, C, D) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)_mm_setzero_ph(), (__mmask8)-1, _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_getmant_sh(W, U, A, B, C, D) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)(__m128h)(W), (__mmask8)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_getmant_round_sh(W, U, A, B, C, D, R) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)(__m128h)(W), (__mmask8)(U), (int)(R))) + +#define _mm_maskz_getmant_sh(U, A, B, C, D) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)_mm_setzero_ph(), (__mmask8)(U), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_maskz_getmant_round_sh(U, A, B, C, D, R) \ + ((__m128h)__builtin_ia32_getmantsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (int)(((D) << 2) | (C)), \ + (__v8hf)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +#define _mm_getexp_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_getexpsh128_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_getexp_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_getexpsh128_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_getexp_sh(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_getexpsh128_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask_getexp_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_getexpsh128_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_getexp_sh(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_getexpsh128_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_getexp_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_getexpsh128_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +#define _mm_scalef_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_scalefsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_scalef_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_scalefsh_round_mask( + (__v8hf)__A, (__v8hf)(__B), (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_scalef_sh(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_scalefsh_round_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask_scalef_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_scalefsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_scalef_sh(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_scalefsh_round_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_scalef_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_scalefsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +#define _mm_roundscale_round_sh(A, B, imm, R) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(imm), (int)(R))) + +#define _mm_roundscale_sh(A, B, imm) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(imm), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_roundscale_sh(W, U, A, B, I) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(I), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_roundscale_round_sh(W, U, A, B, I, R) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(I), (int)(R))) + +#define _mm_maskz_roundscale_sh(U, A, B, I) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(I), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_maskz_roundscale_round_sh(U, A, B, I, R) \ + ((__m128h)__builtin_ia32_rndscalesh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(I), (int)(R))) + +#define _mm_reduce_sh(A, B, C) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(C), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_mask_reduce_sh(W, U, A, B, C) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(C), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_maskz_reduce_sh(U, A, B, C) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(C), _MM_FROUND_CUR_DIRECTION)) + +#define _mm_reduce_round_sh(A, B, C, R) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(C), (int)(R))) + +#define _mm_mask_reduce_round_sh(W, U, A, B, C, R) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(C), (int)(R))) + +#define _mm_maskz_reduce_round_sh(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_reducesh_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(C), (int)(R))) + +#define _mm512_sqrt_round_ph(A, R) \ + ((__m512h)__builtin_ia32_sqrtph512((__v32hf)(__m512h)(A), (int)(R))) + +#define _mm512_mask_sqrt_round_ph(W, U, A, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_sqrt_round_ph((A), (R)), \ + (__v32hf)(__m512h)(W))) + +#define _mm512_maskz_sqrt_round_ph(U, A, R) \ + ((__m512h)__builtin_ia32_selectph_512( \ + (__mmask32)(U), (__v32hf)_mm512_sqrt_round_ph((A), (R)), \ + (__v32hf)_mm512_setzero_ph())) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_sqrt_ph(__m512h __A) { + return (__m512h)__builtin_ia32_sqrtph512((__v32hf)__A, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_sqrt_ph(__m512h __W, __mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)(__U), + (__v32hf)__builtin_ia32_sqrtph512((__A), (_MM_FROUND_CUR_DIRECTION)), + (__v32hf)(__m512h)(__W)); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_sqrt_ph(__mmask32 __U, __m512h __A) { + return (__m512h)__builtin_ia32_selectph_512( + (__mmask32)(__U), + (__v32hf)__builtin_ia32_sqrtph512((__A), (_MM_FROUND_CUR_DIRECTION)), + (__v32hf)_mm512_setzero_ph()); +} + +#define _mm_sqrt_round_sh(A, B, R) \ + ((__m128h)__builtin_ia32_sqrtsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_sqrt_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_sqrtsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_sqrt_round_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_sqrtsh_round_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_sqrt_sh(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_sqrtsh_round_mask( + (__v8hf)(__m128h)(__A), (__v8hf)(__m128h)(__B), (__v8hf)_mm_setzero_ph(), + (__mmask8)-1, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_sqrt_sh(__m128h __W, + __mmask32 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_sqrtsh_round_mask( + (__v8hf)(__m128h)(__A), (__v8hf)(__m128h)(__B), (__v8hf)(__m128h)(__W), + (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_sqrt_sh(__mmask32 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_sqrtsh_round_mask( + (__v8hf)(__m128h)(__A), (__v8hf)(__m128h)(__B), (__v8hf)_mm_setzero_ph(), + (__mmask8)(__U), _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_mask_fpclass_ph_mask(U, A, imm) \ + ((__mmask32)__builtin_ia32_fpclassph512_mask((__v32hf)(__m512h)(A), \ + (int)(imm), (__mmask32)(U))) + +#define _mm512_fpclass_ph_mask(A, imm) \ + ((__mmask32)__builtin_ia32_fpclassph512_mask((__v32hf)(__m512h)(A), \ + (int)(imm), (__mmask32)-1)) + +#define _mm_fpclass_sh_mask(A, imm) \ + ((__mmask8)__builtin_ia32_fpclasssh_mask((__v8hf)(__m128h)(A), (int)(imm), \ + (__mmask8)-1)) + +#define _mm_mask_fpclass_sh_mask(U, A, imm) \ + ((__mmask8)__builtin_ia32_fpclasssh_mask((__v8hf)(__m128h)(A), (int)(imm), \ + (__mmask8)(U))) + +#define _mm512_cvt_roundpd_ph(A, R) \ + ((__m128h)__builtin_ia32_vcvtpd2ph512_mask( \ + (__v8df)(A), (__v8hf)_mm_undefined_ph(), (__mmask8)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundpd_ph(W, U, A, R) \ + ((__m128h)__builtin_ia32_vcvtpd2ph512_mask((__v8df)(A), (__v8hf)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundpd_ph(U, A, R) \ + ((__m128h)__builtin_ia32_vcvtpd2ph512_mask( \ + (__v8df)(A), (__v8hf)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 _mm512_cvtpd_ph(__m512d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph512_mask( + (__v8df)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtpd_ph(__m128h __W, __mmask8 __U, __m512d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph512_mask( + (__v8df)__A, (__v8hf)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtpd_ph(__mmask8 __U, __m512d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph512_mask( + (__v8df)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_pd(A, R) \ + ((__m512d)__builtin_ia32_vcvtph2pd512_mask( \ + (__v8hf)(A), (__v8df)_mm512_undefined_pd(), (__mmask8)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundph_pd(W, U, A, R) \ + ((__m512d)__builtin_ia32_vcvtph2pd512_mask((__v8hf)(A), (__v8df)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_pd(U, A, R) \ + ((__m512d)__builtin_ia32_vcvtph2pd512_mask( \ + (__v8hf)(A), (__v8df)_mm512_setzero_pd(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512d __DEFAULT_FN_ATTRS512 _mm512_cvtph_pd(__m128h __A) { + return (__m512d)__builtin_ia32_vcvtph2pd512_mask( + (__v8hf)__A, (__v8df)_mm512_setzero_pd(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512d __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_pd(__m512d __W, __mmask8 __U, __m128h __A) { + return (__m512d)__builtin_ia32_vcvtph2pd512_mask( + (__v8hf)__A, (__v8df)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512d __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_pd(__mmask8 __U, __m128h __A) { + return (__m512d)__builtin_ia32_vcvtph2pd512_mask( + (__v8hf)__A, (__v8df)_mm512_setzero_pd(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsh_ss(A, B, R) \ + ((__m128)__builtin_ia32_vcvtsh2ss_round_mask((__v4sf)(A), (__v8hf)(B), \ + (__v4sf)_mm_undefined_ps(), \ + (__mmask8)(-1), (int)(R))) + +#define _mm_mask_cvt_roundsh_ss(W, U, A, B, R) \ + ((__m128)__builtin_ia32_vcvtsh2ss_round_mask( \ + (__v4sf)(A), (__v8hf)(B), (__v4sf)(W), (__mmask8)(U), (int)(R))) + +#define _mm_maskz_cvt_roundsh_ss(U, A, B, R) \ + ((__m128)__builtin_ia32_vcvtsh2ss_round_mask((__v4sf)(A), (__v8hf)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_cvtsh_ss(__m128 __A, + __m128h __B) { + return (__m128)__builtin_ia32_vcvtsh2ss_round_mask( + (__v4sf)__A, (__v8hf)__B, (__v4sf)_mm_undefined_ps(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_cvtsh_ss(__m128 __W, + __mmask8 __U, + __m128 __A, + __m128h __B) { + return (__m128)__builtin_ia32_vcvtsh2ss_round_mask((__v4sf)__A, (__v8hf)__B, + (__v4sf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_cvtsh_ss(__mmask8 __U, + __m128 __A, + __m128h __B) { + return (__m128)__builtin_ia32_vcvtsh2ss_round_mask( + (__v4sf)__A, (__v8hf)__B, (__v4sf)_mm_setzero_ps(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundss_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtss2sh_round_mask((__v8hf)(A), (__v4sf)(B), \ + (__v8hf)_mm_undefined_ph(), \ + (__mmask8)(-1), (int)(R))) + +#define _mm_mask_cvt_roundss_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vcvtss2sh_round_mask( \ + (__v8hf)(A), (__v4sf)(B), (__v8hf)(W), (__mmask8)(U), (int)(R))) + +#define _mm_maskz_cvt_roundss_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_vcvtss2sh_round_mask((__v8hf)(A), (__v4sf)(B), \ + (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtss_sh(__m128h __A, + __m128 __B) { + return (__m128h)__builtin_ia32_vcvtss2sh_round_mask( + (__v8hf)__A, (__v4sf)__B, (__v8hf)_mm_undefined_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_cvtss_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128 __B) { + return (__m128h)__builtin_ia32_vcvtss2sh_round_mask( + (__v8hf)__A, (__v4sf)__B, (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_cvtss_sh(__mmask8 __U, + __m128h __A, + __m128 __B) { + return (__m128h)__builtin_ia32_vcvtss2sh_round_mask( + (__v8hf)__A, (__v4sf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsd_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtsd2sh_round_mask((__v8hf)(A), (__v2df)(B), \ + (__v8hf)_mm_undefined_ph(), \ + (__mmask8)(-1), (int)(R))) + +#define _mm_mask_cvt_roundsd_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vcvtsd2sh_round_mask( \ + (__v8hf)(A), (__v2df)(B), (__v8hf)(W), (__mmask8)(U), (int)(R))) + +#define _mm_maskz_cvt_roundsd_sh(U, A, B, R) \ + ((__m128h)__builtin_ia32_vcvtsd2sh_round_mask((__v8hf)(A), (__v2df)(B), \ + (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtsd_sh(__m128h __A, + __m128d __B) { + return (__m128h)__builtin_ia32_vcvtsd2sh_round_mask( + (__v8hf)__A, (__v2df)__B, (__v8hf)_mm_undefined_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_cvtsd_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128d __B) { + return (__m128h)__builtin_ia32_vcvtsd2sh_round_mask( + (__v8hf)__A, (__v2df)__B, (__v8hf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtsd_sh(__mmask8 __U, __m128h __A, __m128d __B) { + return (__m128h)__builtin_ia32_vcvtsd2sh_round_mask( + (__v8hf)__A, (__v2df)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsh_sd(A, B, R) \ + ((__m128d)__builtin_ia32_vcvtsh2sd_round_mask((__v2df)(A), (__v8hf)(B), \ + (__v2df)_mm_undefined_pd(), \ + (__mmask8)(-1), (int)(R))) + +#define _mm_mask_cvt_roundsh_sd(W, U, A, B, R) \ + ((__m128d)__builtin_ia32_vcvtsh2sd_round_mask( \ + (__v2df)(A), (__v8hf)(B), (__v2df)(W), (__mmask8)(U), (int)(R))) + +#define _mm_maskz_cvt_roundsh_sd(U, A, B, R) \ + ((__m128d)__builtin_ia32_vcvtsh2sd_round_mask((__v2df)(A), (__v8hf)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_cvtsh_sd(__m128d __A, + __m128h __B) { + return (__m128d)__builtin_ia32_vcvtsh2sd_round_mask( + (__v2df)__A, (__v8hf)__B, (__v2df)_mm_undefined_pd(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_cvtsh_sd(__m128d __W, + __mmask8 __U, + __m128d __A, + __m128h __B) { + return (__m128d)__builtin_ia32_vcvtsh2sd_round_mask( + (__v2df)__A, (__v8hf)__B, (__v2df)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtsh_sd(__mmask8 __U, __m128d __A, __m128h __B) { + return (__m128d)__builtin_ia32_vcvtsh2sd_round_mask( + (__v2df)__A, (__v8hf)__B, (__v2df)_mm_setzero_pd(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epi16(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2w512_mask((__v32hf)(A), \ + (__v32hi)_mm512_undefined_epi32(), \ + (__mmask32)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundph_epi16(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2w512_mask((__v32hf)(A), (__v32hi)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epi16(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2w512_mask((__v32hf)(A), \ + (__v32hi)_mm512_setzero_epi32(), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epi16(__m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2w512_mask( + (__v32hf)__A, (__v32hi)_mm512_setzero_epi32(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epi16(__m512i __W, __mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2w512_mask( + (__v32hf)__A, (__v32hi)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epi16(__mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2w512_mask( + (__v32hf)__A, (__v32hi)_mm512_setzero_epi32(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epi16(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2w512_mask( \ + (__v32hf)(A), (__v32hi)_mm512_undefined_epi32(), (__mmask32)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epi16(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2w512_mask((__v32hf)(A), (__v32hi)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epi16(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2w512_mask((__v32hf)(A), \ + (__v32hi)_mm512_setzero_epi32(), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epi16(__m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2w512_mask( + (__v32hf)__A, (__v32hi)_mm512_setzero_epi32(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epi16(__m512i __W, __mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2w512_mask( + (__v32hf)__A, (__v32hi)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epi16(__mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2w512_mask( + (__v32hf)__A, (__v32hi)_mm512_setzero_epi32(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepi16_ph(A, R) \ + ((__m512h)__builtin_ia32_vcvtw2ph512_mask((__v32hi)(A), \ + (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepi16_ph(W, U, A, R) \ + ((__m512h)__builtin_ia32_vcvtw2ph512_mask((__v32hi)(A), (__v32hf)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepi16_ph(U, A, R) \ + ((__m512h)__builtin_ia32_vcvtw2ph512_mask( \ + (__v32hi)(A), (__v32hf)_mm512_setzero_ph(), (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_cvtepi16_ph(__m512i __A) { + return (__m512h)__builtin_ia32_vcvtw2ph512_mask( + (__v32hi)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepi16_ph(__m512h __W, __mmask32 __U, __m512i __A) { + return (__m512h)__builtin_ia32_vcvtw2ph512_mask( + (__v32hi)__A, (__v32hf)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepi16_ph(__mmask32 __U, __m512i __A) { + return (__m512h)__builtin_ia32_vcvtw2ph512_mask( + (__v32hi)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epu16(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uw512_mask( \ + (__v32hf)(A), (__v32hu)_mm512_undefined_epi32(), (__mmask32)(-1), \ + (int)(R))) + +#define _mm512_mask_cvt_roundph_epu16(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uw512_mask((__v32hf)(A), (__v32hu)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epu16(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uw512_mask((__v32hf)(A), \ + (__v32hu)_mm512_setzero_epi32(), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epu16(__m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2uw512_mask( + (__v32hf)__A, (__v32hu)_mm512_setzero_epi32(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epu16(__m512i __W, __mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2uw512_mask( + (__v32hf)__A, (__v32hu)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epu16(__mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvtph2uw512_mask( + (__v32hf)__A, (__v32hu)_mm512_setzero_epi32(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epu16(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uw512_mask( \ + (__v32hf)(A), (__v32hu)_mm512_undefined_epi32(), (__mmask32)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epu16(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uw512_mask((__v32hf)(A), (__v32hu)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epu16(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uw512_mask((__v32hf)(A), \ + (__v32hu)_mm512_setzero_epi32(), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epu16(__m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2uw512_mask( + (__v32hf)__A, (__v32hu)_mm512_setzero_epi32(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epu16(__m512i __W, __mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2uw512_mask( + (__v32hf)__A, (__v32hu)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epu16(__mmask32 __U, __m512h __A) { + return (__m512i)__builtin_ia32_vcvttph2uw512_mask( + (__v32hf)__A, (__v32hu)_mm512_setzero_epi32(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepu16_ph(A, R) \ + ((__m512h)__builtin_ia32_vcvtuw2ph512_mask((__v32hu)(A), \ + (__v32hf)_mm512_undefined_ph(), \ + (__mmask32)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepu16_ph(W, U, A, R) \ + ((__m512h)__builtin_ia32_vcvtuw2ph512_mask((__v32hu)(A), (__v32hf)(W), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepu16_ph(U, A, R) \ + ((__m512h)__builtin_ia32_vcvtuw2ph512_mask( \ + (__v32hu)(A), (__v32hf)_mm512_setzero_ph(), (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_cvtepu16_ph(__m512i __A) { + return (__m512h)__builtin_ia32_vcvtuw2ph512_mask( + (__v32hu)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepu16_ph(__m512h __W, __mmask32 __U, __m512i __A) { + return (__m512h)__builtin_ia32_vcvtuw2ph512_mask( + (__v32hu)__A, (__v32hf)__W, (__mmask32)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepu16_ph(__mmask32 __U, __m512i __A) { + return (__m512h)__builtin_ia32_vcvtuw2ph512_mask( + (__v32hu)__A, (__v32hf)_mm512_setzero_ph(), (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epi32(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2dq512_mask( \ + (__v16hf)(A), (__v16si)_mm512_undefined_epi32(), (__mmask16)(-1), \ + (int)(R))) + +#define _mm512_mask_cvt_roundph_epi32(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2dq512_mask((__v16hf)(A), (__v16si)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epi32(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2dq512_mask((__v16hf)(A), \ + (__v16si)_mm512_setzero_epi32(), \ + (__mmask16)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epi32(__m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2dq512_mask( + (__v16hf)__A, (__v16si)_mm512_setzero_epi32(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epi32(__m512i __W, __mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2dq512_mask( + (__v16hf)__A, (__v16si)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epi32(__mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2dq512_mask( + (__v16hf)__A, (__v16si)_mm512_setzero_epi32(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epu32(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2udq512_mask( \ + (__v16hf)(A), (__v16su)_mm512_undefined_epi32(), (__mmask16)(-1), \ + (int)(R))) + +#define _mm512_mask_cvt_roundph_epu32(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2udq512_mask((__v16hf)(A), (__v16su)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epu32(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2udq512_mask((__v16hf)(A), \ + (__v16su)_mm512_setzero_epi32(), \ + (__mmask16)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epu32(__m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2udq512_mask( + (__v16hf)__A, (__v16su)_mm512_setzero_epi32(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epu32(__m512i __W, __mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2udq512_mask( + (__v16hf)__A, (__v16su)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epu32(__mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvtph2udq512_mask( + (__v16hf)__A, (__v16su)_mm512_setzero_epi32(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepi32_ph(A, R) \ + ((__m256h)__builtin_ia32_vcvtdq2ph512_mask((__v16si)(A), \ + (__v16hf)_mm256_undefined_ph(), \ + (__mmask16)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepi32_ph(W, U, A, R) \ + ((__m256h)__builtin_ia32_vcvtdq2ph512_mask((__v16si)(A), (__v16hf)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepi32_ph(U, A, R) \ + ((__m256h)__builtin_ia32_vcvtdq2ph512_mask( \ + (__v16si)(A), (__v16hf)_mm256_setzero_ph(), (__mmask16)(U), (int)(R))) + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_cvtepi32_ph(__m512i __A) { + return (__m256h)__builtin_ia32_vcvtdq2ph512_mask( + (__v16si)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepi32_ph(__m256h __W, __mmask16 __U, __m512i __A) { + return (__m256h)__builtin_ia32_vcvtdq2ph512_mask( + (__v16si)__A, (__v16hf)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepi32_ph(__mmask16 __U, __m512i __A) { + return (__m256h)__builtin_ia32_vcvtdq2ph512_mask( + (__v16si)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepu32_ph(A, R) \ + ((__m256h)__builtin_ia32_vcvtudq2ph512_mask((__v16su)(A), \ + (__v16hf)_mm256_undefined_ph(), \ + (__mmask16)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepu32_ph(W, U, A, R) \ + ((__m256h)__builtin_ia32_vcvtudq2ph512_mask((__v16su)(A), (__v16hf)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepu32_ph(U, A, R) \ + ((__m256h)__builtin_ia32_vcvtudq2ph512_mask( \ + (__v16su)(A), (__v16hf)_mm256_setzero_ph(), (__mmask16)(U), (int)(R))) + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_cvtepu32_ph(__m512i __A) { + return (__m256h)__builtin_ia32_vcvtudq2ph512_mask( + (__v16su)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepu32_ph(__m256h __W, __mmask16 __U, __m512i __A) { + return (__m256h)__builtin_ia32_vcvtudq2ph512_mask( + (__v16su)__A, (__v16hf)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepu32_ph(__mmask16 __U, __m512i __A) { + return (__m256h)__builtin_ia32_vcvtudq2ph512_mask( + (__v16su)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epi32(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2dq512_mask( \ + (__v16hf)(A), (__v16si)_mm512_undefined_epi32(), (__mmask16)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epi32(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2dq512_mask((__v16hf)(A), (__v16si)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epi32(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2dq512_mask((__v16hf)(A), \ + (__v16si)_mm512_setzero_epi32(), \ + (__mmask16)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epi32(__m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2dq512_mask( + (__v16hf)__A, (__v16si)_mm512_setzero_epi32(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epi32(__m512i __W, __mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2dq512_mask( + (__v16hf)__A, (__v16si)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epi32(__mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2dq512_mask( + (__v16hf)__A, (__v16si)_mm512_setzero_epi32(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epu32(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2udq512_mask( \ + (__v16hf)(A), (__v16su)_mm512_undefined_epi32(), (__mmask16)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epu32(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2udq512_mask((__v16hf)(A), (__v16su)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epu32(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2udq512_mask( \ + (__v16hf)(A), (__v16su)_mm512_setzero_epi32(), (__mmask16)(U), \ + (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epu32(__m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2udq512_mask( + (__v16hf)__A, (__v16su)_mm512_setzero_epi32(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epu32(__m512i __W, __mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2udq512_mask( + (__v16hf)__A, (__v16su)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epu32(__mmask16 __U, __m256h __A) { + return (__m512i)__builtin_ia32_vcvttph2udq512_mask( + (__v16hf)__A, (__v16su)_mm512_setzero_epi32(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepi64_ph(A, R) \ + ((__m128h)__builtin_ia32_vcvtqq2ph512_mask( \ + (__v8di)(A), (__v8hf)_mm_undefined_ph(), (__mmask8)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepi64_ph(W, U, A, R) \ + ((__m128h)__builtin_ia32_vcvtqq2ph512_mask((__v8di)(A), (__v8hf)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepi64_ph(U, A, R) \ + ((__m128h)__builtin_ia32_vcvtqq2ph512_mask( \ + (__v8di)(A), (__v8hf)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_cvtepi64_ph(__m512i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph512_mask( + (__v8di)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepi64_ph(__m128h __W, __mmask8 __U, __m512i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph512_mask( + (__v8di)__A, (__v8hf)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepi64_ph(__mmask8 __U, __m512i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph512_mask( + (__v8di)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epi64(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2qq512_mask((__v8hf)(A), \ + (__v8di)_mm512_undefined_epi32(), \ + (__mmask8)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundph_epi64(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2qq512_mask((__v8hf)(A), (__v8di)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epi64(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2qq512_mask( \ + (__v8hf)(A), (__v8di)_mm512_setzero_epi32(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epi64(__m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2qq512_mask( + (__v8hf)__A, (__v8di)_mm512_setzero_epi32(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epi64(__m512i __W, __mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2qq512_mask( + (__v8hf)__A, (__v8di)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epi64(__mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2qq512_mask( + (__v8hf)__A, (__v8di)_mm512_setzero_epi32(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundepu64_ph(A, R) \ + ((__m128h)__builtin_ia32_vcvtuqq2ph512_mask( \ + (__v8du)(A), (__v8hf)_mm_undefined_ph(), (__mmask8)(-1), (int)(R))) + +#define _mm512_mask_cvt_roundepu64_ph(W, U, A, R) \ + ((__m128h)__builtin_ia32_vcvtuqq2ph512_mask((__v8du)(A), (__v8hf)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundepu64_ph(U, A, R) \ + ((__m128h)__builtin_ia32_vcvtuqq2ph512_mask( \ + (__v8du)(A), (__v8hf)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_cvtepu64_ph(__m512i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph512_mask( + (__v8du)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtepu64_ph(__m128h __W, __mmask8 __U, __m512i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph512_mask( + (__v8du)__A, (__v8hf)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtepu64_ph(__mmask8 __U, __m512i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph512_mask( + (__v8du)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvt_roundph_epu64(A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uqq512_mask( \ + (__v8hf)(A), (__v8du)_mm512_undefined_epi32(), (__mmask8)(-1), \ + (int)(R))) + +#define _mm512_mask_cvt_roundph_epu64(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uqq512_mask((__v8hf)(A), (__v8du)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvt_roundph_epu64(U, A, R) \ + ((__m512i)__builtin_ia32_vcvtph2uqq512_mask( \ + (__v8hf)(A), (__v8du)_mm512_setzero_epi32(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvtph_epu64(__m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2uqq512_mask( + (__v8hf)__A, (__v8du)_mm512_setzero_epi32(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtph_epu64(__m512i __W, __mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2uqq512_mask( + (__v8hf)__A, (__v8du)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtph_epu64(__mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvtph2uqq512_mask( + (__v8hf)__A, (__v8du)_mm512_setzero_epi32(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epi64(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2qq512_mask( \ + (__v8hf)(A), (__v8di)_mm512_undefined_epi32(), (__mmask8)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epi64(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2qq512_mask((__v8hf)(A), (__v8di)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epi64(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2qq512_mask( \ + (__v8hf)(A), (__v8di)_mm512_setzero_epi32(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epi64(__m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2qq512_mask( + (__v8hf)__A, (__v8di)_mm512_setzero_epi32(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epi64(__m512i __W, __mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2qq512_mask( + (__v8hf)__A, (__v8di)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epi64(__mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2qq512_mask( + (__v8hf)__A, (__v8di)_mm512_setzero_epi32(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtt_roundph_epu64(A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uqq512_mask( \ + (__v8hf)(A), (__v8du)_mm512_undefined_epi32(), (__mmask8)(-1), \ + (int)(R))) + +#define _mm512_mask_cvtt_roundph_epu64(W, U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uqq512_mask((__v8hf)(A), (__v8du)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm512_maskz_cvtt_roundph_epu64(U, A, R) \ + ((__m512i)__builtin_ia32_vcvttph2uqq512_mask( \ + (__v8hf)(A), (__v8du)_mm512_setzero_epi32(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_cvttph_epu64(__m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2uqq512_mask( + (__v8hf)__A, (__v8du)_mm512_setzero_epi32(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_mask_cvttph_epu64(__m512i __W, __mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2uqq512_mask( + (__v8hf)__A, (__v8du)__W, (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512i __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvttph_epu64(__mmask8 __U, __m128h __A) { + return (__m512i)__builtin_ia32_vcvttph2uqq512_mask( + (__v8hf)__A, (__v8du)_mm512_setzero_epi32(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsh_i32(A, R) \ + ((int)__builtin_ia32_vcvtsh2si32((__v8hf)(A), (int)(R))) + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_cvtsh_i32(__m128h __A) { + return (int)__builtin_ia32_vcvtsh2si32((__v8hf)__A, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsh_u32(A, R) \ + ((unsigned int)__builtin_ia32_vcvtsh2usi32((__v8hf)(A), (int)(R))) + +static __inline__ unsigned int __DEFAULT_FN_ATTRS128 +_mm_cvtsh_u32(__m128h __A) { + return (unsigned int)__builtin_ia32_vcvtsh2usi32((__v8hf)__A, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __x86_64__ +#define _mm_cvt_roundsh_i64(A, R) \ + ((long long)__builtin_ia32_vcvtsh2si64((__v8hf)(A), (int)(R))) + +static __inline__ long long __DEFAULT_FN_ATTRS128 _mm_cvtsh_i64(__m128h __A) { + return (long long)__builtin_ia32_vcvtsh2si64((__v8hf)__A, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_cvt_roundsh_u64(A, R) \ + ((unsigned long long)__builtin_ia32_vcvtsh2usi64((__v8hf)(A), (int)(R))) + +static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 +_mm_cvtsh_u64(__m128h __A) { + return (unsigned long long)__builtin_ia32_vcvtsh2usi64( + (__v8hf)__A, _MM_FROUND_CUR_DIRECTION); +} +#endif // __x86_64__ + +#define _mm_cvt_roundu32_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtusi2sh((__v8hf)(A), (unsigned int)(B), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_cvtu32_sh(__m128h __A, unsigned int __B) { + __A[0] = __B; + return __A; +} + +#ifdef __x86_64__ +#define _mm_cvt_roundu64_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtusi642sh((__v8hf)(A), (unsigned long long)(B), \ + (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_cvtu64_sh(__m128h __A, unsigned long long __B) { + __A[0] = __B; + return __A; +} +#endif + +#define _mm_cvt_roundi32_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtsi2sh((__v8hf)(A), (int)(B), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvti32_sh(__m128h __A, + int __B) { + __A[0] = __B; + return __A; +} + +#ifdef __x86_64__ +#define _mm_cvt_roundi64_sh(A, B, R) \ + ((__m128h)__builtin_ia32_vcvtsi642sh((__v8hf)(A), (long long)(B), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvti64_sh(__m128h __A, + long long __B) { + __A[0] = __B; + return __A; +} +#endif + +#define _mm_cvtt_roundsh_i32(A, R) \ + ((int)__builtin_ia32_vcvttsh2si32((__v8hf)(A), (int)(R))) + +static __inline__ int __DEFAULT_FN_ATTRS128 _mm_cvttsh_i32(__m128h __A) { + return (int)__builtin_ia32_vcvttsh2si32((__v8hf)__A, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __x86_64__ +#define _mm_cvtt_roundsh_i64(A, R) \ + ((long long)__builtin_ia32_vcvttsh2si64((__v8hf)(A), (int)(R))) + +static __inline__ long long __DEFAULT_FN_ATTRS128 _mm_cvttsh_i64(__m128h __A) { + return (long long)__builtin_ia32_vcvttsh2si64((__v8hf)__A, + _MM_FROUND_CUR_DIRECTION); +} +#endif + +#define _mm_cvtt_roundsh_u32(A, R) \ + ((unsigned int)__builtin_ia32_vcvttsh2usi32((__v8hf)(A), (int)(R))) + +static __inline__ unsigned int __DEFAULT_FN_ATTRS128 +_mm_cvttsh_u32(__m128h __A) { + return (unsigned int)__builtin_ia32_vcvttsh2usi32((__v8hf)__A, + _MM_FROUND_CUR_DIRECTION); +} + +#ifdef __x86_64__ +#define _mm_cvtt_roundsh_u64(A, R) \ + ((unsigned long long)__builtin_ia32_vcvttsh2usi64((__v8hf)(A), (int)(R))) + +static __inline__ unsigned long long __DEFAULT_FN_ATTRS128 +_mm_cvttsh_u64(__m128h __A) { + return (unsigned long long)__builtin_ia32_vcvttsh2usi64( + (__v8hf)__A, _MM_FROUND_CUR_DIRECTION); +} +#endif + +#define _mm512_cvtx_roundph_ps(A, R) \ + ((__m512)__builtin_ia32_vcvtph2psx512_mask((__v16hf)(A), \ + (__v16sf)_mm512_undefined_ps(), \ + (__mmask16)(-1), (int)(R))) + +#define _mm512_mask_cvtx_roundph_ps(W, U, A, R) \ + ((__m512)__builtin_ia32_vcvtph2psx512_mask((__v16hf)(A), (__v16sf)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvtx_roundph_ps(U, A, R) \ + ((__m512)__builtin_ia32_vcvtph2psx512_mask( \ + (__v16hf)(A), (__v16sf)_mm512_setzero_ps(), (__mmask16)(U), (int)(R))) + +static __inline__ __m512 __DEFAULT_FN_ATTRS512 _mm512_cvtxph_ps(__m256h __A) { + return (__m512)__builtin_ia32_vcvtph2psx512_mask( + (__v16hf)__A, (__v16sf)_mm512_setzero_ps(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512 __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtxph_ps(__m512 __W, __mmask16 __U, __m256h __A) { + return (__m512)__builtin_ia32_vcvtph2psx512_mask( + (__v16hf)__A, (__v16sf)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512 __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtxph_ps(__mmask16 __U, __m256h __A) { + return (__m512)__builtin_ia32_vcvtph2psx512_mask( + (__v16hf)__A, (__v16sf)_mm512_setzero_ps(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_cvtx_roundps_ph(A, R) \ + ((__m256h)__builtin_ia32_vcvtps2phx512_mask((__v16sf)(A), \ + (__v16hf)_mm256_undefined_ph(), \ + (__mmask16)(-1), (int)(R))) + +#define _mm512_mask_cvtx_roundps_ph(W, U, A, R) \ + ((__m256h)__builtin_ia32_vcvtps2phx512_mask((__v16sf)(A), (__v16hf)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_cvtx_roundps_ph(U, A, R) \ + ((__m256h)__builtin_ia32_vcvtps2phx512_mask( \ + (__v16sf)(A), (__v16hf)_mm256_setzero_ph(), (__mmask16)(U), (int)(R))) + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 _mm512_cvtxps_ph(__m512 __A) { + return (__m256h)__builtin_ia32_vcvtps2phx512_mask( + (__v16sf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_mask_cvtxps_ph(__m256h __W, __mmask16 __U, __m512 __A) { + return (__m256h)__builtin_ia32_vcvtps2phx512_mask( + (__v16sf)__A, (__v16hf)__W, (__mmask16)__U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS512 +_mm512_maskz_cvtxps_ph(__mmask16 __U, __m512 __A) { + return (__m256h)__builtin_ia32_vcvtps2phx512_mask( + (__v16sf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fmadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_fmadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_mask3_fmadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask3( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_fmadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_maskz( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_fmsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_fmsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_fmsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_maskz( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_fnmadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), -(__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask3_fnmadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask3( \ + -(__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_fnmadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_maskz( \ + -(__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_fnmsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), -(__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_maskz_fnmsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_maskz( \ + -(__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fmadd_ph(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmadd_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fmadd_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmaddph512_mask3((__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmadd_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_maskz((__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fmsub_ph(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, (__v32hf)__B, + -(__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmsub_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, (__v32hf)__B, + -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmsub_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_maskz( + (__v32hf)__A, (__v32hf)__B, -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fnmadd_ph(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, -(__v32hf)__B, + (__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fnmadd_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmaddph512_mask3(-(__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fnmadd_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_maskz(-(__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fnmsub_ph(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, -(__v32hf)__B, + -(__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fnmsub_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_maskz( + -(__v32hf)__A, (__v32hf)__B, -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fmaddsub_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_fmaddsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_mask3_fmaddsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask3( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_fmaddsub_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_maskz( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_fmsubadd_round_ph(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)-1, (int)(R))) + +#define _mm512_mask_fmsubadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_mask( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_maskz_fmsubadd_round_ph(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddsubph512_maskz( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_fmaddsub_ph(__m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_mask( + (__v32hf)__A, (__v32hf)__B, (__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmaddsub_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_mask( + (__v32hf)__A, (__v32hf)__B, (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fmaddsub_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmaddsubph512_mask3( + (__v32hf)__A, (__v32hf)__B, (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmaddsub_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_maskz( + (__v32hf)__A, (__v32hf)__B, (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_fmsubadd_ph(__m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_mask( + (__v32hf)__A, (__v32hf)__B, -(__v32hf)__C, (__mmask32)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmsubadd_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_mask( + (__v32hf)__A, (__v32hf)__B, -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmsubadd_ph(__mmask32 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddsubph512_maskz( + (__v32hf)__A, (__v32hf)__B, -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_mask3_fmsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_mask3( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fmsub_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmsubph512_mask3((__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_mask3_fmsubadd_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmsubaddph512_mask3( \ + (__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fmsubadd_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmsubaddph512_mask3( + (__v32hf)__A, (__v32hf)__B, (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_mask_fnmadd_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), -(__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fnmadd_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, -(__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_mask_fnmsub_round_ph(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddph512_mask( \ + (__v32hf)(__m512h)(A), -(__v32hf)(__m512h)(B), -(__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +#define _mm512_mask3_fnmsub_round_ph(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmsubph512_mask3( \ + -(__v32hf)(__m512h)(A), (__v32hf)(__m512h)(B), (__v32hf)(__m512h)(C), \ + (__mmask32)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fnmsub_ph(__m512h __A, __mmask32 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddph512_mask((__v32hf)__A, -(__v32hf)__B, + -(__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fnmsub_ph(__m512h __A, __m512h __B, __m512h __C, __mmask32 __U) { + return (__m512h)__builtin_ia32_vfmsubph512_mask3(-(__v32hf)__A, (__v32hf)__B, + (__v32hf)__C, (__mmask32)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmadd_sh(__m128h __W, + __m128h __A, + __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, (__v8hf)__A, (__v8hf)__B, + (__mmask8)-1, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmadd_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, (__v8hf)__A, (__v8hf)__B, + (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fmadd_round_sh(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fmadd_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(W), (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmadd_sh(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return __builtin_ia32_vfmaddsh3_maskz((__v8hf)__A, (__v8hf)__B, (__v8hf)__C, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_fmadd_round_sh(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_maskz( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), (__v8hf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmadd_sh(__m128h __W, __m128h __X, __m128h __Y, __mmask8 __U) { + return __builtin_ia32_vfmaddsh3_mask3((__v8hf)__W, (__v8hf)__X, (__v8hf)__Y, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask3_fmadd_round_sh(W, X, Y, U, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask3( \ + (__v8hf)(__m128h)(W), (__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmsub_sh(__m128h __W, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmaddsh3_mask((__v8hf)__W, (__v8hf)__A, + -(__v8hf)__B, (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmsub_sh(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmaddsh3_mask((__v8hf)__W, (__v8hf)__A, + -(__v8hf)__B, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fmsub_round_sh(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), -(__v8hf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fmsub_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(W), (__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmsub_sh(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddsh3_maskz((__v8hf)__A, (__v8hf)__B, + -(__v8hf)__C, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_fmsub_round_sh(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_maskz( \ + (__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), -(__v8hf)(__m128h)(C), \ + (__mmask8)(U), (int)R)) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmsub_sh(__m128h __W, __m128h __X, __m128h __Y, __mmask8 __U) { + return __builtin_ia32_vfmsubsh3_mask3((__v8hf)__W, (__v8hf)__X, (__v8hf)__Y, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask3_fmsub_round_sh(W, X, Y, U, R) \ + ((__m128h)__builtin_ia32_vfmsubsh3_mask3( \ + (__v8hf)(__m128h)(W), (__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fnmadd_sh(__m128h __W, + __m128h __A, + __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, -(__v8hf)__A, (__v8hf)__B, + (__mmask8)-1, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fnmadd_sh(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, -(__v8hf)__A, (__v8hf)__B, + (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fnmadd_round_sh(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), (__v8hf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fnmadd_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(W), -(__v8hf)(__m128h)(A), (__v8hf)(__m128h)(B), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fnmadd_sh(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return __builtin_ia32_vfmaddsh3_maskz((__v8hf)__A, -(__v8hf)__B, (__v8hf)__C, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_fnmadd_round_sh(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_maskz( \ + (__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), (__v8hf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fnmadd_sh(__m128h __W, __m128h __X, __m128h __Y, __mmask8 __U) { + return __builtin_ia32_vfmaddsh3_mask3((__v8hf)__W, -(__v8hf)__X, (__v8hf)__Y, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask3_fnmadd_round_sh(W, X, Y, U, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask3( \ + (__v8hf)(__m128h)(W), -(__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fnmsub_sh(__m128h __W, + __m128h __A, + __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, -(__v8hf)__A, -(__v8hf)__B, + (__mmask8)-1, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fnmsub_sh(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return __builtin_ia32_vfmaddsh3_mask((__v8hf)__W, -(__v8hf)__A, -(__v8hf)__B, + (__mmask8)__U, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fnmsub_round_sh(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), -(__v8hf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fnmsub_round_sh(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_mask( \ + (__v8hf)(__m128h)(W), -(__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fnmsub_sh(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return __builtin_ia32_vfmaddsh3_maskz((__v8hf)__A, -(__v8hf)__B, -(__v8hf)__C, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_maskz_fnmsub_round_sh(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddsh3_maskz( \ + (__v8hf)(__m128h)(A), -(__v8hf)(__m128h)(B), -(__v8hf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fnmsub_sh(__m128h __W, __m128h __X, __m128h __Y, __mmask8 __U) { + return __builtin_ia32_vfmsubsh3_mask3((__v8hf)__W, -(__v8hf)__X, (__v8hf)__Y, + (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_mask3_fnmsub_round_sh(W, X, Y, U, R) \ + ((__m128h)__builtin_ia32_vfmsubsh3_mask3( \ + (__v8hf)(__m128h)(W), -(__v8hf)(__m128h)(X), (__v8hf)(__m128h)(Y), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fcmadd_sch(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfcmaddcsh_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fcmadd_sch(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfcmaddcsh_round_mask( + (__v4sf)__A, (__v4sf)(__B), (__v4sf)(__C), __U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fcmadd_sch(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfcmaddcsh_maskz((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fcmadd_sch(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_vfcmaddcsh_round_mask3( + (__v4sf)__A, (__v4sf)__B, (__v4sf)__C, __U, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fcmadd_round_sch(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfcmaddcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fcmadd_round_sch(A, U, B, C, R) \ + ((__m128h)__builtin_ia32_vfcmaddcsh_round_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fcmadd_round_sch(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfcmaddcsh_maskz( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +#define _mm_mask3_fcmadd_round_sch(A, B, C, U, R) \ + ((__m128h)__builtin_ia32_vfcmaddcsh_round_mask3( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmadd_sch(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddcsh_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fmadd_sch(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddcsh_round_mask( + (__v4sf)__A, (__v4sf)(__B), (__v4sf)(__C), __U, _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmadd_sch(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddcsh_maskz((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmadd_sch(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_vfmaddcsh_round_mask3( + (__v4sf)__A, (__v4sf)__B, (__v4sf)__C, __U, _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fmadd_round_sch(A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)-1, (int)(R))) + +#define _mm_mask_fmadd_round_sch(A, U, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddcsh_round_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fmadd_round_sch(U, A, B, C, R) \ + ((__m128h)__builtin_ia32_vfmaddcsh_maskz( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +#define _mm_mask3_fmadd_round_sch(A, B, C, U, R) \ + ((__m128h)__builtin_ia32_vfmaddcsh_round_mask3( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(C), \ + (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fcmul_sch(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcsh_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_undefined_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fcmul_sch(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcsh_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fcmul_sch(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcsh_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fcmul_round_sch(A, B, R) \ + ((__m128h)__builtin_ia32_vfcmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), \ + (__v4sf)(__m128h)_mm_undefined_ph(), (__mmask8)-1, (int)(R))) + +#define _mm_mask_fcmul_round_sch(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfcmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fcmul_round_sch(U, A, B, R) \ + ((__m128h)__builtin_ia32_vfcmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), \ + (__v4sf)(__m128h)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmul_sch(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcsh_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_undefined_ph(), (__mmask8)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmul_sch(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcsh_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__W, (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmul_sch(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcsh_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_setzero_ph(), (__mmask8)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm_fmul_round_sch(A, B, R) \ + ((__m128h)__builtin_ia32_vfmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), \ + (__v4sf)(__m128h)_mm_undefined_ph(), (__mmask8)-1, (int)(R))) + +#define _mm_mask_fmul_round_sch(W, U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), (__v4sf)(__m128h)(W), \ + (__mmask8)(U), (int)(R))) + +#define _mm_maskz_fmul_round_sch(U, A, B, R) \ + ((__m128h)__builtin_ia32_vfmulcsh_mask( \ + (__v4sf)(__m128h)(A), (__v4sf)(__m128h)(B), \ + (__v4sf)(__m128h)_mm_setzero_ph(), (__mmask8)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fcmul_pch(__m512h __A, + __m512h __B) { + return (__m512h)__builtin_ia32_vfcmulcph512_mask( + (__v16sf)__A, (__v16sf)__B, (__v16sf)_mm512_undefined_ph(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fcmul_pch(__m512h __W, __mmask16 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_vfcmulcph512_mask((__v16sf)__A, (__v16sf)__B, + (__v16sf)__W, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fcmul_pch(__mmask16 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_vfcmulcph512_mask( + (__v16sf)__A, (__v16sf)__B, (__v16sf)_mm512_setzero_ph(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fcmul_round_pch(A, B, R) \ + ((__m512h)__builtin_ia32_vfcmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), \ + (__v16sf)(__m512h)_mm512_undefined_ph(), (__mmask16)-1, (int)(R))) + +#define _mm512_mask_fcmul_round_pch(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_vfcmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_fcmul_round_pch(U, A, B, R) \ + ((__m512h)__builtin_ia32_vfcmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), \ + (__v16sf)(__m512h)_mm512_setzero_ph(), (__mmask16)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fmul_pch(__m512h __A, + __m512h __B) { + return (__m512h)__builtin_ia32_vfmulcph512_mask( + (__v16sf)__A, (__v16sf)__B, (__v16sf)_mm512_undefined_ph(), (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmul_pch(__m512h __W, __mmask16 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_vfmulcph512_mask((__v16sf)__A, (__v16sf)__B, + (__v16sf)__W, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmul_pch(__mmask16 __U, __m512h __A, __m512h __B) { + return (__m512h)__builtin_ia32_vfmulcph512_mask( + (__v16sf)__A, (__v16sf)__B, (__v16sf)_mm512_setzero_ph(), (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fmul_round_pch(A, B, R) \ + ((__m512h)__builtin_ia32_vfmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), \ + (__v16sf)(__m512h)_mm512_undefined_ph(), (__mmask16)-1, (int)(R))) + +#define _mm512_mask_fmul_round_pch(W, U, A, B, R) \ + ((__m512h)__builtin_ia32_vfmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(W), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_fmul_round_pch(U, A, B, R) \ + ((__m512h)__builtin_ia32_vfmulcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), \ + (__v16sf)(__m512h)_mm512_setzero_ph(), (__mmask16)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fcmadd_pch(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfcmaddcph512_mask3( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fcmadd_pch(__m512h __A, __mmask16 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfcmaddcph512_mask( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fcmadd_pch(__m512h __A, __m512h __B, __m512h __C, __mmask16 __U) { + return (__m512h)__builtin_ia32_vfcmaddcph512_mask3( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fcmadd_pch(__mmask16 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfcmaddcph512_maskz( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fcmadd_round_pch(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfcmaddcph512_mask3( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)-1, (int)(R))) + +#define _mm512_mask_fcmadd_round_pch(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfcmaddcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_mask3_fcmadd_round_pch(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfcmaddcph512_mask3( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_fcmadd_round_pch(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfcmaddcph512_maskz( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 _mm512_fmadd_pch(__m512h __A, + __m512h __B, + __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddcph512_mask3((__v16sf)__A, (__v16sf)__B, + (__v16sf)__C, (__mmask16)-1, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_fmadd_pch(__m512h __A, __mmask16 __U, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddcph512_mask((__v16sf)__A, (__v16sf)__B, + (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask3_fmadd_pch(__m512h __A, __m512h __B, __m512h __C, __mmask16 __U) { + return (__m512h)__builtin_ia32_vfmaddcph512_mask3( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_maskz_fmadd_pch(__mmask16 __U, __m512h __A, __m512h __B, __m512h __C) { + return (__m512h)__builtin_ia32_vfmaddcph512_maskz( + (__v16sf)__A, (__v16sf)__B, (__v16sf)__C, (__mmask16)__U, + _MM_FROUND_CUR_DIRECTION); +} + +#define _mm512_fmadd_round_pch(A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddcph512_mask3( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)-1, (int)(R))) + +#define _mm512_mask_fmadd_round_pch(A, U, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddcph512_mask( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_mask3_fmadd_round_pch(A, B, C, U, R) \ + ((__m512h)__builtin_ia32_vfmaddcph512_mask3( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +#define _mm512_maskz_fmadd_round_pch(U, A, B, C, R) \ + ((__m512h)__builtin_ia32_vfmaddcph512_maskz( \ + (__v16sf)(__m512h)(A), (__v16sf)(__m512h)(B), (__v16sf)(__m512h)(C), \ + (__mmask16)(U), (int)(R))) + +static __inline__ _Float16 __DEFAULT_FN_ATTRS512 +_mm512_reduce_add_ph(__m512h __W) { + return __builtin_ia32_reduce_fadd_ph512(-0.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS512 +_mm512_reduce_mul_ph(__m512h __W) { + return __builtin_ia32_reduce_fmul_ph512(1.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS512 +_mm512_reduce_max_ph(__m512h __V) { + return __builtin_ia32_reduce_fmax_ph512(__V); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS512 +_mm512_reduce_min_ph(__m512h __V) { + return __builtin_ia32_reduce_fmin_ph512(__V); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_mask_blend_ph(__mmask32 __U, __m512h __A, __m512h __W) { + return (__m512h)__builtin_ia32_selectph_512((__mmask32)__U, (__v32hf)__W, + (__v32hf)__A); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_permutex2var_ph(__m512h __A, __m512i __I, __m512h __B) { + return (__m512h)__builtin_ia32_vpermi2varhi512((__v32hi)__A, (__v32hi)__I, + (__v32hi)__B); +} + +static __inline__ __m512h __DEFAULT_FN_ATTRS512 +_mm512_permutexvar_ph(__m512i __A, __m512h __B) { + return (__m512h)__builtin_ia32_permvarhi512((__v32hi)__B, (__v32hi)__A); +} + +// intrinsics below are alias for f*mul_*ch +#define _mm512_mul_pch(A, B) _mm512_fmul_pch(A, B) +#define _mm512_mask_mul_pch(W, U, A, B) _mm512_mask_fmul_pch(W, U, A, B) +#define _mm512_maskz_mul_pch(U, A, B) _mm512_maskz_fmul_pch(U, A, B) +#define _mm512_mul_round_pch(A, B, R) _mm512_fmul_round_pch(A, B, R) +#define _mm512_mask_mul_round_pch(W, U, A, B, R) \ + _mm512_mask_fmul_round_pch(W, U, A, B, R) +#define _mm512_maskz_mul_round_pch(U, A, B, R) \ + _mm512_maskz_fmul_round_pch(U, A, B, R) + +#define _mm512_cmul_pch(A, B) _mm512_fcmul_pch(A, B) +#define _mm512_mask_cmul_pch(W, U, A, B) _mm512_mask_fcmul_pch(W, U, A, B) +#define _mm512_maskz_cmul_pch(U, A, B) _mm512_maskz_fcmul_pch(U, A, B) +#define _mm512_cmul_round_pch(A, B, R) _mm512_fcmul_round_pch(A, B, R) +#define _mm512_mask_cmul_round_pch(W, U, A, B, R) \ + _mm512_mask_fcmul_round_pch(W, U, A, B, R) +#define _mm512_maskz_cmul_round_pch(U, A, B, R) \ + _mm512_maskz_fcmul_round_pch(U, A, B, R) + +#define _mm_mul_sch(A, B) _mm_fmul_sch(A, B) +#define _mm_mask_mul_sch(W, U, A, B) _mm_mask_fmul_sch(W, U, A, B) +#define _mm_maskz_mul_sch(U, A, B) _mm_maskz_fmul_sch(U, A, B) +#define _mm_mul_round_sch(A, B, R) _mm_fmul_round_sch(A, B, R) +#define _mm_mask_mul_round_sch(W, U, A, B, R) \ + _mm_mask_fmul_round_sch(W, U, A, B, R) +#define _mm_maskz_mul_round_sch(U, A, B, R) _mm_maskz_fmul_round_sch(U, A, B, R) + +#define _mm_cmul_sch(A, B) _mm_fcmul_sch(A, B) +#define _mm_mask_cmul_sch(W, U, A, B) _mm_mask_fcmul_sch(W, U, A, B) +#define _mm_maskz_cmul_sch(U, A, B) _mm_maskz_fcmul_sch(U, A, B) +#define _mm_cmul_round_sch(A, B, R) _mm_fcmul_round_sch(A, B, R) +#define _mm_mask_cmul_round_sch(W, U, A, B, R) \ + _mm_mask_fcmul_round_sch(W, U, A, B, R) +#define _mm_maskz_cmul_round_sch(U, A, B, R) \ + _mm_maskz_fcmul_round_sch(U, A, B, R) + +#undef __DEFAULT_FN_ATTRS128 +#undef __DEFAULT_FN_ATTRS256 +#undef __DEFAULT_FN_ATTRS512 + +#endif diff --git a/clang/lib/Headers/avx512vbmi2intrin.h b/clang/lib/Headers/avx512vbmi2intrin.h index a23144616ce..17fa77722c6 100644 --- a/clang/lib/Headers/avx512vbmi2intrin.h +++ b/clang/lib/Headers/avx512vbmi2intrin.h @@ -129,88 +129,88 @@ _mm512_maskz_expandloadu_epi8(__mmask64 __U, void const *__P) } #define _mm512_shldi_epi64(A, B, I) \ - (__m512i)__builtin_ia32_vpshldq512((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshldq512((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), (int)(I))) #define _mm512_mask_shldi_epi64(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shldi_epi64((A), (B), (I)), \ - (__v8di)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shldi_epi64((A), (B), (I)), \ + (__v8di)(__m512i)(S))) #define _mm512_maskz_shldi_epi64(U, A, B, I) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shldi_epi64((A), (B), (I)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shldi_epi64((A), (B), (I)), \ + (__v8di)_mm512_setzero_si512())) #define _mm512_shldi_epi32(A, B, I) \ - (__m512i)__builtin_ia32_vpshldd512((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshldd512((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), (int)(I))) #define _mm512_mask_shldi_epi32(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shldi_epi32((A), (B), (I)), \ - (__v16si)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shldi_epi32((A), (B), (I)), \ + (__v16si)(__m512i)(S))) #define _mm512_maskz_shldi_epi32(U, A, B, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shldi_epi32((A), (B), (I)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shldi_epi32((A), (B), (I)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_shldi_epi16(A, B, I) \ - (__m512i)__builtin_ia32_vpshldw512((__v32hi)(__m512i)(A), \ - (__v32hi)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshldw512((__v32hi)(__m512i)(A), \ + (__v32hi)(__m512i)(B), (int)(I))) #define _mm512_mask_shldi_epi16(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shldi_epi16((A), (B), (I)), \ - (__v32hi)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shldi_epi16((A), (B), (I)), \ + (__v32hi)(__m512i)(S))) #define _mm512_maskz_shldi_epi16(U, A, B, I) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shldi_epi16((A), (B), (I)), \ - (__v32hi)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shldi_epi16((A), (B), (I)), \ + (__v32hi)_mm512_setzero_si512())) #define _mm512_shrdi_epi64(A, B, I) \ - (__m512i)__builtin_ia32_vpshrdq512((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshrdq512((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), (int)(I))) #define _mm512_mask_shrdi_epi64(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shrdi_epi64((A), (B), (I)), \ - (__v8di)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shrdi_epi64((A), (B), (I)), \ + (__v8di)(__m512i)(S))) #define _mm512_maskz_shrdi_epi64(U, A, B, I) \ - (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ - (__v8di)_mm512_shrdi_epi64((A), (B), (I)), \ - (__v8di)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ + (__v8di)_mm512_shrdi_epi64((A), (B), (I)), \ + (__v8di)_mm512_setzero_si512())) #define _mm512_shrdi_epi32(A, B, I) \ - (__m512i)__builtin_ia32_vpshrdd512((__v16si)(__m512i)(A), \ - (__v16si)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshrdd512((__v16si)(__m512i)(A), \ + (__v16si)(__m512i)(B), (int)(I))) #define _mm512_mask_shrdi_epi32(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shrdi_epi32((A), (B), (I)), \ - (__v16si)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shrdi_epi32((A), (B), (I)), \ + (__v16si)(__m512i)(S))) #define _mm512_maskz_shrdi_epi32(U, A, B, I) \ - (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ - (__v16si)_mm512_shrdi_epi32((A), (B), (I)), \ - (__v16si)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ + (__v16si)_mm512_shrdi_epi32((A), (B), (I)), \ + (__v16si)_mm512_setzero_si512())) #define _mm512_shrdi_epi16(A, B, I) \ - (__m512i)__builtin_ia32_vpshrdw512((__v32hi)(__m512i)(A), \ - (__v32hi)(__m512i)(B), (int)(I)) + ((__m512i)__builtin_ia32_vpshrdw512((__v32hi)(__m512i)(A), \ + (__v32hi)(__m512i)(B), (int)(I))) #define _mm512_mask_shrdi_epi16(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shrdi_epi16((A), (B), (I)), \ - (__v32hi)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shrdi_epi16((A), (B), (I)), \ + (__v32hi)(__m512i)(S))) #define _mm512_maskz_shrdi_epi16(U, A, B, I) \ - (__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ - (__v32hi)_mm512_shrdi_epi16((A), (B), (I)), \ - (__v32hi)_mm512_setzero_si512()) + ((__m512i)__builtin_ia32_selectw_512((__mmask32)(U), \ + (__v32hi)_mm512_shrdi_epi16((A), (B), (I)), \ + (__v32hi)_mm512_setzero_si512())) static __inline__ __m512i __DEFAULT_FN_ATTRS _mm512_shldv_epi64(__m512i __A, __m512i __B, __m512i __C) diff --git a/clang/lib/Headers/avx512vlbf16intrin.h b/clang/lib/Headers/avx512vlbf16intrin.h index 1b1a744bcdb..6a5a86071f0 100644 --- a/clang/lib/Headers/avx512vlbf16intrin.h +++ b/clang/lib/Headers/avx512vlbf16intrin.h @@ -420,18 +420,46 @@ static __inline__ __bfloat16 __DEFAULT_FN_ATTRS128 _mm_cvtness_sbh(float __A) { return __R[0]; } +/// Convert Packed BF16 Data to Packed float Data. +/// +/// \headerfile +/// +/// \param __A +/// A 128-bit vector of [4 x bfloat]. +/// \returns A 128-bit vector of [4 x float] come from conversion of __A +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_cvtpbh_ps(__m128bh __A) { + return _mm_castsi128_ps( + (__m128i)_mm_slli_epi32((__m128i)_mm_cvtepi16_epi32((__m128i)__A), 16)); +} + /// Convert Packed BF16 Data to Packed float Data. /// /// \headerfile /// /// \param __A /// A 128-bit vector of [8 x bfloat]. -/// \returns A 256-bit vector of [8 x float] come from convertion of __A +/// \returns A 256-bit vector of [8 x float] come from conversion of __A static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_cvtpbh_ps(__m128bh __A) { return _mm256_castsi256_ps((__m256i)_mm256_slli_epi32( (__m256i)_mm256_cvtepi16_epi32((__m128i)__A), 16)); } +/// Convert Packed BF16 Data to Packed float Data using zeroing mask. +/// +/// \headerfile +/// +/// \param __U +/// A 4-bit mask. Elements are zeroed out when the corresponding mask +/// bit is not set. +/// \param __A +/// A 128-bit vector of [4 x bfloat]. +/// \returns A 128-bit vector of [4 x float] come from conversion of __A +static __inline__ __m128 __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtpbh_ps(__mmask8 __U, __m128bh __A) { + return _mm_castsi128_ps((__m128i)_mm_slli_epi32( + (__m128i)_mm_maskz_cvtepi16_epi32((__mmask8)__U, (__m128i)__A), 16)); +} + /// Convert Packed BF16 Data to Packed float Data using zeroing mask. /// /// \headerfile @@ -441,13 +469,33 @@ static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_cvtpbh_ps(__m128bh __A) { /// bit is not set. /// \param __A /// A 128-bit vector of [8 x bfloat]. -/// \returns A 256-bit vector of [8 x float] come from convertion of __A +/// \returns A 256-bit vector of [8 x float] come from conversion of __A static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_maskz_cvtpbh_ps(__mmask8 __U, __m128bh __A) { return _mm256_castsi256_ps((__m256i)_mm256_slli_epi32( (__m256i)_mm256_maskz_cvtepi16_epi32((__mmask8)__U, (__m128i)__A), 16)); } +/// Convert Packed BF16 Data to Packed float Data using merging mask. +/// +/// \headerfile +/// +/// \param __S +/// A 128-bit vector of [4 x float]. Elements are copied from __S when +/// the corresponding mask bit is not set. +/// \param __U +/// A 4-bit mask. Elements are zeroed out when the corresponding mask +/// bit is not set. +/// \param __A +/// A 128-bit vector of [4 x bfloat]. +/// \returns A 128-bit vector of [4 x float] come from conversion of __A +static __inline__ __m128 __DEFAULT_FN_ATTRS128 +_mm_mask_cvtpbh_ps(__m128 __S, __mmask8 __U, __m128bh __A) { + return _mm_castsi128_ps((__m128i)_mm_mask_slli_epi32( + (__m128i)__S, (__mmask8)__U, (__m128i)_mm_cvtepi16_epi32((__m128i)__A), + 16)); +} + /// Convert Packed BF16 Data to Packed float Data using merging mask. /// /// \headerfile @@ -460,7 +508,7 @@ _mm256_maskz_cvtpbh_ps(__mmask8 __U, __m128bh __A) { /// bit is not set. /// \param __A /// A 128-bit vector of [8 x bfloat]. -/// \returns A 256-bit vector of [8 x float] come from convertion of __A +/// \returns A 256-bit vector of [8 x float] come from conversion of __A static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_mask_cvtpbh_ps(__m256 __S, __mmask8 __U, __m128bh __A) { return _mm256_castsi256_ps((__m256i)_mm256_mask_slli_epi32( diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h index 6ed10ed9803..7873516053e 100644 --- a/clang/lib/Headers/avx512vlbwintrin.h +++ b/clang/lib/Headers/avx512vlbwintrin.h @@ -21,84 +21,84 @@ /* Integer compare */ #define _mm_cmp_epi8_mask(a, b, p) \ - (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm_mask_cmp_epi8_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_cmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm_cmp_epu8_mask(a, b, p) \ - (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm_mask_cmp_epu8_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_ucmpb128_mask((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm256_cmp_epi8_mask(a, b, p) \ - (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)-1) + ((__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)-1)) #define _mm256_mask_cmp_epi8_mask(m, a, b, p) \ - (__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)(m)) + ((__mmask32)__builtin_ia32_cmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)(m))) #define _mm256_cmp_epu8_mask(a, b, p) \ - (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)-1) + ((__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)-1)) #define _mm256_mask_cmp_epu8_mask(m, a, b, p) \ - (__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ - (__v32qi)(__m256i)(b), (int)(p), \ - (__mmask32)(m)) + ((__mmask32)__builtin_ia32_ucmpb256_mask((__v32qi)(__m256i)(a), \ + (__v32qi)(__m256i)(b), (int)(p), \ + (__mmask32)(m))) #define _mm_cmp_epi16_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epi16_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_epu16_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epu16_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ - (__v8hi)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpw128_mask((__v8hi)(__m128i)(a), \ + (__v8hi)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_epi16_mask(a, b, p) \ - (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm256_mask_cmp_epi16_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_cmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm256_cmp_epu16_mask(a, b, p) \ - (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)-1) + ((__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)-1)) #define _mm256_mask_cmp_epu16_mask(m, a, b, p) \ - (__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ - (__v16hi)(__m256i)(b), (int)(p), \ - (__mmask16)(m)) + ((__mmask16)__builtin_ia32_ucmpw256_mask((__v16hi)(__m256i)(a), \ + (__v16hi)(__m256i)(b), (int)(p), \ + (__mmask16)(m))) #define _mm_cmpeq_epi8_mask(A, B) \ _mm_cmp_epi8_mask((A), (B), _MM_CMPINT_EQ) @@ -1821,46 +1821,46 @@ _mm256_maskz_cvtepu8_epi16 (__mmask16 __U, __m128i __A) #define _mm_mask_shufflehi_epi16(W, U, A, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shufflehi_epi16((A), (imm)), \ - (__v8hi)(__m128i)(W)) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shufflehi_epi16((A), (imm)), \ + (__v8hi)(__m128i)(W))) #define _mm_maskz_shufflehi_epi16(U, A, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shufflehi_epi16((A), (imm)), \ - (__v8hi)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shufflehi_epi16((A), (imm)), \ + (__v8hi)_mm_setzero_si128())) #define _mm256_mask_shufflehi_epi16(W, U, A, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shufflehi_epi16((A), (imm)), \ - (__v16hi)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shufflehi_epi16((A), (imm)), \ + (__v16hi)(__m256i)(W))) #define _mm256_maskz_shufflehi_epi16(U, A, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shufflehi_epi16((A), (imm)), \ - (__v16hi)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shufflehi_epi16((A), (imm)), \ + (__v16hi)_mm256_setzero_si256())) #define _mm_mask_shufflelo_epi16(W, U, A, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shufflelo_epi16((A), (imm)), \ - (__v8hi)(__m128i)(W)) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shufflelo_epi16((A), (imm)), \ + (__v8hi)(__m128i)(W))) #define _mm_maskz_shufflelo_epi16(U, A, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shufflelo_epi16((A), (imm)), \ - (__v8hi)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shufflelo_epi16((A), (imm)), \ + (__v8hi)_mm_setzero_si128())) #define _mm256_mask_shufflelo_epi16(W, U, A, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shufflelo_epi16((A), \ - (imm)), \ - (__v16hi)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shufflelo_epi16((A), \ + (imm)), \ + (__v16hi)(__m256i)(W))) #define _mm256_maskz_shufflelo_epi16(U, A, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shufflelo_epi16((A), \ - (imm)), \ - (__v16hi)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shufflelo_epi16((A), \ + (imm)), \ + (__v16hi)_mm256_setzero_si256())) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_sllv_epi16(__m256i __A, __m256i __B) @@ -2756,52 +2756,52 @@ _mm256_mask_permutexvar_epi16 (__m256i __W, __mmask16 __M, __m256i __A, } #define _mm_mask_alignr_epi8(W, U, A, B, N) \ - (__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ + ((__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ (__v16qi)_mm_alignr_epi8((A), (B), (int)(N)), \ - (__v16qi)(__m128i)(W)) + (__v16qi)(__m128i)(W))) #define _mm_maskz_alignr_epi8(U, A, B, N) \ - (__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ + ((__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ (__v16qi)_mm_alignr_epi8((A), (B), (int)(N)), \ - (__v16qi)_mm_setzero_si128()) + (__v16qi)_mm_setzero_si128())) #define _mm256_mask_alignr_epi8(W, U, A, B, N) \ - (__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ + ((__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ (__v32qi)_mm256_alignr_epi8((A), (B), (int)(N)), \ - (__v32qi)(__m256i)(W)) + (__v32qi)(__m256i)(W))) #define _mm256_maskz_alignr_epi8(U, A, B, N) \ - (__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ + ((__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ (__v32qi)_mm256_alignr_epi8((A), (B), (int)(N)), \ - (__v32qi)_mm256_setzero_si256()) + (__v32qi)_mm256_setzero_si256())) #define _mm_dbsad_epu8(A, B, imm) \ - (__m128i)__builtin_ia32_dbpsadbw128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(imm)) + ((__m128i)__builtin_ia32_dbpsadbw128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(imm))) #define _mm_mask_dbsad_epu8(W, U, A, B, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ (__v8hi)_mm_dbsad_epu8((A), (B), (imm)), \ - (__v8hi)(__m128i)(W)) + (__v8hi)(__m128i)(W))) #define _mm_maskz_dbsad_epu8(U, A, B, imm) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ (__v8hi)_mm_dbsad_epu8((A), (B), (imm)), \ - (__v8hi)_mm_setzero_si128()) + (__v8hi)_mm_setzero_si128())) #define _mm256_dbsad_epu8(A, B, imm) \ - (__m256i)__builtin_ia32_dbpsadbw256((__v32qi)(__m256i)(A), \ - (__v32qi)(__m256i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_dbpsadbw256((__v32qi)(__m256i)(A), \ + (__v32qi)(__m256i)(B), (int)(imm))) #define _mm256_mask_dbsad_epu8(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ (__v16hi)_mm256_dbsad_epu8((A), (B), (imm)), \ - (__v16hi)(__m256i)(W)) + (__v16hi)(__m256i)(W))) #define _mm256_maskz_dbsad_epu8(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ (__v16hi)_mm256_dbsad_epu8((A), (B), (imm)), \ - (__v16hi)_mm256_setzero_si256()) + (__v16hi)_mm256_setzero_si256())) #undef __DEFAULT_FN_ATTRS128 #undef __DEFAULT_FN_ATTRS256 diff --git a/clang/lib/Headers/avx512vldqintrin.h b/clang/lib/Headers/avx512vldqintrin.h index 95ba574ea82..713e1a18a1b 100644 --- a/clang/lib/Headers/avx512vldqintrin.h +++ b/clang/lib/Headers/avx512vldqintrin.h @@ -773,134 +773,134 @@ _mm256_maskz_cvtepu64_ps (__mmask8 __U, __m256i __A) { } #define _mm_range_pd(A, B, C) \ - (__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), (int)(C), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), (int)(C), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1)) #define _mm_mask_range_pd(W, U, A, B, C) \ - (__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), (int)(C), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), (int)(C), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm_maskz_range_pd(U, A, B, C) \ - (__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), (int)(C), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_rangepd128_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), (int)(C), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm256_range_pd(A, B, C) \ - (__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), (int)(C), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), (int)(C), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)-1)) #define _mm256_mask_range_pd(W, U, A, B, C) \ - (__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), (int)(C), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), (int)(C), \ + (__v4df)(__m256d)(W), \ + (__mmask8)(U))) #define _mm256_maskz_range_pd(U, A, B, C) \ - (__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), (int)(C), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_rangepd256_mask((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), (int)(C), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)(U))) #define _mm_range_ps(A, B, C) \ - (__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), (int)(C), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), (int)(C), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1)) #define _mm_mask_range_ps(W, U, A, B, C) \ - (__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), (int)(C), \ - (__v4sf)(__m128)(W), (__mmask8)(U)) + ((__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), (int)(C), \ + (__v4sf)(__m128)(W), (__mmask8)(U))) #define _mm_maskz_range_ps(U, A, B, C) \ - (__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), (int)(C), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_rangeps128_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), (int)(C), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) #define _mm256_range_ps(A, B, C) \ - (__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(C), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1) + ((__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), (int)(C), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1)) #define _mm256_mask_range_ps(W, U, A, B, C) \ - (__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(C), \ - (__v8sf)(__m256)(W), (__mmask8)(U)) + ((__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), (int)(C), \ + (__v8sf)(__m256)(W), (__mmask8)(U))) #define _mm256_maskz_range_ps(U, A, B, C) \ - (__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(C), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_rangeps256_mask((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), (int)(C), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U))) #define _mm_reduce_pd(A, B) \ - (__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1)) #define _mm_mask_reduce_pd(W, U, A, B) \ - (__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm_maskz_reduce_pd(U, A, B) \ - (__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_reducepd128_mask((__v2df)(__m128d)(A), (int)(B), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm256_reduce_pd(A, B) \ - (__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)-1)) #define _mm256_mask_reduce_pd(W, U, A, B) \ - (__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ + (__v4df)(__m256d)(W), \ + (__mmask8)(U))) #define _mm256_maskz_reduce_pd(U, A, B) \ - (__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_reducepd256_mask((__v4df)(__m256d)(A), (int)(B), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)(U))) #define _mm_reduce_ps(A, B) \ - (__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1)) #define _mm_mask_reduce_ps(W, U, A, B) \ - (__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U))) #define _mm_maskz_reduce_ps(U, A, B) \ - (__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_reduceps128_mask((__v4sf)(__m128)(A), (int)(B), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) #define _mm256_reduce_ps(A, B) \ - (__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1) + ((__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1)) #define _mm256_mask_reduce_ps(W, U, A, B) \ - (__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ - (__v8sf)(__m256)(W), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ + (__v8sf)(__m256)(W), \ + (__mmask8)(U))) #define _mm256_maskz_reduce_ps(U, A, B) \ - (__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_reduceps256_mask((__v8sf)(__m256)(A), (int)(B), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U))) static __inline__ __mmask8 __DEFAULT_FN_ATTRS128 _mm_movepi32_mask (__m128i __A) @@ -1066,100 +1066,100 @@ _mm256_maskz_broadcast_i64x2 (__mmask8 __M, __m128i __A) } #define _mm256_extractf64x2_pd(A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v2df)_mm_undefined_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v2df)_mm_undefined_pd(), \ + (__mmask8)-1)) #define _mm256_mask_extractf64x2_pd(W, U, A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm256_maskz_extractf64x2_pd(U, A, imm) \ - (__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_extractf64x2_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm256_extracti64x2_epi64(A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ + ((__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ (int)(imm), \ (__v2di)_mm_undefined_si128(), \ - (__mmask8)-1) + (__mmask8)-1)) #define _mm256_mask_extracti64x2_epi64(W, U, A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ - (int)(imm), \ - (__v2di)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ + (int)(imm), \ + (__v2di)(__m128i)(W), \ + (__mmask8)(U))) #define _mm256_maskz_extracti64x2_epi64(U, A, imm) \ - (__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ - (int)(imm), \ - (__v2di)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti64x2_256_mask((__v4di)(__m256i)(A), \ + (int)(imm), \ + (__v2di)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm256_insertf64x2(A, B, imm) \ - (__m256d)__builtin_ia32_insertf64x2_256((__v4df)(__m256d)(A), \ - (__v2df)(__m128d)(B), (int)(imm)) + ((__m256d)__builtin_ia32_insertf64x2_256((__v4df)(__m256d)(A), \ + (__v2df)(__m128d)(B), (int)(imm))) #define _mm256_mask_insertf64x2(W, U, A, B, imm) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ (__v4df)_mm256_insertf64x2((A), (B), (imm)), \ - (__v4df)(__m256d)(W)) + (__v4df)(__m256d)(W))) #define _mm256_maskz_insertf64x2(U, A, B, imm) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ (__v4df)_mm256_insertf64x2((A), (B), (imm)), \ - (__v4df)_mm256_setzero_pd()) + (__v4df)_mm256_setzero_pd())) #define _mm256_inserti64x2(A, B, imm) \ - (__m256i)__builtin_ia32_inserti64x2_256((__v4di)(__m256i)(A), \ - (__v2di)(__m128i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_inserti64x2_256((__v4di)(__m256i)(A), \ + (__v2di)(__m128i)(B), (int)(imm))) #define _mm256_mask_inserti64x2(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_inserti64x2((A), (B), (imm)), \ - (__v4di)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_inserti64x2((A), (B), (imm)), \ + (__v4di)(__m256i)(W))) #define _mm256_maskz_inserti64x2(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_inserti64x2((A), (B), (imm)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_inserti64x2((A), (B), (imm)), \ + (__v4di)_mm256_setzero_si256())) #define _mm_mask_fpclass_pd_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd128_mask((__v2df)(__m128d)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclasspd128_mask((__v2df)(__m128d)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm_fpclass_pd_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd128_mask((__v2df)(__m128d)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclasspd128_mask((__v2df)(__m128d)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm256_mask_fpclass_pd_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd256_mask((__v4df)(__m256d)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclasspd256_mask((__v4df)(__m256d)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm256_fpclass_pd_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclasspd256_mask((__v4df)(__m256d)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclasspd256_mask((__v4df)(__m256d)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm_mask_fpclass_ps_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclassps128_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclassps128_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm_fpclass_ps_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclassps128_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclassps128_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__mmask8)-1)) #define _mm256_mask_fpclass_ps_mask(U, A, imm) \ - (__mmask8)__builtin_ia32_fpclassps256_mask((__v8sf)(__m256)(A), (int)(imm), \ - (__mmask8)(U)) + ((__mmask8)__builtin_ia32_fpclassps256_mask((__v8sf)(__m256)(A), (int)(imm), \ + (__mmask8)(U))) #define _mm256_fpclass_ps_mask(A, imm) \ - (__mmask8)__builtin_ia32_fpclassps256_mask((__v8sf)(__m256)(A), (int)(imm), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_fpclassps256_mask((__v8sf)(__m256)(A), (int)(imm), \ + (__mmask8)-1)) #undef __DEFAULT_FN_ATTRS128 #undef __DEFAULT_FN_ATTRS256 diff --git a/clang/lib/Headers/avx512vlfp16intrin.h b/clang/lib/Headers/avx512vlfp16intrin.h new file mode 100644 index 00000000000..3d27853ad96 --- /dev/null +++ b/clang/lib/Headers/avx512vlfp16intrin.h @@ -0,0 +1,2068 @@ +/*===---------- avx512vlfp16intrin.h - AVX512-FP16 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 __IMMINTRIN_H +#error \ + "Never use directly; include instead." +#endif + +#ifndef __AVX512VLFP16INTRIN_H +#define __AVX512VLFP16INTRIN_H + +/* Define the default attributes for the functions in this file. */ +#define __DEFAULT_FN_ATTRS256 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("avx512fp16, avx512vl"), \ + __min_vector_width__(256))) +#define __DEFAULT_FN_ATTRS128 \ + __attribute__((__always_inline__, __nodebug__, \ + __target__("avx512fp16, avx512vl"), \ + __min_vector_width__(128))) + +static __inline__ _Float16 __DEFAULT_FN_ATTRS128 _mm_cvtsh_h(__m128h __a) { + return __a[0]; +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS256 _mm256_cvtsh_h(__m256h __a) { + return __a[0]; +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_set_sh(_Float16 __h) { + return __extension__(__m128h){__h, 0, 0, 0, 0, 0, 0, 0}; +} + +static __inline __m128h __DEFAULT_FN_ATTRS128 _mm_set1_ph(_Float16 __h) { + return (__m128h)(__v8hf){__h, __h, __h, __h, __h, __h, __h, __h}; +} + +static __inline __m256h __DEFAULT_FN_ATTRS256 _mm256_set1_ph(_Float16 __h) { + return (__m256h)(__v16hf){__h, __h, __h, __h, __h, __h, __h, __h, + __h, __h, __h, __h, __h, __h, __h, __h}; +} + +static __inline __m128h __DEFAULT_FN_ATTRS128 +_mm_set_ph(_Float16 __h1, _Float16 __h2, _Float16 __h3, _Float16 __h4, + _Float16 __h5, _Float16 __h6, _Float16 __h7, _Float16 __h8) { + return (__m128h)(__v8hf){__h8, __h7, __h6, __h5, __h4, __h3, __h2, __h1}; +} + +static __inline __m256h __DEFAULT_FN_ATTRS256 +_mm256_set1_pch(_Float16 _Complex h) { + return (__m256h)_mm256_set1_ps(__builtin_bit_cast(float, h)); +} + +static __inline __m128h __DEFAULT_FN_ATTRS128 +_mm_set1_pch(_Float16 _Complex h) { + return (__m128h)_mm_set1_ps(__builtin_bit_cast(float, h)); +} + +static __inline __m256h __DEFAULT_FN_ATTRS256 +_mm256_set_ph(_Float16 __h1, _Float16 __h2, _Float16 __h3, _Float16 __h4, + _Float16 __h5, _Float16 __h6, _Float16 __h7, _Float16 __h8, + _Float16 __h9, _Float16 __h10, _Float16 __h11, _Float16 __h12, + _Float16 __h13, _Float16 __h14, _Float16 __h15, _Float16 __h16) { + return (__m256h)(__v16hf){__h16, __h15, __h14, __h13, __h12, __h11, + __h10, __h9, __h8, __h7, __h6, __h5, + __h4, __h3, __h2, __h1}; +} + +#define _mm_setr_ph(h1, h2, h3, h4, h5, h6, h7, h8) \ + _mm_set_ph((h8), (h7), (h6), (h5), (h4), (h3), (h2), (h1)) + +#define _mm256_setr_ph(h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12, h13, \ + h14, h15, h16) \ + _mm256_set_ph((h16), (h15), (h14), (h13), (h12), (h11), (h10), (h9), (h8), \ + (h7), (h6), (h5), (h4), (h3), (h2), (h1)) + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_add_ph(__m256h __A, + __m256h __B) { + return (__m256h)((__v16hf)__A + (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_add_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_add_ph(__A, __B), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_add_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_add_ph(__A, __B), (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_add_ph(__m128h __A, + __m128h __B) { + return (__m128h)((__v8hf)__A + (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_add_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_add_ph(__A, __B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_add_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_add_ph(__A, __B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_sub_ph(__m256h __A, + __m256h __B) { + return (__m256h)((__v16hf)__A - (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_sub_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_sub_ph(__A, __B), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_sub_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_sub_ph(__A, __B), (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_sub_ph(__m128h __A, + __m128h __B) { + return (__m128h)((__v8hf)__A - (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_sub_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_sub_ph(__A, __B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_sub_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_sub_ph(__A, __B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_mul_ph(__m256h __A, + __m256h __B) { + return (__m256h)((__v16hf)__A * (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_mul_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_mul_ph(__A, __B), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_mul_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_mul_ph(__A, __B), (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mul_ph(__m128h __A, + __m128h __B) { + return (__m128h)((__v8hf)__A * (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_mul_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_mul_ph(__A, __B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_mul_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_mul_ph(__A, __B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_div_ph(__m256h __A, + __m256h __B) { + return (__m256h)((__v16hf)__A / (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_div_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_div_ph(__A, __B), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_div_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + __U, (__v16hf)_mm256_div_ph(__A, __B), (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_div_ph(__m128h __A, + __m128h __B) { + return (__m128h)((__v8hf)__A / (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_div_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_div_ph(__A, __B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_div_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128(__U, (__v8hf)_mm_div_ph(__A, __B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_min_ph(__m256h __A, + __m256h __B) { + return (__m256h)__builtin_ia32_minph256((__v16hf)__A, (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_min_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + (__v16hf)__builtin_ia32_minph256((__v16hf)__A, (__v16hf)__B), + (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_min_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + (__v16hf)__builtin_ia32_minph256((__v16hf)__A, (__v16hf)__B), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_min_ph(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_minph128((__v8hf)__A, (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_min_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)__builtin_ia32_minph128((__v8hf)__A, (__v8hf)__B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_min_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)__builtin_ia32_minph128((__v8hf)__A, (__v8hf)__B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_max_ph(__m256h __A, + __m256h __B) { + return (__m256h)__builtin_ia32_maxph256((__v16hf)__A, (__v16hf)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_max_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + (__v16hf)__builtin_ia32_maxph256((__v16hf)__A, (__v16hf)__B), + (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_max_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + (__v16hf)__builtin_ia32_maxph256((__v16hf)__A, (__v16hf)__B), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_max_ph(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_maxph128((__v8hf)__A, (__v8hf)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_max_ph(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)__builtin_ia32_maxph128((__v8hf)__A, (__v8hf)__B), + (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_max_ph(__mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)__builtin_ia32_maxph128((__v8hf)__A, (__v8hf)__B), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_abs_ph(__m256h __A) { + return (__m256h)_mm256_and_epi32(_mm256_set1_epi32(0x7FFF7FFF), (__m256i)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_abs_ph(__m128h __A) { + return (__m128h)_mm_and_epi32(_mm_set1_epi32(0x7FFF7FFF), (__m128i)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_conj_pch(__m256h __A) { + return (__m256h)_mm256_xor_ps((__m256)__A, _mm256_set1_ps(-0.0f)); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_conj_pch(__m256h __W, __mmask8 __U, __m256h __A) { + return (__m256h)__builtin_ia32_selectps_256( + (__mmask8)__U, (__v8sf)_mm256_conj_pch(__A), (__v8sf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_conj_pch(__mmask8 __U, __m256h __A) { + return (__m256h)__builtin_ia32_selectps_256( + (__mmask8)__U, (__v8sf)_mm256_conj_pch(__A), (__v8sf)_mm256_setzero_ps()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_conj_pch(__m128h __A) { + return (__m128h)_mm_xor_ps((__m128)__A, _mm_set1_ps(-0.0f)); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_conj_pch(__m128h __W, + __mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_selectps_128( + (__mmask8)__U, (__v4sf)_mm_conj_pch(__A), (__v4sf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_conj_pch(__mmask8 __U, __m128h __A) { + return (__m128h)__builtin_ia32_selectps_128( + (__mmask8)__U, (__v4sf)_mm_conj_pch(__A), (__v4sf)_mm_setzero_ps()); +} + +#define _mm256_cmp_ph_mask(a, b, p) \ + ((__mmask16)__builtin_ia32_cmpph256_mask( \ + (__v16hf)(__m256h)(a), (__v16hf)(__m256h)(b), (int)(p), (__mmask16)-1)) + +#define _mm256_mask_cmp_ph_mask(m, a, b, p) \ + ((__mmask16)__builtin_ia32_cmpph256_mask( \ + (__v16hf)(__m256h)(a), (__v16hf)(__m256h)(b), (int)(p), (__mmask16)(m))) + +#define _mm_cmp_ph_mask(a, b, p) \ + ((__mmask8)__builtin_ia32_cmpph128_mask( \ + (__v8hf)(__m128h)(a), (__v8hf)(__m128h)(b), (int)(p), (__mmask8)-1)) + +#define _mm_mask_cmp_ph_mask(m, a, b, p) \ + ((__mmask8)__builtin_ia32_cmpph128_mask( \ + (__v8hf)(__m128h)(a), (__v8hf)(__m128h)(b), (int)(p), (__mmask8)(m))) + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_rcp_ph(__m256h __A) { + return (__m256h)__builtin_ia32_rcpph256_mask( + (__v16hf)__A, (__v16hf)_mm256_undefined_ph(), (__mmask16)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_rcp_ph(__m256h __W, __mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_rcpph256_mask((__v16hf)__A, (__v16hf)__W, + (__mmask16)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_rcp_ph(__mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_rcpph256_mask( + (__v16hf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_rcp_ph(__m128h __A) { + return (__m128h)__builtin_ia32_rcpph128_mask( + (__v8hf)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_rcp_ph(__m128h __W, + __mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_rcpph128_mask((__v8hf)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_rcp_ph(__mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_rcpph128_mask( + (__v8hf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_rsqrt_ph(__m256h __A) { + return (__m256h)__builtin_ia32_rsqrtph256_mask( + (__v16hf)__A, (__v16hf)_mm256_undefined_ph(), (__mmask16)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_rsqrt_ph(__m256h __W, __mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_rsqrtph256_mask((__v16hf)__A, (__v16hf)__W, + (__mmask16)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_rsqrt_ph(__mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_rsqrtph256_mask( + (__v16hf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_rsqrt_ph(__m128h __A) { + return (__m128h)__builtin_ia32_rsqrtph128_mask( + (__v8hf)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_rsqrt_ph(__m128h __W, + __mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_rsqrtph128_mask((__v8hf)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_rsqrt_ph(__mmask8 __U, __m128h __A) { + return (__m128h)__builtin_ia32_rsqrtph128_mask( + (__v8hf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_getexp_ph(__m128h __A) { + return (__m128h)__builtin_ia32_getexpph128_mask( + (__v8hf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_getexp_ph(__m128h __W, __mmask8 __U, __m128h __A) { + return (__m128h)__builtin_ia32_getexpph128_mask((__v8hf)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_getexp_ph(__mmask8 __U, __m128h __A) { + return (__m128h)__builtin_ia32_getexpph128_mask( + (__v8hf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_getexp_ph(__m256h __A) { + return (__m256h)__builtin_ia32_getexpph256_mask( + (__v16hf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_getexp_ph(__m256h __W, __mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_getexpph256_mask((__v16hf)__A, (__v16hf)__W, + (__mmask16)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_getexp_ph(__mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_getexpph256_mask( + (__v16hf)__A, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U); +} + +#define _mm_getmant_ph(A, B, C) \ + ((__m128h)__builtin_ia32_getmantph128_mask( \ + (__v8hf)(__m128h)(A), (int)(((C) << 2) | (B)), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1)) + +#define _mm_mask_getmant_ph(W, U, A, B, C) \ + ((__m128h)__builtin_ia32_getmantph128_mask( \ + (__v8hf)(__m128h)(A), (int)(((C) << 2) | (B)), (__v8hf)(__m128h)(W), \ + (__mmask8)(U))) + +#define _mm_maskz_getmant_ph(U, A, B, C) \ + ((__m128h)__builtin_ia32_getmantph128_mask( \ + (__v8hf)(__m128h)(A), (int)(((C) << 2) | (B)), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U))) + +#define _mm256_getmant_ph(A, B, C) \ + ((__m256h)__builtin_ia32_getmantph256_mask( \ + (__v16hf)(__m256h)(A), (int)(((C) << 2) | (B)), \ + (__v16hf)_mm256_setzero_ph(), (__mmask16)-1)) + +#define _mm256_mask_getmant_ph(W, U, A, B, C) \ + ((__m256h)__builtin_ia32_getmantph256_mask( \ + (__v16hf)(__m256h)(A), (int)(((C) << 2) | (B)), (__v16hf)(__m256h)(W), \ + (__mmask16)(U))) + +#define _mm256_maskz_getmant_ph(U, A, B, C) \ + ((__m256h)__builtin_ia32_getmantph256_mask( \ + (__v16hf)(__m256h)(A), (int)(((C) << 2) | (B)), \ + (__v16hf)_mm256_setzero_ph(), (__mmask16)(U))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_scalef_ph(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_scalefph128_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_scalef_ph(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_scalefph128_mask((__v8hf)__A, (__v8hf)__B, + (__v8hf)__W, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_scalef_ph(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_scalefph128_mask( + (__v8hf)__A, (__v8hf)__B, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_scalef_ph(__m256h __A, + __m256h __B) { + return (__m256h)__builtin_ia32_scalefph256_mask( + (__v16hf)__A, (__v16hf)__B, (__v16hf)_mm256_setzero_ph(), (__mmask16)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_scalef_ph(__m256h __W, __mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_scalefph256_mask((__v16hf)__A, (__v16hf)__B, + (__v16hf)__W, (__mmask16)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_scalef_ph(__mmask16 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_scalefph256_mask( + (__v16hf)__A, (__v16hf)__B, (__v16hf)_mm256_setzero_ph(), (__mmask16)__U); +} + +#define _mm_roundscale_ph(A, imm) \ + ((__m128h)__builtin_ia32_rndscaleph_128_mask( \ + (__v8hf)(__m128h)(A), (int)(imm), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1)) + +#define _mm_mask_roundscale_ph(W, U, A, imm) \ + ((__m128h)__builtin_ia32_rndscaleph_128_mask( \ + (__v8hf)(__m128h)(A), (int)(imm), (__v8hf)(__m128h)(W), (__mmask8)(U))) + +#define _mm_maskz_roundscale_ph(U, A, imm) \ + ((__m128h)__builtin_ia32_rndscaleph_128_mask( \ + (__v8hf)(__m128h)(A), (int)(imm), (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U))) + +#define _mm256_roundscale_ph(A, imm) \ + ((__m256h)__builtin_ia32_rndscaleph_256_mask( \ + (__v16hf)(__m256h)(A), (int)(imm), (__v16hf)_mm256_setzero_ph(), \ + (__mmask16)-1)) + +#define _mm256_mask_roundscale_ph(W, U, A, imm) \ + ((__m256h)__builtin_ia32_rndscaleph_256_mask( \ + (__v16hf)(__m256h)(A), (int)(imm), (__v16hf)(__m256h)(W), \ + (__mmask16)(U))) + +#define _mm256_maskz_roundscale_ph(U, A, imm) \ + ((__m256h)__builtin_ia32_rndscaleph_256_mask( \ + (__v16hf)(__m256h)(A), (int)(imm), (__v16hf)_mm256_setzero_ph(), \ + (__mmask16)(U))) + +#define _mm_reduce_ph(A, imm) \ + ((__m128h)__builtin_ia32_reduceph128_mask((__v8hf)(__m128h)(A), (int)(imm), \ + (__v8hf)_mm_setzero_ph(), \ + (__mmask8)-1)) + +#define _mm_mask_reduce_ph(W, U, A, imm) \ + ((__m128h)__builtin_ia32_reduceph128_mask( \ + (__v8hf)(__m128h)(A), (int)(imm), (__v8hf)(__m128h)(W), (__mmask8)(U))) + +#define _mm_maskz_reduce_ph(U, A, imm) \ + ((__m128h)__builtin_ia32_reduceph128_mask((__v8hf)(__m128h)(A), (int)(imm), \ + (__v8hf)_mm_setzero_ph(), \ + (__mmask8)(U))) + +#define _mm256_reduce_ph(A, imm) \ + ((__m256h)__builtin_ia32_reduceph256_mask((__v16hf)(__m256h)(A), (int)(imm), \ + (__v16hf)_mm256_setzero_ph(), \ + (__mmask16)-1)) + +#define _mm256_mask_reduce_ph(W, U, A, imm) \ + ((__m256h)__builtin_ia32_reduceph256_mask((__v16hf)(__m256h)(A), (int)(imm), \ + (__v16hf)(__m256h)(W), \ + (__mmask16)(U))) + +#define _mm256_maskz_reduce_ph(U, A, imm) \ + ((__m256h)__builtin_ia32_reduceph256_mask((__v16hf)(__m256h)(A), (int)(imm), \ + (__v16hf)_mm256_setzero_ph(), \ + (__mmask16)(U))) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_sqrt_ph(__m128h __a) { + return __builtin_ia32_sqrtph((__v8hf)__a); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_sqrt_ph(__m128h __W, + __mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_sqrt_ph(__A), (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_maskz_sqrt_ph(__mmask8 __U, + __m128h __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_sqrt_ph(__A), (__v8hf)_mm_setzero_ph()); +} + +static __inline __m256h __DEFAULT_FN_ATTRS256 _mm256_sqrt_ph(__m256h __a) { + return (__m256h)__builtin_ia32_sqrtph256((__v16hf)__a); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_sqrt_ph(__m256h __W, __mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, (__v16hf)_mm256_sqrt_ph(__A), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_sqrt_ph(__mmask16 __U, __m256h __A) { + return (__m256h)__builtin_ia32_selectph_256((__mmask16)__U, + (__v16hf)_mm256_sqrt_ph(__A), + (__v16hf)_mm256_setzero_ph()); +} + +#define _mm_mask_fpclass_ph_mask(U, A, imm) \ + ((__mmask8)__builtin_ia32_fpclassph128_mask((__v8hf)(__m128h)(A), \ + (int)(imm), (__mmask8)(U))) + +#define _mm_fpclass_ph_mask(A, imm) \ + ((__mmask8)__builtin_ia32_fpclassph128_mask((__v8hf)(__m128h)(A), \ + (int)(imm), (__mmask8)-1)) + +#define _mm256_mask_fpclass_ph_mask(U, A, imm) \ + ((__mmask16)__builtin_ia32_fpclassph256_mask((__v16hf)(__m256h)(A), \ + (int)(imm), (__mmask16)(U))) + +#define _mm256_fpclass_ph_mask(A, imm) \ + ((__mmask16)__builtin_ia32_fpclassph256_mask((__v16hf)(__m256h)(A), \ + (int)(imm), (__mmask16)-1)) + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtpd_ph(__m128d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph128_mask( + (__v2df)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_cvtpd_ph(__m128h __W, + __mmask8 __U, + __m128d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph128_mask((__v2df)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtpd_ph(__mmask8 __U, __m128d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph128_mask( + (__v2df)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 _mm256_cvtpd_ph(__m256d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph256_mask( + (__v4df)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtpd_ph(__m128h __W, __mmask8 __U, __m256d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph256_mask((__v4df)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtpd_ph(__mmask8 __U, __m256d __A) { + return (__m128h)__builtin_ia32_vcvtpd2ph256_mask( + (__v4df)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_cvtph_pd(__m128h __A) { + return (__m128d)__builtin_ia32_vcvtph2pd128_mask( + (__v8hf)__A, (__v2df)_mm_undefined_pd(), (__mmask8)-1); +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_cvtph_pd(__m128d __W, + __mmask8 __U, + __m128h __A) { + return (__m128d)__builtin_ia32_vcvtph2pd128_mask((__v8hf)__A, (__v2df)__W, + (__mmask8)__U); +} + +static __inline__ __m128d __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_pd(__mmask8 __U, __m128h __A) { + return (__m128d)__builtin_ia32_vcvtph2pd128_mask( + (__v8hf)__A, (__v2df)_mm_setzero_pd(), (__mmask8)__U); +} + +static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_cvtph_pd(__m128h __A) { + return (__m256d)__builtin_ia32_vcvtph2pd256_mask( + (__v8hf)__A, (__v4df)_mm256_undefined_pd(), (__mmask8)-1); +} + +static __inline__ __m256d __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_pd(__m256d __W, __mmask8 __U, __m128h __A) { + return (__m256d)__builtin_ia32_vcvtph2pd256_mask((__v8hf)__A, (__v4df)__W, + (__mmask8)__U); +} + +static __inline__ __m256d __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_pd(__mmask8 __U, __m128h __A) { + return (__m256d)__builtin_ia32_vcvtph2pd256_mask( + (__v8hf)__A, (__v4df)_mm256_setzero_pd(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epi16(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2w128_mask( + (__v8hf)__A, (__v8hi)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epi16(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2w128_mask((__v8hf)__A, (__v8hi)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epi16(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2w128_mask( + (__v8hf)__A, (__v8hi)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epi16(__m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2w256_mask( + (__v16hf)__A, (__v16hi)_mm256_undefined_si256(), (__mmask16)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epi16(__m256i __W, __mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2w256_mask((__v16hf)__A, (__v16hi)__W, + (__mmask16)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epi16(__mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2w256_mask( + (__v16hf)__A, (__v16hi)_mm256_setzero_si256(), (__mmask16)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epi16(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2w128_mask( + (__v8hf)__A, (__v8hi)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epi16(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2w128_mask((__v8hf)__A, (__v8hi)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epi16(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2w128_mask( + (__v8hf)__A, (__v8hi)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epi16(__m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2w256_mask( + (__v16hf)__A, (__v16hi)_mm256_undefined_si256(), (__mmask16)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epi16(__m256i __W, __mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2w256_mask((__v16hf)__A, (__v16hi)__W, + (__mmask16)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epi16(__mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2w256_mask( + (__v16hf)__A, (__v16hi)_mm256_setzero_si256(), (__mmask16)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepi16_ph(__m128i __A) { + return (__m128h) __builtin_convertvector((__v8hi)__A, __v8hf); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepi16_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_cvtepi16_ph(__A), (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepi16_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_cvtepi16_ph(__A), (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_cvtepi16_ph(__m256i __A) { + return (__m256h) __builtin_convertvector((__v16hi)__A, __v16hf); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepi16_ph(__m256h __W, __mmask16 __U, __m256i __A) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, (__v16hf)_mm256_cvtepi16_ph(__A), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepi16_ph(__mmask16 __U, __m256i __A) { + return (__m256h)__builtin_ia32_selectph_256((__mmask16)__U, + (__v16hf)_mm256_cvtepi16_ph(__A), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epu16(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uw128_mask( + (__v8hf)__A, (__v8hu)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epu16(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uw128_mask((__v8hf)__A, (__v8hu)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epu16(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uw128_mask( + (__v8hf)__A, (__v8hu)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epu16(__m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2uw256_mask( + (__v16hf)__A, (__v16hu)_mm256_undefined_si256(), (__mmask16)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epu16(__m256i __W, __mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2uw256_mask((__v16hf)__A, (__v16hu)__W, + (__mmask16)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epu16(__mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvtph2uw256_mask( + (__v16hf)__A, (__v16hu)_mm256_setzero_si256(), (__mmask16)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epu16(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uw128_mask( + (__v8hf)__A, (__v8hu)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epu16(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uw128_mask((__v8hf)__A, (__v8hu)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epu16(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uw128_mask( + (__v8hf)__A, (__v8hu)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epu16(__m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2uw256_mask( + (__v16hf)__A, (__v16hu)_mm256_undefined_si256(), (__mmask16)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epu16(__m256i __W, __mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2uw256_mask((__v16hf)__A, (__v16hu)__W, + (__mmask16)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epu16(__mmask16 __U, __m256h __A) { + return (__m256i)__builtin_ia32_vcvttph2uw256_mask( + (__v16hf)__A, (__v16hu)_mm256_setzero_si256(), (__mmask16)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepu16_ph(__m128i __A) { + return (__m128h) __builtin_convertvector((__v8hu)__A, __v8hf); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepu16_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_cvtepu16_ph(__A), (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepu16_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm_cvtepu16_ph(__A), (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_cvtepu16_ph(__m256i __A) { + return (__m256h) __builtin_convertvector((__v16hu)__A, __v16hf); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepu16_ph(__m256h __W, __mmask16 __U, __m256i __A) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, (__v16hf)_mm256_cvtepu16_ph(__A), (__v16hf)__W); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepu16_ph(__mmask16 __U, __m256i __A) { + return (__m256h)__builtin_ia32_selectph_256((__mmask16)__U, + (__v16hf)_mm256_cvtepu16_ph(__A), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epi32(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2dq128_mask( + (__v8hf)__A, (__v4si)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epi32(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2dq128_mask((__v8hf)__A, (__v4si)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epi32(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2dq128_mask( + (__v8hf)__A, (__v4si)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epi32(__m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2dq256_mask( + (__v8hf)__A, (__v8si)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epi32(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2dq256_mask((__v8hf)__A, (__v8si)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epi32(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2dq256_mask( + (__v8hf)__A, (__v8si)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epu32(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2udq128_mask( + (__v8hf)__A, (__v4su)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epu32(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2udq128_mask((__v8hf)__A, (__v4su)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epu32(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2udq128_mask( + (__v8hf)__A, (__v4su)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epu32(__m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2udq256_mask( + (__v8hf)__A, (__v8su)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epu32(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2udq256_mask((__v8hf)__A, (__v8su)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epu32(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2udq256_mask( + (__v8hf)__A, (__v8su)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepi32_ph(__m128i __A) { + return (__m128h)__builtin_ia32_vcvtdq2ph128_mask( + (__v4si)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepi32_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtdq2ph128_mask((__v4si)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepi32_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtdq2ph128_mask( + (__v4si)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_cvtepi32_ph(__m256i __A) { + return (__m128h) __builtin_convertvector((__v8si)__A, __v8hf); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepi32_ph(__m128h __W, __mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm256_cvtepi32_ph(__A), (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepi32_ph(__mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm256_cvtepi32_ph(__A), (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepu32_ph(__m128i __A) { + return (__m128h)__builtin_ia32_vcvtudq2ph128_mask( + (__v4su)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepu32_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtudq2ph128_mask((__v4su)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepu32_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtudq2ph128_mask( + (__v4su)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_cvtepu32_ph(__m256i __A) { + return (__m128h) __builtin_convertvector((__v8su)__A, __v8hf); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepu32_ph(__m128h __W, __mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm256_cvtepu32_ph(__A), (__v8hf)__W); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepu32_ph(__mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, (__v8hf)_mm256_cvtepu32_ph(__A), (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epi32(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2dq128_mask( + (__v8hf)__A, (__v4si)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epi32(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2dq128_mask((__v8hf)__A, (__v4si)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epi32(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2dq128_mask( + (__v8hf)__A, (__v4si)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epi32(__m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2dq256_mask( + (__v8hf)__A, (__v8si)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epi32(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2dq256_mask((__v8hf)__A, (__v8si)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epi32(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2dq256_mask( + (__v8hf)__A, (__v8si)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epu32(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2udq128_mask( + (__v8hf)__A, (__v4su)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epu32(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2udq128_mask((__v8hf)__A, (__v4su)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epu32(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2udq128_mask( + (__v8hf)__A, (__v4su)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epu32(__m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2udq256_mask( + (__v8hf)__A, (__v8su)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epu32(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2udq256_mask((__v8hf)__A, (__v8su)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epu32(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2udq256_mask( + (__v8hf)__A, (__v8su)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepi64_ph(__m128i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph128_mask( + (__v2di)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepi64_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph128_mask((__v2di)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepi64_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph128_mask( + (__v2di)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_cvtepi64_ph(__m256i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph256_mask( + (__v4di)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepi64_ph(__m128h __W, __mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph256_mask((__v4di)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepi64_ph(__mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_vcvtqq2ph256_mask( + (__v4di)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epi64(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2qq128_mask( + (__v8hf)__A, (__v2di)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epi64(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2qq128_mask((__v8hf)__A, (__v2di)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epi64(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2qq128_mask( + (__v8hf)__A, (__v2di)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epi64(__m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2qq256_mask( + (__v8hf)__A, (__v4di)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epi64(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2qq256_mask((__v8hf)__A, (__v4di)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epi64(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2qq256_mask( + (__v8hf)__A, (__v4di)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtepu64_ph(__m128i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph128_mask( + (__v2du)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_cvtepu64_ph(__m128h __W, __mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph128_mask((__v2du)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtepu64_ph(__mmask8 __U, __m128i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph128_mask( + (__v2du)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_cvtepu64_ph(__m256i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph256_mask( + (__v4du)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtepu64_ph(__m128h __W, __mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph256_mask((__v4du)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtepu64_ph(__mmask8 __U, __m256i __A) { + return (__m128h)__builtin_ia32_vcvtuqq2ph256_mask( + (__v4du)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvtph_epu64(__m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uqq128_mask( + (__v8hf)__A, (__v2du)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvtph_epu64(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uqq128_mask((__v8hf)__A, (__v2du)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtph_epu64(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvtph2uqq128_mask( + (__v8hf)__A, (__v2du)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvtph_epu64(__m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2uqq256_mask( + (__v8hf)__A, (__v4du)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtph_epu64(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2uqq256_mask((__v8hf)__A, (__v4du)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtph_epu64(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvtph2uqq256_mask( + (__v8hf)__A, (__v4du)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epi64(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2qq128_mask( + (__v8hf)__A, (__v2di)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epi64(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2qq128_mask((__v8hf)__A, (__v2di)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epi64(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2qq128_mask( + (__v8hf)__A, (__v2di)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epi64(__m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2qq256_mask( + (__v8hf)__A, (__v4di)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epi64(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2qq256_mask((__v8hf)__A, (__v4di)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epi64(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2qq256_mask( + (__v8hf)__A, (__v4di)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_cvttph_epu64(__m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uqq128_mask( + (__v8hf)__A, (__v2du)_mm_undefined_si128(), (__mmask8)-1); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_mask_cvttph_epu64(__m128i __W, __mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uqq128_mask((__v8hf)__A, (__v2du)__W, + (__mmask8)__U); +} + +static __inline__ __m128i __DEFAULT_FN_ATTRS128 +_mm_maskz_cvttph_epu64(__mmask8 __U, __m128h __A) { + return (__m128i)__builtin_ia32_vcvttph2uqq128_mask( + (__v8hf)__A, (__v2du)_mm_setzero_si128(), (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_cvttph_epu64(__m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2uqq256_mask( + (__v8hf)__A, (__v4du)_mm256_undefined_si256(), (__mmask8)-1); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_mask_cvttph_epu64(__m256i __W, __mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2uqq256_mask((__v8hf)__A, (__v4du)__W, + (__mmask8)__U); +} + +static __inline__ __m256i __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvttph_epu64(__mmask8 __U, __m128h __A) { + return (__m256i)__builtin_ia32_vcvttph2uqq256_mask( + (__v8hf)__A, (__v4du)_mm256_setzero_si256(), (__mmask8)__U); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_cvtxph_ps(__m128h __A) { + return (__m128)__builtin_ia32_vcvtph2psx128_mask( + (__v8hf)__A, (__v4sf)_mm_undefined_ps(), (__mmask8)-1); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_cvtxph_ps(__m128 __W, + __mmask8 __U, + __m128h __A) { + return (__m128)__builtin_ia32_vcvtph2psx128_mask((__v8hf)__A, (__v4sf)__W, + (__mmask8)__U); +} + +static __inline__ __m128 __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtxph_ps(__mmask8 __U, __m128h __A) { + return (__m128)__builtin_ia32_vcvtph2psx128_mask( + (__v8hf)__A, (__v4sf)_mm_setzero_ps(), (__mmask8)__U); +} + +static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_cvtxph_ps(__m128h __A) { + return (__m256)__builtin_ia32_vcvtph2psx256_mask( + (__v8hf)__A, (__v8sf)_mm256_undefined_ps(), (__mmask8)-1); +} + +static __inline__ __m256 __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtxph_ps(__m256 __W, __mmask8 __U, __m128h __A) { + return (__m256)__builtin_ia32_vcvtph2psx256_mask((__v8hf)__A, (__v8sf)__W, + (__mmask8)__U); +} + +static __inline__ __m256 __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtxph_ps(__mmask8 __U, __m128h __A) { + return (__m256)__builtin_ia32_vcvtph2psx256_mask( + (__v8hf)__A, (__v8sf)_mm256_setzero_ps(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_cvtxps_ph(__m128 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx128_mask( + (__v4sf)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_cvtxps_ph(__m128h __W, + __mmask8 __U, + __m128 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx128_mask((__v4sf)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_cvtxps_ph(__mmask8 __U, __m128 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx128_mask( + (__v4sf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 _mm256_cvtxps_ph(__m256 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx256_mask( + (__v8sf)__A, (__v8hf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_mask_cvtxps_ph(__m128h __W, __mmask8 __U, __m256 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx256_mask((__v8sf)__A, (__v8hf)__W, + (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS256 +_mm256_maskz_cvtxps_ph(__mmask8 __U, __m256 __A) { + return (__m128h)__builtin_ia32_vcvtps2phx256_mask( + (__v8sf)__A, (__v8hf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmadd_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmadd_ph(__m128h __A, + __mmask8 __U, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmadd_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmadd_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmsub_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, + -(__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmsub_ph(__m128h __A, + __mmask8 __U, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, _mm_fmsub_ph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmsub_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, _mm_fmsub_ph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fnmadd_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph(-(__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fnmadd_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph(-(__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fnmsub_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph(-(__v8hf)__A, (__v8hf)__B, -(__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fmadd_ph(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmadd_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fmadd_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmadd_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fmsub_ph(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, + -(__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmsub_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmsub_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fnmadd_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256(-(__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fnmadd_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256(-(__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fnmsub_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256(-(__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmaddsub_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fmaddsub_ph(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmaddsub_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmaddsub_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, (__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmsubadd_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, + -(__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fmsubadd_ph(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, -(__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmsubadd_ph(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, -(__v8hf)__C), + (__v8hf)_mm_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_fmaddsub_ph(__m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmaddsub_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fmaddsub_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmaddsub_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, (__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_fmsubadd_ph(__m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, + -(__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmsubadd_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmsubadd_ph(__mmask16 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)_mm256_setzero_ph()); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmsub_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, (__v8hf)__B, -(__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fmsub_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmsubadd_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddsubph((__v8hf)__A, (__v8hf)__B, -(__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fmsubadd_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddsubph256((__v16hf)__A, (__v16hf)__B, -(__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fnmadd_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddph((__v8hf)__A, -(__v8hf)__B, + (__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fnmadd_ph(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, -(__v8hf)__B, (__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fnmadd_ph(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddph256((__v16hf)__A, -(__v16hf)__B, + (__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fnmadd_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, -(__v16hf)__B, (__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fnmsub_ph(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddph((__v8hf)__A, -(__v8hf)__B, + -(__v8hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fnmsub_ph(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, -(__v8hf)__B, -(__v8hf)__C), + (__v8hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fnmsub_ph(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_selectph_128( + (__mmask8)__U, + __builtin_ia32_vfmaddph((__v8hf)__A, -(__v8hf)__B, -(__v8hf)__C), + (__v8hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fnmsub_ph(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddph256((__v16hf)__A, -(__v16hf)__B, + -(__v16hf)__C); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fnmsub_ph(__m256h __A, __mmask16 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, -(__v16hf)__B, -(__v16hf)__C), + (__v16hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fnmsub_ph(__m256h __A, __m256h __B, __m256h __C, __mmask16 __U) { + return (__m256h)__builtin_ia32_selectph_256( + (__mmask16)__U, + __builtin_ia32_vfmaddph256((__v16hf)__A, -(__v16hf)__B, -(__v16hf)__C), + (__v16hf)__C); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fcmul_pch(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcph128_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fcmul_pch(__m128h __W, __mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__W, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fcmul_pch(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfcmulcph128_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS128 _mm256_fcmul_pch(__m256h __A, + __m256h __B) { + return (__m256h)__builtin_ia32_vfcmulcph256_mask( + (__v8sf)__A, (__v8sf)__B, (__v8sf)_mm256_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fcmul_pch(__m256h __W, __mmask8 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_vfcmulcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__W, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fcmul_pch(__mmask8 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_vfcmulcph256_mask( + (__v8sf)__A, (__v8sf)__B, (__v8sf)_mm256_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fcmadd_pch(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfcmaddcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fcmadd_pch(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectps_128( + __U, + __builtin_ia32_vfcmaddcph128_mask((__v4sf)__A, (__v4sf)(__m128h)__B, + (__v4sf)__C, (__mmask8)__U), + (__v4sf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fcmadd_pch(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_vfcmaddcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fcmadd_pch(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfcmaddcph128_maskz( + (__v4sf)__A, (__v4sf)__B, (__v4sf)__C, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fcmadd_pch(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfcmaddcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__C, (__mmask8)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fcmadd_pch(__m256h __A, __mmask8 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectps_256( + __U, + __builtin_ia32_vfcmaddcph256_mask((__v8sf)__A, (__v8sf)__B, (__v8sf)__C, + (__mmask8)__U), + (__v8sf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fcmadd_pch(__m256h __A, __m256h __B, __m256h __C, __mmask8 __U) { + return (__m256h)__builtin_ia32_vfcmaddcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__C, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fcmadd_pch(__mmask8 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_vfcmaddcph256_maskz( + (__v8sf)__A, (__v8sf)__B, (__v8sf)__C, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmul_pch(__m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcph128_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_fmul_pch(__m128h __W, + __mmask8 __U, + __m128h __A, + __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__W, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmul_pch(__mmask8 __U, __m128h __A, __m128h __B) { + return (__m128h)__builtin_ia32_vfmulcph128_mask( + (__v4sf)__A, (__v4sf)__B, (__v4sf)_mm_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fmul_pch(__m256h __A, + __m256h __B) { + return (__m256h)__builtin_ia32_vfmulcph256_mask( + (__v8sf)__A, (__v8sf)__B, (__v8sf)_mm256_undefined_ph(), (__mmask8)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmul_pch(__m256h __W, __mmask8 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_vfmulcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__W, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmul_pch(__mmask8 __U, __m256h __A, __m256h __B) { + return (__m256h)__builtin_ia32_vfmulcph256_mask( + (__v8sf)__A, (__v8sf)__B, (__v8sf)_mm256_setzero_ph(), (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_fmadd_pch(__m128h __A, + __m128h __B, + __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)-1); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask_fmadd_pch(__m128h __A, __mmask8 __U, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_selectps_128( + __U, + __builtin_ia32_vfmaddcph128_mask((__v4sf)__A, (__v4sf)__B, (__v4sf)__C, + (__mmask8)__U), + (__v4sf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_mask3_fmadd_pch(__m128h __A, __m128h __B, __m128h __C, __mmask8 __U) { + return (__m128h)__builtin_ia32_vfmaddcph128_mask((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_maskz_fmadd_pch(__mmask8 __U, __m128h __A, __m128h __B, __m128h __C) { + return (__m128h)__builtin_ia32_vfmaddcph128_maskz((__v4sf)__A, (__v4sf)__B, + (__v4sf)__C, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 _mm256_fmadd_pch(__m256h __A, + __m256h __B, + __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__C, (__mmask8)-1); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_fmadd_pch(__m256h __A, __mmask8 __U, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_selectps_256( + __U, + __builtin_ia32_vfmaddcph256_mask((__v8sf)__A, (__v8sf)__B, (__v8sf)__C, + (__mmask8)__U), + (__v8sf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask3_fmadd_pch(__m256h __A, __m256h __B, __m256h __C, __mmask8 __U) { + return (__m256h)__builtin_ia32_vfmaddcph256_mask((__v8sf)__A, (__v8sf)__B, + (__v8sf)__C, (__mmask8)__U); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_maskz_fmadd_pch(__mmask8 __U, __m256h __A, __m256h __B, __m256h __C) { + return (__m256h)__builtin_ia32_vfmaddcph256_maskz((__v8sf)__A, (__v8sf)__B, + (__v8sf)__C, (__mmask8)__U); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 _mm_mask_blend_ph(__mmask8 __U, + __m128h __A, + __m128h __W) { + return (__m128h)__builtin_ia32_selectph_128((__mmask8)__U, (__v8hf)__W, + (__v8hf)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_mask_blend_ph(__mmask16 __U, __m256h __A, __m256h __W) { + return (__m256h)__builtin_ia32_selectph_256((__mmask16)__U, (__v16hf)__W, + (__v16hf)__A); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_permutex2var_ph(__m128h __A, __m128i __I, __m128h __B) { + return (__m128h)__builtin_ia32_vpermi2varhi128((__v8hi)__A, (__v8hi)__I, + (__v8hi)__B); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_permutex2var_ph(__m256h __A, __m256i __I, __m256h __B) { + return (__m256h)__builtin_ia32_vpermi2varhi256((__v16hi)__A, (__v16hi)__I, + (__v16hi)__B); +} + +static __inline__ __m128h __DEFAULT_FN_ATTRS128 +_mm_permutexvar_ph(__m128i __A, __m128h __B) { + return (__m128h)__builtin_ia32_permvarhi128((__v8hi)__B, (__v8hi)__A); +} + +static __inline__ __m256h __DEFAULT_FN_ATTRS256 +_mm256_permutexvar_ph(__m256i __A, __m256h __B) { + return (__m256h)__builtin_ia32_permvarhi256((__v16hi)__B, (__v16hi)__A); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS256 +_mm256_reduce_add_ph(__m256h __W) { + return __builtin_ia32_reduce_fadd_ph256(-0.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS256 +_mm256_reduce_mul_ph(__m256h __W) { + return __builtin_ia32_reduce_fmul_ph256(1.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS256 +_mm256_reduce_max_ph(__m256h __V) { + return __builtin_ia32_reduce_fmax_ph256(__V); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS256 +_mm256_reduce_min_ph(__m256h __V) { + return __builtin_ia32_reduce_fmin_ph256(__V); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS128 +_mm_reduce_add_ph(__m128h __W) { + return __builtin_ia32_reduce_fadd_ph128(-0.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS128 +_mm_reduce_mul_ph(__m128h __W) { + return __builtin_ia32_reduce_fmul_ph128(1.0f16, __W); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS128 +_mm_reduce_max_ph(__m128h __V) { + return __builtin_ia32_reduce_fmax_ph128(__V); +} + +static __inline__ _Float16 __DEFAULT_FN_ATTRS128 +_mm_reduce_min_ph(__m128h __V) { + return __builtin_ia32_reduce_fmin_ph128(__V); +} + +// intrinsics below are alias for f*mul_*ch +#define _mm_mul_pch(A, B) _mm_fmul_pch(A, B) +#define _mm_mask_mul_pch(W, U, A, B) _mm_mask_fmul_pch(W, U, A, B) +#define _mm_maskz_mul_pch(U, A, B) _mm_maskz_fmul_pch(U, A, B) +#define _mm256_mul_pch(A, B) _mm256_fmul_pch(A, B) +#define _mm256_mask_mul_pch(W, U, A, B) _mm256_mask_fmul_pch(W, U, A, B) +#define _mm256_maskz_mul_pch(U, A, B) _mm256_maskz_fmul_pch(U, A, B) + +#define _mm_cmul_pch(A, B) _mm_fcmul_pch(A, B) +#define _mm_mask_cmul_pch(W, U, A, B) _mm_mask_fcmul_pch(W, U, A, B) +#define _mm_maskz_cmul_pch(U, A, B) _mm_maskz_fcmul_pch(U, A, B) +#define _mm256_cmul_pch(A, B) _mm256_fcmul_pch(A, B) +#define _mm256_mask_cmul_pch(W, U, A, B) _mm256_mask_fcmul_pch(W, U, A, B) +#define _mm256_maskz_cmul_pch(U, A, B) _mm256_maskz_fcmul_pch(U, A, B) + +#undef __DEFAULT_FN_ATTRS128 +#undef __DEFAULT_FN_ATTRS256 + +#endif diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h index 968c10efeac..0519dba5908 100644 --- a/clang/lib/Headers/avx512vlintrin.h +++ b/clang/lib/Headers/avx512vlintrin.h @@ -771,124 +771,124 @@ _mm_maskz_xor_epi64(__mmask8 __U, __m128i __A, __m128i __B) } #define _mm_cmp_epi32_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)(__m128i)(a), \ - (__v4si)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpd128_mask((__v4si)(__m128i)(a), \ + (__v4si)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epi32_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpd128_mask((__v4si)(__m128i)(a), \ - (__v4si)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpd128_mask((__v4si)(__m128i)(a), \ + (__v4si)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_epu32_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)(__m128i)(a), \ - (__v4si)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)(__m128i)(a), \ + (__v4si)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epu32_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)(__m128i)(a), \ - (__v4si)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpd128_mask((__v4si)(__m128i)(a), \ + (__v4si)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_epi32_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)(__m256i)(a), \ - (__v8si)(__m256i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpd256_mask((__v8si)(__m256i)(a), \ + (__v8si)(__m256i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_epi32_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpd256_mask((__v8si)(__m256i)(a), \ - (__v8si)(__m256i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpd256_mask((__v8si)(__m256i)(a), \ + (__v8si)(__m256i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_epu32_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)(__m256i)(a), \ - (__v8si)(__m256i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)(__m256i)(a), \ + (__v8si)(__m256i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_epu32_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)(__m256i)(a), \ - (__v8si)(__m256i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpd256_mask((__v8si)(__m256i)(a), \ + (__v8si)(__m256i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_epi64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)(__m128i)(a), \ - (__v2di)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpq128_mask((__v2di)(__m128i)(a), \ + (__v2di)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epi64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpq128_mask((__v2di)(__m128i)(a), \ - (__v2di)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpq128_mask((__v2di)(__m128i)(a), \ + (__v2di)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_epu64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)(__m128i)(a), \ - (__v2di)(__m128i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)(__m128i)(a), \ + (__v2di)(__m128i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_epu64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)(__m128i)(a), \ - (__v2di)(__m128i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpq128_mask((__v2di)(__m128i)(a), \ + (__v2di)(__m128i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_epi64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)(__m256i)(a), \ - (__v4di)(__m256i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpq256_mask((__v4di)(__m256i)(a), \ + (__v4di)(__m256i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_epi64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpq256_mask((__v4di)(__m256i)(a), \ - (__v4di)(__m256i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpq256_mask((__v4di)(__m256i)(a), \ + (__v4di)(__m256i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_epu64_mask(a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)(__m256i)(a), \ - (__v4di)(__m256i)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)(__m256i)(a), \ + (__v4di)(__m256i)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_epu64_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)(__m256i)(a), \ - (__v4di)(__m256i)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_ucmpq256_mask((__v4di)(__m256i)(a), \ + (__v4di)(__m256i)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_ps_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpps256_mask((__v8sf)(__m256)(a), \ - (__v8sf)(__m256)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpps256_mask((__v8sf)(__m256)(a), \ + (__v8sf)(__m256)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_ps_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpps256_mask((__v8sf)(__m256)(a), \ - (__v8sf)(__m256)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpps256_mask((__v8sf)(__m256)(a), \ + (__v8sf)(__m256)(b), (int)(p), \ + (__mmask8)(m))) #define _mm256_cmp_pd_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmppd256_mask((__v4df)(__m256d)(a), \ - (__v4df)(__m256d)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmppd256_mask((__v4df)(__m256d)(a), \ + (__v4df)(__m256d)(b), (int)(p), \ + (__mmask8)-1)) #define _mm256_mask_cmp_pd_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmppd256_mask((__v4df)(__m256d)(a), \ - (__v4df)(__m256d)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmppd256_mask((__v4df)(__m256d)(a), \ + (__v4df)(__m256d)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_ps_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmpps128_mask((__v4sf)(__m128)(a), \ - (__v4sf)(__m128)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmpps128_mask((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_ps_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmpps128_mask((__v4sf)(__m128)(a), \ - (__v4sf)(__m128)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmpps128_mask((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (int)(p), \ + (__mmask8)(m))) #define _mm_cmp_pd_mask(a, b, p) \ - (__mmask8)__builtin_ia32_cmppd128_mask((__v2df)(__m128d)(a), \ - (__v2df)(__m128d)(b), (int)(p), \ - (__mmask8)-1) + ((__mmask8)__builtin_ia32_cmppd128_mask((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (int)(p), \ + (__mmask8)-1)) #define _mm_mask_cmp_pd_mask(m, a, b, p) \ - (__mmask8)__builtin_ia32_cmppd128_mask((__v2df)(__m128d)(a), \ - (__v2df)(__m128d)(b), (int)(p), \ - (__mmask8)(m)) + ((__mmask8)__builtin_ia32_cmppd128_mask((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (int)(p), \ + (__mmask8)(m))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_fmadd_pd(__m128d __A, __mmask8 __U, __m128d __B, __m128d __C) @@ -3289,78 +3289,78 @@ _mm256_maskz_min_epu64 (__mmask8 __M, __m256i __A, __m256i __B) { } #define _mm_roundscale_pd(A, imm) \ - (__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ - (int)(imm), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ + (int)(imm), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1)) #define _mm_mask_roundscale_pd(W, U, A, imm) \ - (__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ - (int)(imm), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ + (int)(imm), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm_maskz_roundscale_pd(U, A, imm) \ - (__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ - (int)(imm), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_rndscalepd_128_mask((__v2df)(__m128d)(A), \ + (int)(imm), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm256_roundscale_pd(A, imm) \ - (__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)-1)) #define _mm256_mask_roundscale_pd(W, U, A, imm) \ - (__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v4df)(__m256d)(W), \ + (__mmask8)(U))) #define _mm256_maskz_roundscale_pd(U, A, imm) \ - (__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ - (int)(imm), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_rndscalepd_256_mask((__v4df)(__m256d)(A), \ + (int)(imm), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)(U))) #define _mm_roundscale_ps(A, imm) \ - (__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1)) #define _mm_mask_roundscale_ps(W, U, A, imm) \ - (__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U))) #define _mm_maskz_roundscale_ps(U, A, imm) \ - (__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_rndscaleps_128_mask((__v4sf)(__m128)(A), (int)(imm), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) #define _mm256_roundscale_ps(A, imm) \ - (__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1) + ((__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1)) #define _mm256_mask_roundscale_ps(W, U, A, imm) \ - (__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ - (__v8sf)(__m256)(W), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ + (__v8sf)(__m256)(W), \ + (__mmask8)(U))) #define _mm256_maskz_roundscale_ps(U, A, imm) \ - (__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_rndscaleps_256_mask((__v8sf)(__m256)(A), (int)(imm), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_scalef_pd (__m128d __A, __m128d __B) { @@ -4298,56 +4298,56 @@ _mm256_maskz_scalef_ps (__mmask8 __U, __m256 __A, __m256 __B) { #define _mm_rol_epi32(a, b) \ - (__m128i)__builtin_ia32_prold128((__v4si)(__m128i)(a), (int)(b)) + ((__m128i)__builtin_ia32_prold128((__v4si)(__m128i)(a), (int)(b))) #define _mm_mask_rol_epi32(w, u, a, b) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ - (__v4si)_mm_rol_epi32((a), (b)), \ - (__v4si)(__m128i)(w)) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ + (__v4si)_mm_rol_epi32((a), (b)), \ + (__v4si)(__m128i)(w))) #define _mm_maskz_rol_epi32(u, a, b) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ - (__v4si)_mm_rol_epi32((a), (b)), \ - (__v4si)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ + (__v4si)_mm_rol_epi32((a), (b)), \ + (__v4si)_mm_setzero_si128())) #define _mm256_rol_epi32(a, b) \ - (__m256i)__builtin_ia32_prold256((__v8si)(__m256i)(a), (int)(b)) + ((__m256i)__builtin_ia32_prold256((__v8si)(__m256i)(a), (int)(b))) #define _mm256_mask_rol_epi32(w, u, a, b) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ - (__v8si)_mm256_rol_epi32((a), (b)), \ - (__v8si)(__m256i)(w)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ + (__v8si)_mm256_rol_epi32((a), (b)), \ + (__v8si)(__m256i)(w))) #define _mm256_maskz_rol_epi32(u, a, b) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ - (__v8si)_mm256_rol_epi32((a), (b)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ + (__v8si)_mm256_rol_epi32((a), (b)), \ + (__v8si)_mm256_setzero_si256())) #define _mm_rol_epi64(a, b) \ - (__m128i)__builtin_ia32_prolq128((__v2di)(__m128i)(a), (int)(b)) + ((__m128i)__builtin_ia32_prolq128((__v2di)(__m128i)(a), (int)(b))) #define _mm_mask_rol_epi64(w, u, a, b) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ - (__v2di)_mm_rol_epi64((a), (b)), \ - (__v2di)(__m128i)(w)) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ + (__v2di)_mm_rol_epi64((a), (b)), \ + (__v2di)(__m128i)(w))) #define _mm_maskz_rol_epi64(u, a, b) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ - (__v2di)_mm_rol_epi64((a), (b)), \ - (__v2di)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ + (__v2di)_mm_rol_epi64((a), (b)), \ + (__v2di)_mm_setzero_si128())) #define _mm256_rol_epi64(a, b) \ - (__m256i)__builtin_ia32_prolq256((__v4di)(__m256i)(a), (int)(b)) + ((__m256i)__builtin_ia32_prolq256((__v4di)(__m256i)(a), (int)(b))) #define _mm256_mask_rol_epi64(w, u, a, b) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ - (__v4di)_mm256_rol_epi64((a), (b)), \ - (__v4di)(__m256i)(w)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ + (__v4di)_mm256_rol_epi64((a), (b)), \ + (__v4di)(__m256i)(w))) #define _mm256_maskz_rol_epi64(u, a, b) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ - (__v4di)_mm256_rol_epi64((a), (b)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ + (__v4di)_mm256_rol_epi64((a), (b)), \ + (__v4di)_mm256_setzero_si256())) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_rolv_epi32 (__m128i __A, __m128i __B) @@ -4438,56 +4438,56 @@ _mm256_maskz_rolv_epi64 (__mmask8 __U, __m256i __A, __m256i __B) } #define _mm_ror_epi32(a, b) \ - (__m128i)__builtin_ia32_prord128((__v4si)(__m128i)(a), (int)(b)) + ((__m128i)__builtin_ia32_prord128((__v4si)(__m128i)(a), (int)(b))) #define _mm_mask_ror_epi32(w, u, a, b) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ - (__v4si)_mm_ror_epi32((a), (b)), \ - (__v4si)(__m128i)(w)) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ + (__v4si)_mm_ror_epi32((a), (b)), \ + (__v4si)(__m128i)(w))) #define _mm_maskz_ror_epi32(u, a, b) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ - (__v4si)_mm_ror_epi32((a), (b)), \ - (__v4si)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(u), \ + (__v4si)_mm_ror_epi32((a), (b)), \ + (__v4si)_mm_setzero_si128())) #define _mm256_ror_epi32(a, b) \ - (__m256i)__builtin_ia32_prord256((__v8si)(__m256i)(a), (int)(b)) + ((__m256i)__builtin_ia32_prord256((__v8si)(__m256i)(a), (int)(b))) #define _mm256_mask_ror_epi32(w, u, a, b) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ - (__v8si)_mm256_ror_epi32((a), (b)), \ - (__v8si)(__m256i)(w)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ + (__v8si)_mm256_ror_epi32((a), (b)), \ + (__v8si)(__m256i)(w))) #define _mm256_maskz_ror_epi32(u, a, b) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ - (__v8si)_mm256_ror_epi32((a), (b)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(u), \ + (__v8si)_mm256_ror_epi32((a), (b)), \ + (__v8si)_mm256_setzero_si256())) #define _mm_ror_epi64(a, b) \ - (__m128i)__builtin_ia32_prorq128((__v2di)(__m128i)(a), (int)(b)) + ((__m128i)__builtin_ia32_prorq128((__v2di)(__m128i)(a), (int)(b))) #define _mm_mask_ror_epi64(w, u, a, b) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ - (__v2di)_mm_ror_epi64((a), (b)), \ - (__v2di)(__m128i)(w)) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ + (__v2di)_mm_ror_epi64((a), (b)), \ + (__v2di)(__m128i)(w))) #define _mm_maskz_ror_epi64(u, a, b) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ - (__v2di)_mm_ror_epi64((a), (b)), \ - (__v2di)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(u), \ + (__v2di)_mm_ror_epi64((a), (b)), \ + (__v2di)_mm_setzero_si128())) #define _mm256_ror_epi64(a, b) \ - (__m256i)__builtin_ia32_prorq256((__v4di)(__m256i)(a), (int)(b)) + ((__m256i)__builtin_ia32_prorq256((__v4di)(__m256i)(a), (int)(b))) #define _mm256_mask_ror_epi64(w, u, a, b) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ - (__v4di)_mm256_ror_epi64((a), (b)), \ - (__v4di)(__m256i)(w)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ + (__v4di)_mm256_ror_epi64((a), (b)), \ + (__v4di)(__m256i)(w))) #define _mm256_maskz_ror_epi64(u, a, b) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ - (__v4di)_mm256_ror_epi64((a), (b)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(u), \ + (__v4di)_mm256_ror_epi64((a), (b)), \ + (__v4di)_mm256_setzero_si256())) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_sll_epi32(__m128i __W, __mmask8 __U, __m128i __A, __m128i __B) @@ -5356,76 +5356,76 @@ _mm256_maskz_set1_epi64 (__mmask8 __M, long long __A) } #define _mm_fixupimm_pd(A, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmpd128_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_fixupimmpd128_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)-1)) #define _mm_mask_fixupimm_pd(A, U, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmpd128_mask((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_fixupimmpd128_mask((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm_maskz_fixupimm_pd(U, A, B, C, imm) \ - (__m128d)__builtin_ia32_fixupimmpd128_maskz((__v2df)(__m128d)(A), \ - (__v2df)(__m128d)(B), \ - (__v2di)(__m128i)(C), \ - (int)(imm), (__mmask8)(U)) + ((__m128d)__builtin_ia32_fixupimmpd128_maskz((__v2df)(__m128d)(A), \ + (__v2df)(__m128d)(B), \ + (__v2di)(__m128i)(C), \ + (int)(imm), (__mmask8)(U))) #define _mm256_fixupimm_pd(A, B, C, imm) \ - (__m256d)__builtin_ia32_fixupimmpd256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (__v4di)(__m256i)(C), (int)(imm), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_fixupimmpd256_mask((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), \ + (__v4di)(__m256i)(C), (int)(imm), \ + (__mmask8)-1)) #define _mm256_mask_fixupimm_pd(A, U, B, C, imm) \ - (__m256d)__builtin_ia32_fixupimmpd256_mask((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (__v4di)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_fixupimmpd256_mask((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), \ + (__v4di)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm256_maskz_fixupimm_pd(U, A, B, C, imm) \ - (__m256d)__builtin_ia32_fixupimmpd256_maskz((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), \ - (__v4di)(__m256i)(C), \ - (int)(imm), (__mmask8)(U)) + ((__m256d)__builtin_ia32_fixupimmpd256_maskz((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), \ + (__v4di)(__m256i)(C), \ + (int)(imm), (__mmask8)(U))) #define _mm_fixupimm_ps(A, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmps128_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm_mask_fixupimm_ps(A, U, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmps128_mask((__v4sf)(__m128)(A), \ - (__v4sf)(__m128)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm_maskz_fixupimm_ps(U, A, B, C, imm) \ - (__m128)__builtin_ia32_fixupimmps128_maskz((__v4sf)(__m128)(A), \ + ((__m128)__builtin_ia32_fixupimmps128_mask((__v4sf)(__m128)(A), \ (__v4sf)(__m128)(B), \ (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm_mask_fixupimm_ps(A, U, B, C, imm) \ + ((__m128)__builtin_ia32_fixupimmps128_mask((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm_maskz_fixupimm_ps(U, A, B, C, imm) \ + ((__m128)__builtin_ia32_fixupimmps128_maskz((__v4sf)(__m128)(A), \ + (__v4sf)(__m128)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm256_fixupimm_ps(A, B, C, imm) \ - (__m256)__builtin_ia32_fixupimmps256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), \ - (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm256_mask_fixupimm_ps(A, U, B, C, imm) \ - (__m256)__builtin_ia32_fixupimmps256_mask((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), \ - (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm256_maskz_fixupimm_ps(U, A, B, C, imm) \ - (__m256)__builtin_ia32_fixupimmps256_maskz((__v8sf)(__m256)(A), \ + ((__m256)__builtin_ia32_fixupimmps256_mask((__v8sf)(__m256)(A), \ (__v8sf)(__m256)(B), \ (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm256_mask_fixupimm_ps(A, U, B, C, imm) \ + ((__m256)__builtin_ia32_fixupimmps256_mask((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), \ + (__v8si)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm256_maskz_fixupimm_ps(U, A, B, C, imm) \ + ((__m256)__builtin_ia32_fixupimmps256_maskz((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), \ + (__v8si)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_load_pd (__m128d __W, __mmask8 __U, void const *__P) @@ -6033,44 +6033,44 @@ _mm256_maskz_rcp14_ps (__mmask8 __U, __m256 __A) } #define _mm_mask_permute_pd(W, U, X, C) \ - (__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ - (__v2df)_mm_permute_pd((X), (C)), \ - (__v2df)(__m128d)(W)) + ((__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ + (__v2df)_mm_permute_pd((X), (C)), \ + (__v2df)(__m128d)(W))) #define _mm_maskz_permute_pd(U, X, C) \ - (__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ - (__v2df)_mm_permute_pd((X), (C)), \ - (__v2df)_mm_setzero_pd()) + ((__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ + (__v2df)_mm_permute_pd((X), (C)), \ + (__v2df)_mm_setzero_pd())) #define _mm256_mask_permute_pd(W, U, X, C) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_permute_pd((X), (C)), \ - (__v4df)(__m256d)(W)) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_permute_pd((X), (C)), \ + (__v4df)(__m256d)(W))) #define _mm256_maskz_permute_pd(U, X, C) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_permute_pd((X), (C)), \ - (__v4df)_mm256_setzero_pd()) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_permute_pd((X), (C)), \ + (__v4df)_mm256_setzero_pd())) #define _mm_mask_permute_ps(W, U, X, C) \ - (__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ - (__v4sf)_mm_permute_ps((X), (C)), \ - (__v4sf)(__m128)(W)) + ((__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ + (__v4sf)_mm_permute_ps((X), (C)), \ + (__v4sf)(__m128)(W))) #define _mm_maskz_permute_ps(U, X, C) \ - (__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ - (__v4sf)_mm_permute_ps((X), (C)), \ - (__v4sf)_mm_setzero_ps()) + ((__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ + (__v4sf)_mm_permute_ps((X), (C)), \ + (__v4sf)_mm_setzero_ps())) #define _mm256_mask_permute_ps(W, U, X, C) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_permute_ps((X), (C)), \ - (__v8sf)(__m256)(W)) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_permute_ps((X), (C)), \ + (__v8sf)(__m256)(W))) #define _mm256_maskz_permute_ps(U, X, C) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_permute_ps((X), (C)), \ - (__v8sf)_mm256_setzero_ps()) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_permute_ps((X), (C)), \ + (__v8sf)_mm256_setzero_ps())) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_permutevar_pd(__m128d __W, __mmask8 __U, __m128d __A, __m128i __C) @@ -6526,175 +6526,175 @@ _mm256_maskz_srai_epi64(__mmask8 __U, __m256i __A, unsigned int __imm) } #define _mm_ternarylogic_epi32(A, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogd128_mask((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm_mask_ternarylogic_epi32(A, U, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogd128_mask((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), \ - (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm_maskz_ternarylogic_epi32(U, A, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogd128_maskz((__v4si)(__m128i)(A), \ + ((__m128i)__builtin_ia32_pternlogd128_mask((__v4si)(__m128i)(A), \ (__v4si)(__m128i)(B), \ (__v4si)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm_mask_ternarylogic_epi32(A, U, B, C, imm) \ + ((__m128i)__builtin_ia32_pternlogd128_mask((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm_maskz_ternarylogic_epi32(U, A, B, C, imm) \ + ((__m128i)__builtin_ia32_pternlogd128_maskz((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), \ + (__v4si)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm256_ternarylogic_epi32(A, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogd256_mask((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), \ - (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm256_mask_ternarylogic_epi32(A, U, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogd256_mask((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), \ - (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm256_maskz_ternarylogic_epi32(U, A, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogd256_maskz((__v8si)(__m256i)(A), \ + ((__m256i)__builtin_ia32_pternlogd256_mask((__v8si)(__m256i)(A), \ (__v8si)(__m256i)(B), \ (__v8si)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm256_mask_ternarylogic_epi32(A, U, B, C, imm) \ + ((__m256i)__builtin_ia32_pternlogd256_mask((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), \ + (__v8si)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm256_maskz_ternarylogic_epi32(U, A, B, C, imm) \ + ((__m256i)__builtin_ia32_pternlogd256_maskz((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), \ + (__v8si)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm_ternarylogic_epi64(A, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogq128_mask((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm_mask_ternarylogic_epi64(A, U, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogq128_mask((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), \ - (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm_maskz_ternarylogic_epi64(U, A, B, C, imm) \ - (__m128i)__builtin_ia32_pternlogq128_maskz((__v2di)(__m128i)(A), \ + ((__m128i)__builtin_ia32_pternlogq128_mask((__v2di)(__m128i)(A), \ (__v2di)(__m128i)(B), \ (__v2di)(__m128i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm_mask_ternarylogic_epi64(A, U, B, C, imm) \ + ((__m128i)__builtin_ia32_pternlogq128_mask((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm_maskz_ternarylogic_epi64(U, A, B, C, imm) \ + ((__m128i)__builtin_ia32_pternlogq128_maskz((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), \ + (__v2di)(__m128i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm256_ternarylogic_epi64(A, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogq256_mask((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (__v4di)(__m256i)(C), (int)(imm), \ - (__mmask8)-1) - -#define _mm256_mask_ternarylogic_epi64(A, U, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogq256_mask((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (__v4di)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) - -#define _mm256_maskz_ternarylogic_epi64(U, A, B, C, imm) \ - (__m256i)__builtin_ia32_pternlogq256_maskz((__v4di)(__m256i)(A), \ + ((__m256i)__builtin_ia32_pternlogq256_mask((__v4di)(__m256i)(A), \ (__v4di)(__m256i)(B), \ (__v4di)(__m256i)(C), (int)(imm), \ - (__mmask8)(U)) + (__mmask8)-1)) + +#define _mm256_mask_ternarylogic_epi64(A, U, B, C, imm) \ + ((__m256i)__builtin_ia32_pternlogq256_mask((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), \ + (__v4di)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) + +#define _mm256_maskz_ternarylogic_epi64(U, A, B, C, imm) \ + ((__m256i)__builtin_ia32_pternlogq256_maskz((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), \ + (__v4di)(__m256i)(C), (int)(imm), \ + (__mmask8)(U))) #define _mm256_shuffle_f32x4(A, B, imm) \ - (__m256)__builtin_ia32_shuf_f32x4_256((__v8sf)(__m256)(A), \ - (__v8sf)(__m256)(B), (int)(imm)) + ((__m256)__builtin_ia32_shuf_f32x4_256((__v8sf)(__m256)(A), \ + (__v8sf)(__m256)(B), (int)(imm))) #define _mm256_mask_shuffle_f32x4(W, U, A, B, imm) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ - (__v8sf)(__m256)(W)) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ + (__v8sf)(__m256)(W))) #define _mm256_maskz_shuffle_f32x4(U, A, B, imm) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ - (__v8sf)_mm256_setzero_ps()) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_f32x4((A), (B), (imm)), \ + (__v8sf)_mm256_setzero_ps())) #define _mm256_shuffle_f64x2(A, B, imm) \ - (__m256d)__builtin_ia32_shuf_f64x2_256((__v4df)(__m256d)(A), \ - (__v4df)(__m256d)(B), (int)(imm)) + ((__m256d)__builtin_ia32_shuf_f64x2_256((__v4df)(__m256d)(A), \ + (__v4df)(__m256d)(B), (int)(imm))) #define _mm256_mask_shuffle_f64x2(W, U, A, B, imm) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ - (__v4df)(__m256d)(W)) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ + (__v4df)(__m256d)(W))) #define _mm256_maskz_shuffle_f64x2(U, A, B, imm) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ - (__v4df)_mm256_setzero_pd()) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_f64x2((A), (B), (imm)), \ + (__v4df)_mm256_setzero_pd())) #define _mm256_shuffle_i32x4(A, B, imm) \ - (__m256i)__builtin_ia32_shuf_i32x4_256((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_shuf_i32x4_256((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), (int)(imm))) #define _mm256_mask_shuffle_i32x4(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ - (__v8si)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ + (__v8si)(__m256i)(W))) #define _mm256_maskz_shuffle_i32x4(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_i32x4((A), (B), (imm)), \ + (__v8si)_mm256_setzero_si256())) #define _mm256_shuffle_i64x2(A, B, imm) \ - (__m256i)__builtin_ia32_shuf_i64x2_256((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_shuf_i64x2_256((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), (int)(imm))) #define _mm256_mask_shuffle_i64x2(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ - (__v4di)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ + (__v4di)(__m256i)(W))) #define _mm256_maskz_shuffle_i64x2(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shuffle_i64x2((A), (B), (imm)), \ + (__v4di)_mm256_setzero_si256())) #define _mm_mask_shuffle_pd(W, U, A, B, M) \ - (__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ - (__v2df)_mm_shuffle_pd((A), (B), (M)), \ - (__v2df)(__m128d)(W)) + ((__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ + (__v2df)_mm_shuffle_pd((A), (B), (M)), \ + (__v2df)(__m128d)(W))) #define _mm_maskz_shuffle_pd(U, A, B, M) \ - (__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ - (__v2df)_mm_shuffle_pd((A), (B), (M)), \ - (__v2df)_mm_setzero_pd()) + ((__m128d)__builtin_ia32_selectpd_128((__mmask8)(U), \ + (__v2df)_mm_shuffle_pd((A), (B), (M)), \ + (__v2df)_mm_setzero_pd())) #define _mm256_mask_shuffle_pd(W, U, A, B, M) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_shuffle_pd((A), (B), (M)), \ - (__v4df)(__m256d)(W)) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_pd((A), (B), (M)), \ + (__v4df)(__m256d)(W))) #define _mm256_maskz_shuffle_pd(U, A, B, M) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_shuffle_pd((A), (B), (M)), \ - (__v4df)_mm256_setzero_pd()) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_shuffle_pd((A), (B), (M)), \ + (__v4df)_mm256_setzero_pd())) #define _mm_mask_shuffle_ps(W, U, A, B, M) \ - (__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ - (__v4sf)_mm_shuffle_ps((A), (B), (M)), \ - (__v4sf)(__m128)(W)) + ((__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ + (__v4sf)_mm_shuffle_ps((A), (B), (M)), \ + (__v4sf)(__m128)(W))) #define _mm_maskz_shuffle_ps(U, A, B, M) \ - (__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ - (__v4sf)_mm_shuffle_ps((A), (B), (M)), \ - (__v4sf)_mm_setzero_ps()) + ((__m128)__builtin_ia32_selectps_128((__mmask8)(U), \ + (__v4sf)_mm_shuffle_ps((A), (B), (M)), \ + (__v4sf)_mm_setzero_ps())) #define _mm256_mask_shuffle_ps(W, U, A, B, M) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_shuffle_ps((A), (B), (M)), \ - (__v8sf)(__m256)(W)) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_ps((A), (B), (M)), \ + (__v8sf)(__m256)(W))) #define _mm256_maskz_shuffle_ps(U, A, B, M) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ - (__v8sf)_mm256_shuffle_ps((A), (B), (M)), \ - (__v8sf)_mm256_setzero_ps()) + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + (__v8sf)_mm256_shuffle_ps((A), (B), (M)), \ + (__v8sf)_mm256_setzero_ps())) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_rsqrt14_pd (__m128d __A) @@ -7834,262 +7834,262 @@ _mm256_mask_cvtepi64_storeu_epi16 (void * __P, __mmask8 __M, __m256i __A) } #define _mm256_extractf32x4_ps(A, imm) \ - (__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ - (int)(imm), \ - (__v4sf)_mm_undefined_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ + (int)(imm), \ + (__v4sf)_mm_undefined_ps(), \ + (__mmask8)-1)) #define _mm256_mask_extractf32x4_ps(W, U, A, imm) \ - (__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ - (int)(imm), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ + (int)(imm), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U))) #define _mm256_maskz_extractf32x4_ps(U, A, imm) \ - (__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ - (int)(imm), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_extractf32x4_256_mask((__v8sf)(__m256)(A), \ + (int)(imm), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) #define _mm256_extracti32x4_epi32(A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ - (int)(imm), \ - (__v4si)_mm_undefined_si128(), \ - (__mmask8)-1) + ((__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ + (int)(imm), \ + (__v4si)_mm_undefined_si128(), \ + (__mmask8)-1)) #define _mm256_mask_extracti32x4_epi32(W, U, A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ - (int)(imm), \ - (__v4si)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ + (int)(imm), \ + (__v4si)(__m128i)(W), \ + (__mmask8)(U))) #define _mm256_maskz_extracti32x4_epi32(U, A, imm) \ - (__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ - (int)(imm), \ - (__v4si)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_extracti32x4_256_mask((__v8si)(__m256i)(A), \ + (int)(imm), \ + (__v4si)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm256_insertf32x4(A, B, imm) \ - (__m256)__builtin_ia32_insertf32x4_256((__v8sf)(__m256)(A), \ - (__v4sf)(__m128)(B), (int)(imm)) + ((__m256)__builtin_ia32_insertf32x4_256((__v8sf)(__m256)(A), \ + (__v4sf)(__m128)(B), (int)(imm))) #define _mm256_mask_insertf32x4(W, U, A, B, imm) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ (__v8sf)_mm256_insertf32x4((A), (B), (imm)), \ - (__v8sf)(__m256)(W)) + (__v8sf)(__m256)(W))) #define _mm256_maskz_insertf32x4(U, A, B, imm) \ - (__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ + ((__m256)__builtin_ia32_selectps_256((__mmask8)(U), \ (__v8sf)_mm256_insertf32x4((A), (B), (imm)), \ - (__v8sf)_mm256_setzero_ps()) + (__v8sf)_mm256_setzero_ps())) #define _mm256_inserti32x4(A, B, imm) \ - (__m256i)__builtin_ia32_inserti32x4_256((__v8si)(__m256i)(A), \ - (__v4si)(__m128i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_inserti32x4_256((__v8si)(__m256i)(A), \ + (__v4si)(__m128i)(B), (int)(imm))) #define _mm256_mask_inserti32x4(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ (__v8si)_mm256_inserti32x4((A), (B), (imm)), \ - (__v8si)(__m256i)(W)) + (__v8si)(__m256i)(W))) #define _mm256_maskz_inserti32x4(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ (__v8si)_mm256_inserti32x4((A), (B), (imm)), \ - (__v8si)_mm256_setzero_si256()) + (__v8si)_mm256_setzero_si256())) #define _mm_getmant_pd(A, B, C) \ - (__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)-1) + ((__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)-1)) #define _mm_mask_getmant_pd(W, U, A, B, C) \ - (__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v2df)(__m128d)(W), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v2df)(__m128d)(W), \ + (__mmask8)(U))) #define _mm_maskz_getmant_pd(U, A, B, C) \ - (__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v2df)_mm_setzero_pd(), \ - (__mmask8)(U)) + ((__m128d)__builtin_ia32_getmantpd128_mask((__v2df)(__m128d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v2df)_mm_setzero_pd(), \ + (__mmask8)(U))) #define _mm256_getmant_pd(A, B, C) \ - (__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)-1) + ((__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)-1)) #define _mm256_mask_getmant_pd(W, U, A, B, C) \ - (__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4df)(__m256d)(W), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4df)(__m256d)(W), \ + (__mmask8)(U))) #define _mm256_maskz_getmant_pd(U, A, B, C) \ - (__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4df)_mm256_setzero_pd(), \ - (__mmask8)(U)) + ((__m256d)__builtin_ia32_getmantpd256_mask((__v4df)(__m256d)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4df)_mm256_setzero_pd(), \ + (__mmask8)(U))) #define _mm_getmant_ps(A, B, C) \ - (__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)-1) + ((__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)-1)) #define _mm_mask_getmant_ps(W, U, A, B, C) \ - (__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4sf)(__m128)(W), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4sf)(__m128)(W), \ + (__mmask8)(U))) #define _mm_maskz_getmant_ps(U, A, B, C) \ - (__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ - (int)(((C)<<2) | (B)), \ - (__v4sf)_mm_setzero_ps(), \ - (__mmask8)(U)) + ((__m128)__builtin_ia32_getmantps128_mask((__v4sf)(__m128)(A), \ + (int)(((C)<<2) | (B)), \ + (__v4sf)_mm_setzero_ps(), \ + (__mmask8)(U))) #define _mm256_getmant_ps(A, B, C) \ - (__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)-1) + ((__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)-1)) #define _mm256_mask_getmant_ps(W, U, A, B, C) \ - (__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8sf)(__m256)(W), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8sf)(__m256)(W), \ + (__mmask8)(U))) #define _mm256_maskz_getmant_ps(U, A, B, C) \ - (__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ - (int)(((C)<<2) | (B)), \ - (__v8sf)_mm256_setzero_ps(), \ - (__mmask8)(U)) + ((__m256)__builtin_ia32_getmantps256_mask((__v8sf)(__m256)(A), \ + (int)(((C)<<2) | (B)), \ + (__v8sf)_mm256_setzero_ps(), \ + (__mmask8)(U))) #define _mm_mmask_i64gather_pd(v1_old, mask, index, addr, scale) \ - (__m128d)__builtin_ia32_gather3div2df((__v2df)(__m128d)(v1_old), \ - (void const *)(addr), \ - (__v2di)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m128d)__builtin_ia32_gather3div2df((__v2df)(__m128d)(v1_old), \ + (void const *)(addr), \ + (__v2di)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm_mmask_i64gather_epi64(v1_old, mask, index, addr, scale) \ - (__m128i)__builtin_ia32_gather3div2di((__v2di)(__m128i)(v1_old), \ - (void const *)(addr), \ - (__v2di)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m128i)__builtin_ia32_gather3div2di((__v2di)(__m128i)(v1_old), \ + (void const *)(addr), \ + (__v2di)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i64gather_pd(v1_old, mask, index, addr, scale) \ - (__m256d)__builtin_ia32_gather3div4df((__v4df)(__m256d)(v1_old), \ - (void const *)(addr), \ - (__v4di)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256d)__builtin_ia32_gather3div4df((__v4df)(__m256d)(v1_old), \ + (void const *)(addr), \ + (__v4di)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i64gather_epi64(v1_old, mask, index, addr, scale) \ - (__m256i)__builtin_ia32_gather3div4di((__v4di)(__m256i)(v1_old), \ - (void const *)(addr), \ - (__v4di)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256i)__builtin_ia32_gather3div4di((__v4di)(__m256i)(v1_old), \ + (void const *)(addr), \ + (__v4di)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm_mmask_i64gather_ps(v1_old, mask, index, addr, scale) \ - (__m128)__builtin_ia32_gather3div4sf((__v4sf)(__m128)(v1_old), \ - (void const *)(addr), \ - (__v2di)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) - -#define _mm_mmask_i64gather_epi32(v1_old, mask, index, addr, scale) \ - (__m128i)__builtin_ia32_gather3div4si((__v4si)(__m128i)(v1_old), \ + ((__m128)__builtin_ia32_gather3div4sf((__v4sf)(__m128)(v1_old), \ (void const *)(addr), \ (__v2di)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + (__mmask8)(mask), (int)(scale))) + +#define _mm_mmask_i64gather_epi32(v1_old, mask, index, addr, scale) \ + ((__m128i)__builtin_ia32_gather3div4si((__v4si)(__m128i)(v1_old), \ + (void const *)(addr), \ + (__v2di)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i64gather_ps(v1_old, mask, index, addr, scale) \ - (__m128)__builtin_ia32_gather3div8sf((__v4sf)(__m128)(v1_old), \ - (void const *)(addr), \ - (__v4di)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) - -#define _mm256_mmask_i64gather_epi32(v1_old, mask, index, addr, scale) \ - (__m128i)__builtin_ia32_gather3div8si((__v4si)(__m128i)(v1_old), \ + ((__m128)__builtin_ia32_gather3div8sf((__v4sf)(__m128)(v1_old), \ (void const *)(addr), \ (__v4di)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + (__mmask8)(mask), (int)(scale))) + +#define _mm256_mmask_i64gather_epi32(v1_old, mask, index, addr, scale) \ + ((__m128i)__builtin_ia32_gather3div8si((__v4si)(__m128i)(v1_old), \ + (void const *)(addr), \ + (__v4di)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm_mmask_i32gather_pd(v1_old, mask, index, addr, scale) \ - (__m128d)__builtin_ia32_gather3siv2df((__v2df)(__m128d)(v1_old), \ - (void const *)(addr), \ - (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m128d)__builtin_ia32_gather3siv2df((__v2df)(__m128d)(v1_old), \ + (void const *)(addr), \ + (__v4si)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm_mmask_i32gather_epi64(v1_old, mask, index, addr, scale) \ - (__m128i)__builtin_ia32_gather3siv2di((__v2di)(__m128i)(v1_old), \ - (void const *)(addr), \ - (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m128i)__builtin_ia32_gather3siv2di((__v2di)(__m128i)(v1_old), \ + (void const *)(addr), \ + (__v4si)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i32gather_pd(v1_old, mask, index, addr, scale) \ - (__m256d)__builtin_ia32_gather3siv4df((__v4df)(__m256d)(v1_old), \ - (void const *)(addr), \ - (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256d)__builtin_ia32_gather3siv4df((__v4df)(__m256d)(v1_old), \ + (void const *)(addr), \ + (__v4si)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i32gather_epi64(v1_old, mask, index, addr, scale) \ - (__m256i)__builtin_ia32_gather3siv4di((__v4di)(__m256i)(v1_old), \ - (void const *)(addr), \ - (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + ((__m256i)__builtin_ia32_gather3siv4di((__v4di)(__m256i)(v1_old), \ + (void const *)(addr), \ + (__v4si)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm_mmask_i32gather_ps(v1_old, mask, index, addr, scale) \ - (__m128)__builtin_ia32_gather3siv4sf((__v4sf)(__m128)(v1_old), \ - (void const *)(addr), \ - (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) - -#define _mm_mmask_i32gather_epi32(v1_old, mask, index, addr, scale) \ - (__m128i)__builtin_ia32_gather3siv4si((__v4si)(__m128i)(v1_old), \ + ((__m128)__builtin_ia32_gather3siv4sf((__v4sf)(__m128)(v1_old), \ (void const *)(addr), \ (__v4si)(__m128i)(index), \ - (__mmask8)(mask), (int)(scale)) + (__mmask8)(mask), (int)(scale))) + +#define _mm_mmask_i32gather_epi32(v1_old, mask, index, addr, scale) \ + ((__m128i)__builtin_ia32_gather3siv4si((__v4si)(__m128i)(v1_old), \ + (void const *)(addr), \ + (__v4si)(__m128i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_mmask_i32gather_ps(v1_old, mask, index, addr, scale) \ - (__m256)__builtin_ia32_gather3siv8sf((__v8sf)(__m256)(v1_old), \ - (void const *)(addr), \ - (__v8si)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) - -#define _mm256_mmask_i32gather_epi32(v1_old, mask, index, addr, scale) \ - (__m256i)__builtin_ia32_gather3siv8si((__v8si)(__m256i)(v1_old), \ + ((__m256)__builtin_ia32_gather3siv8sf((__v8sf)(__m256)(v1_old), \ (void const *)(addr), \ (__v8si)(__m256i)(index), \ - (__mmask8)(mask), (int)(scale)) + (__mmask8)(mask), (int)(scale))) + +#define _mm256_mmask_i32gather_epi32(v1_old, mask, index, addr, scale) \ + ((__m256i)__builtin_ia32_gather3siv8si((__v8si)(__m256i)(v1_old), \ + (void const *)(addr), \ + (__v8si)(__m256i)(index), \ + (__mmask8)(mask), (int)(scale))) #define _mm256_permutex_pd(X, C) \ - (__m256d)__builtin_ia32_permdf256((__v4df)(__m256d)(X), (int)(C)) + ((__m256d)__builtin_ia32_permdf256((__v4df)(__m256d)(X), (int)(C))) #define _mm256_mask_permutex_pd(W, U, X, C) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ (__v4df)_mm256_permutex_pd((X), (C)), \ - (__v4df)(__m256d)(W)) + (__v4df)(__m256d)(W))) #define _mm256_maskz_permutex_pd(U, X, C) \ - (__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ - (__v4df)_mm256_permutex_pd((X), (C)), \ - (__v4df)_mm256_setzero_pd()) + ((__m256d)__builtin_ia32_selectpd_256((__mmask8)(U), \ + (__v4df)_mm256_permutex_pd((X), (C)), \ + (__v4df)_mm256_setzero_pd())) #define _mm256_permutex_epi64(X, C) \ - (__m256i)__builtin_ia32_permdi256((__v4di)(__m256i)(X), (int)(C)) + ((__m256i)__builtin_ia32_permdi256((__v4di)(__m256i)(X), (int)(C))) #define _mm256_mask_permutex_epi64(W, U, X, C) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ (__v4di)_mm256_permutex_epi64((X), (C)), \ - (__v4di)(__m256i)(W)) + (__v4di)(__m256i)(W))) #define _mm256_maskz_permutex_epi64(U, X, C) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ (__v4di)_mm256_permutex_epi64((X), (C)), \ - (__v4di)_mm256_setzero_si256()) + (__v4di)_mm256_setzero_si256())) static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_permutexvar_pd (__m256i __X, __m256d __Y) @@ -8175,60 +8175,60 @@ _mm256_maskz_permutexvar_epi32(__mmask8 __M, __m256i __X, __m256i __Y) } #define _mm_alignr_epi32(A, B, imm) \ - (__m128i)__builtin_ia32_alignd128((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), (int)(imm)) + ((__m128i)__builtin_ia32_alignd128((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), (int)(imm))) #define _mm_mask_alignr_epi32(W, U, A, B, imm) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ (__v4si)_mm_alignr_epi32((A), (B), (imm)), \ - (__v4si)(__m128i)(W)) + (__v4si)(__m128i)(W))) #define _mm_maskz_alignr_epi32(U, A, B, imm) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ (__v4si)_mm_alignr_epi32((A), (B), (imm)), \ - (__v4si)_mm_setzero_si128()) + (__v4si)_mm_setzero_si128())) #define _mm256_alignr_epi32(A, B, imm) \ - (__m256i)__builtin_ia32_alignd256((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_alignd256((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), (int)(imm))) #define _mm256_mask_alignr_epi32(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ (__v8si)_mm256_alignr_epi32((A), (B), (imm)), \ - (__v8si)(__m256i)(W)) + (__v8si)(__m256i)(W))) #define _mm256_maskz_alignr_epi32(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ (__v8si)_mm256_alignr_epi32((A), (B), (imm)), \ - (__v8si)_mm256_setzero_si256()) + (__v8si)_mm256_setzero_si256())) #define _mm_alignr_epi64(A, B, imm) \ - (__m128i)__builtin_ia32_alignq128((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), (int)(imm)) + ((__m128i)__builtin_ia32_alignq128((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), (int)(imm))) #define _mm_mask_alignr_epi64(W, U, A, B, imm) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ (__v2di)_mm_alignr_epi64((A), (B), (imm)), \ - (__v2di)(__m128i)(W)) + (__v2di)(__m128i)(W))) #define _mm_maskz_alignr_epi64(U, A, B, imm) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ (__v2di)_mm_alignr_epi64((A), (B), (imm)), \ - (__v2di)_mm_setzero_si128()) + (__v2di)_mm_setzero_si128())) #define _mm256_alignr_epi64(A, B, imm) \ - (__m256i)__builtin_ia32_alignq256((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), (int)(imm)) + ((__m256i)__builtin_ia32_alignq256((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), (int)(imm))) #define _mm256_mask_alignr_epi64(W, U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ (__v4di)_mm256_alignr_epi64((A), (B), (imm)), \ - (__v4di)(__m256i)(W)) + (__v4di)(__m256i)(W))) #define _mm256_maskz_alignr_epi64(U, A, B, imm) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ (__v4di)_mm256_alignr_epi64((A), (B), (imm)), \ - (__v4di)_mm256_setzero_si256()) + (__v4di)_mm256_setzero_si256())) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_movehdup_ps (__m128 __W, __mmask8 __U, __m128 __A) @@ -8295,24 +8295,24 @@ _mm256_maskz_moveldup_ps (__mmask8 __U, __m256 __A) } #define _mm256_mask_shuffle_epi32(W, U, A, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shuffle_epi32((A), (I)), \ - (__v8si)(__m256i)(W)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_epi32((A), (I)), \ + (__v8si)(__m256i)(W))) #define _mm256_maskz_shuffle_epi32(U, A, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shuffle_epi32((A), (I)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shuffle_epi32((A), (I)), \ + (__v8si)_mm256_setzero_si256())) #define _mm_mask_shuffle_epi32(W, U, A, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shuffle_epi32((A), (I)), \ - (__v4si)(__m128i)(W)) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shuffle_epi32((A), (I)), \ + (__v4si)(__m128i)(W))) #define _mm_maskz_shuffle_epi32(U, A, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shuffle_epi32((A), (I)), \ - (__v4si)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shuffle_epi32((A), (I)), \ + (__v4si)_mm_setzero_si128())) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_mov_pd (__m128d __W, __mmask8 __U, __m128d __A) @@ -8413,27 +8413,27 @@ _mm256_maskz_cvtph_ps (__mmask8 __U, __m128i __A) } #define _mm_mask_cvt_roundps_ph(W, U, A, I) \ - (__m128i)__builtin_ia32_vcvtps2ph_mask((__v4sf)(__m128)(A), (int)(I), \ - (__v8hi)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_vcvtps2ph_mask((__v4sf)(__m128)(A), (int)(I), \ + (__v8hi)(__m128i)(W), \ + (__mmask8)(U))) #define _mm_maskz_cvt_roundps_ph(U, A, I) \ - (__m128i)__builtin_ia32_vcvtps2ph_mask((__v4sf)(__m128)(A), (int)(I), \ - (__v8hi)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_vcvtps2ph_mask((__v4sf)(__m128)(A), (int)(I), \ + (__v8hi)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm_mask_cvtps_ph _mm_mask_cvt_roundps_ph #define _mm_maskz_cvtps_ph _mm_maskz_cvt_roundps_ph #define _mm256_mask_cvt_roundps_ph(W, U, A, I) \ - (__m128i)__builtin_ia32_vcvtps2ph256_mask((__v8sf)(__m256)(A), (int)(I), \ - (__v8hi)(__m128i)(W), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_vcvtps2ph256_mask((__v8sf)(__m256)(A), (int)(I), \ + (__v8hi)(__m128i)(W), \ + (__mmask8)(U))) #define _mm256_maskz_cvt_roundps_ph(U, A, I) \ - (__m128i)__builtin_ia32_vcvtps2ph256_mask((__v8sf)(__m256)(A), (int)(I), \ - (__v8hi)_mm_setzero_si128(), \ - (__mmask8)(U)) + ((__m128i)__builtin_ia32_vcvtps2ph256_mask((__v8sf)(__m256)(A), (int)(I), \ + (__v8hi)_mm_setzero_si128(), \ + (__mmask8)(U))) #define _mm256_mask_cvtps_ph _mm256_mask_cvt_roundps_ph #define _mm256_maskz_cvtps_ph _mm256_maskz_cvt_roundps_ph diff --git a/clang/lib/Headers/avx512vlvbmi2intrin.h b/clang/lib/Headers/avx512vlvbmi2intrin.h index a40f926de75..fac1f232415 100644 --- a/clang/lib/Headers/avx512vlvbmi2intrin.h +++ b/clang/lib/Headers/avx512vlvbmi2intrin.h @@ -239,172 +239,172 @@ _mm256_maskz_expandloadu_epi8(__mmask32 __U, void const *__P) } #define _mm256_shldi_epi64(A, B, I) \ - (__m256i)__builtin_ia32_vpshldq256((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshldq256((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), (int)(I))) #define _mm256_mask_shldi_epi64(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shldi_epi64((A), (B), (I)), \ - (__v4di)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shldi_epi64((A), (B), (I)), \ + (__v4di)(__m256i)(S))) #define _mm256_maskz_shldi_epi64(U, A, B, I) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shldi_epi64((A), (B), (I)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shldi_epi64((A), (B), (I)), \ + (__v4di)_mm256_setzero_si256())) #define _mm_shldi_epi64(A, B, I) \ - (__m128i)__builtin_ia32_vpshldq128((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshldq128((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), (int)(I))) #define _mm_mask_shldi_epi64(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ - (__v2di)_mm_shldi_epi64((A), (B), (I)), \ - (__v2di)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + (__v2di)_mm_shldi_epi64((A), (B), (I)), \ + (__v2di)(__m128i)(S))) #define _mm_maskz_shldi_epi64(U, A, B, I) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ - (__v2di)_mm_shldi_epi64((A), (B), (I)), \ - (__v2di)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + (__v2di)_mm_shldi_epi64((A), (B), (I)), \ + (__v2di)_mm_setzero_si128())) #define _mm256_shldi_epi32(A, B, I) \ - (__m256i)__builtin_ia32_vpshldd256((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshldd256((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), (int)(I))) #define _mm256_mask_shldi_epi32(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shldi_epi32((A), (B), (I)), \ - (__v8si)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shldi_epi32((A), (B), (I)), \ + (__v8si)(__m256i)(S))) #define _mm256_maskz_shldi_epi32(U, A, B, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shldi_epi32((A), (B), (I)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shldi_epi32((A), (B), (I)), \ + (__v8si)_mm256_setzero_si256())) #define _mm_shldi_epi32(A, B, I) \ - (__m128i)__builtin_ia32_vpshldd128((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshldd128((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), (int)(I))) #define _mm_mask_shldi_epi32(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shldi_epi32((A), (B), (I)), \ - (__v4si)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shldi_epi32((A), (B), (I)), \ + (__v4si)(__m128i)(S))) #define _mm_maskz_shldi_epi32(U, A, B, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shldi_epi32((A), (B), (I)), \ - (__v4si)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shldi_epi32((A), (B), (I)), \ + (__v4si)_mm_setzero_si128())) #define _mm256_shldi_epi16(A, B, I) \ - (__m256i)__builtin_ia32_vpshldw256((__v16hi)(__m256i)(A), \ - (__v16hi)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshldw256((__v16hi)(__m256i)(A), \ + (__v16hi)(__m256i)(B), (int)(I))) #define _mm256_mask_shldi_epi16(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shldi_epi16((A), (B), (I)), \ - (__v16hi)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shldi_epi16((A), (B), (I)), \ + (__v16hi)(__m256i)(S))) #define _mm256_maskz_shldi_epi16(U, A, B, I) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shldi_epi16((A), (B), (I)), \ - (__v16hi)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shldi_epi16((A), (B), (I)), \ + (__v16hi)_mm256_setzero_si256())) #define _mm_shldi_epi16(A, B, I) \ - (__m128i)__builtin_ia32_vpshldw128((__v8hi)(__m128i)(A), \ - (__v8hi)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshldw128((__v8hi)(__m128i)(A), \ + (__v8hi)(__m128i)(B), (int)(I))) #define _mm_mask_shldi_epi16(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shldi_epi16((A), (B), (I)), \ - (__v8hi)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shldi_epi16((A), (B), (I)), \ + (__v8hi)(__m128i)(S))) #define _mm_maskz_shldi_epi16(U, A, B, I) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shldi_epi16((A), (B), (I)), \ - (__v8hi)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shldi_epi16((A), (B), (I)), \ + (__v8hi)_mm_setzero_si128())) #define _mm256_shrdi_epi64(A, B, I) \ - (__m256i)__builtin_ia32_vpshrdq256((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshrdq256((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), (int)(I))) #define _mm256_mask_shrdi_epi64(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shrdi_epi64((A), (B), (I)), \ - (__v4di)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shrdi_epi64((A), (B), (I)), \ + (__v4di)(__m256i)(S))) #define _mm256_maskz_shrdi_epi64(U, A, B, I) \ - (__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ - (__v4di)_mm256_shrdi_epi64((A), (B), (I)), \ - (__v4di)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectq_256((__mmask8)(U), \ + (__v4di)_mm256_shrdi_epi64((A), (B), (I)), \ + (__v4di)_mm256_setzero_si256())) #define _mm_shrdi_epi64(A, B, I) \ - (__m128i)__builtin_ia32_vpshrdq128((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshrdq128((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), (int)(I))) #define _mm_mask_shrdi_epi64(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ - (__v2di)_mm_shrdi_epi64((A), (B), (I)), \ - (__v2di)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + (__v2di)_mm_shrdi_epi64((A), (B), (I)), \ + (__v2di)(__m128i)(S))) #define _mm_maskz_shrdi_epi64(U, A, B, I) \ - (__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ - (__v2di)_mm_shrdi_epi64((A), (B), (I)), \ - (__v2di)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectq_128((__mmask8)(U), \ + (__v2di)_mm_shrdi_epi64((A), (B), (I)), \ + (__v2di)_mm_setzero_si128())) #define _mm256_shrdi_epi32(A, B, I) \ - (__m256i)__builtin_ia32_vpshrdd256((__v8si)(__m256i)(A), \ - (__v8si)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshrdd256((__v8si)(__m256i)(A), \ + (__v8si)(__m256i)(B), (int)(I))) #define _mm256_mask_shrdi_epi32(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shrdi_epi32((A), (B), (I)), \ - (__v8si)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shrdi_epi32((A), (B), (I)), \ + (__v8si)(__m256i)(S))) #define _mm256_maskz_shrdi_epi32(U, A, B, I) \ - (__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ - (__v8si)_mm256_shrdi_epi32((A), (B), (I)), \ - (__v8si)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectd_256((__mmask8)(U), \ + (__v8si)_mm256_shrdi_epi32((A), (B), (I)), \ + (__v8si)_mm256_setzero_si256())) #define _mm_shrdi_epi32(A, B, I) \ - (__m128i)__builtin_ia32_vpshrdd128((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshrdd128((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), (int)(I))) #define _mm_mask_shrdi_epi32(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shrdi_epi32((A), (B), (I)), \ - (__v4si)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shrdi_epi32((A), (B), (I)), \ + (__v4si)(__m128i)(S))) #define _mm_maskz_shrdi_epi32(U, A, B, I) \ - (__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ - (__v4si)_mm_shrdi_epi32((A), (B), (I)), \ - (__v4si)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectd_128((__mmask8)(U), \ + (__v4si)_mm_shrdi_epi32((A), (B), (I)), \ + (__v4si)_mm_setzero_si128())) #define _mm256_shrdi_epi16(A, B, I) \ - (__m256i)__builtin_ia32_vpshrdw256((__v16hi)(__m256i)(A), \ - (__v16hi)(__m256i)(B), (int)(I)) + ((__m256i)__builtin_ia32_vpshrdw256((__v16hi)(__m256i)(A), \ + (__v16hi)(__m256i)(B), (int)(I))) #define _mm256_mask_shrdi_epi16(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shrdi_epi16((A), (B), (I)), \ - (__v16hi)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shrdi_epi16((A), (B), (I)), \ + (__v16hi)(__m256i)(S))) #define _mm256_maskz_shrdi_epi16(U, A, B, I) \ - (__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ - (__v16hi)_mm256_shrdi_epi16((A), (B), (I)), \ - (__v16hi)_mm256_setzero_si256()) + ((__m256i)__builtin_ia32_selectw_256((__mmask16)(U), \ + (__v16hi)_mm256_shrdi_epi16((A), (B), (I)), \ + (__v16hi)_mm256_setzero_si256())) #define _mm_shrdi_epi16(A, B, I) \ - (__m128i)__builtin_ia32_vpshrdw128((__v8hi)(__m128i)(A), \ - (__v8hi)(__m128i)(B), (int)(I)) + ((__m128i)__builtin_ia32_vpshrdw128((__v8hi)(__m128i)(A), \ + (__v8hi)(__m128i)(B), (int)(I))) #define _mm_mask_shrdi_epi16(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shrdi_epi16((A), (B), (I)), \ - (__v8hi)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shrdi_epi16((A), (B), (I)), \ + (__v8hi)(__m128i)(S))) #define _mm_maskz_shrdi_epi16(U, A, B, I) \ - (__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ - (__v8hi)_mm_shrdi_epi16((A), (B), (I)), \ - (__v8hi)_mm_setzero_si128()) + ((__m128i)__builtin_ia32_selectw_128((__mmask8)(U), \ + (__v8hi)_mm_shrdi_epi16((A), (B), (I)), \ + (__v8hi)_mm_setzero_si128())) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_shldv_epi64(__m256i __A, __m256i __B, __m256i __C) diff --git a/clang/lib/Headers/avx512vlvnniintrin.h b/clang/lib/Headers/avx512vlvnniintrin.h index 71ac1b4370d..0fb29af262f 100644 --- a/clang/lib/Headers/avx512vlvnniintrin.h +++ b/clang/lib/Headers/avx512vlvnniintrin.h @@ -36,7 +36,7 @@ /// DST[MAX:256] := 0 /// \endoperation #define _mm256_dpbusd_epi32(S, A, B) \ - (__m256i)__builtin_ia32_vpdpbusd256((__v8si)(S), (__v8si)(A), (__v8si)(B)) + ((__m256i)__builtin_ia32_vpdpbusd256((__v8si)(S), (__v8si)(A), (__v8si)(B))) /// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a A with /// corresponding signed 8-bit integers in \a B, producing 4 intermediate signed @@ -56,7 +56,7 @@ /// DST[MAX:256] := 0 /// \endoperation #define _mm256_dpbusds_epi32(S, A, B) \ - (__m256i)__builtin_ia32_vpdpbusds256((__v8si)(S), (__v8si)(A), (__v8si)(B)) + ((__m256i)__builtin_ia32_vpdpbusds256((__v8si)(S), (__v8si)(A), (__v8si)(B))) /// Multiply groups of 2 adjacent pairs of signed 16-bit integers in \a A with /// corresponding 16-bit integers in \a B, producing 2 intermediate signed 32-bit @@ -74,7 +74,7 @@ /// DST[MAX:256] := 0 /// \endoperation #define _mm256_dpwssd_epi32(S, A, B) \ - (__m256i)__builtin_ia32_vpdpwssd256((__v8si)(S), (__v8si)(A), (__v8si)(B)) + ((__m256i)__builtin_ia32_vpdpwssd256((__v8si)(S), (__v8si)(A), (__v8si)(B))) /// Multiply groups of 2 adjacent pairs of signed 16-bit integers in \a A with /// corresponding 16-bit integers in \a B, producing 2 intermediate signed 32-bit @@ -92,7 +92,7 @@ /// DST[MAX:256] := 0 /// \endoperation #define _mm256_dpwssds_epi32(S, A, B) \ - (__m256i)__builtin_ia32_vpdpwssds256((__v8si)(S), (__v8si)(A), (__v8si)(B)) + ((__m256i)__builtin_ia32_vpdpwssds256((__v8si)(S), (__v8si)(A), (__v8si)(B))) /// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a A with /// corresponding signed 8-bit integers in \a B, producing 4 intermediate signed @@ -112,7 +112,7 @@ /// DST[MAX:128] := 0 /// \endoperation #define _mm_dpbusd_epi32(S, A, B) \ - (__m128i)__builtin_ia32_vpdpbusd128((__v4si)(S), (__v4si)(A), (__v4si)(B)) + ((__m128i)__builtin_ia32_vpdpbusd128((__v4si)(S), (__v4si)(A), (__v4si)(B))) /// Multiply groups of 4 adjacent pairs of unsigned 8-bit integers in \a A with /// corresponding signed 8-bit integers in \a B, producing 4 intermediate signed @@ -132,7 +132,7 @@ /// DST[MAX:128] := 0 /// \endoperation #define _mm_dpbusds_epi32(S, A, B) \ - (__m128i)__builtin_ia32_vpdpbusds128((__v4si)(S), (__v4si)(A), (__v4si)(B)) + ((__m128i)__builtin_ia32_vpdpbusds128((__v4si)(S), (__v4si)(A), (__v4si)(B))) /// Multiply groups of 2 adjacent pairs of signed 16-bit integers in \a A with /// corresponding 16-bit integers in \a B, producing 2 intermediate signed 32-bit @@ -150,7 +150,7 @@ /// DST[MAX:128] := 0 /// \endoperation #define _mm_dpwssd_epi32(S, A, B) \ - (__m128i)__builtin_ia32_vpdpwssd128((__v4si)(S), (__v4si)(A), (__v4si)(B)) + ((__m128i)__builtin_ia32_vpdpwssd128((__v4si)(S), (__v4si)(A), (__v4si)(B))) /// Multiply groups of 2 adjacent pairs of signed 16-bit integers in \a A with /// corresponding 16-bit integers in \a B, producing 2 intermediate signed 32-bit @@ -168,7 +168,7 @@ /// DST[MAX:128] := 0 /// \endoperation #define _mm_dpwssds_epi32(S, A, B) \ - (__m128i)__builtin_ia32_vpdpwssds128((__v4si)(S), (__v4si)(A), (__v4si)(B)) + ((__m128i)__builtin_ia32_vpdpwssds128((__v4si)(S), (__v4si)(A), (__v4si)(B))) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_dpbusd_epi32(__m256i __S, __mmask8 __U, __m256i __A, __m256i __B) diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h index 382b6215751..17fe6369117 100644 --- a/clang/lib/Headers/avxintrin.h +++ b/clang/lib/Headers/avxintrin.h @@ -400,7 +400,7 @@ _mm256_rcp_ps(__m256 __a) /// 11: Truncated. /// \returns A 256-bit vector of [4 x double] containing the rounded values. #define _mm256_round_pd(V, M) \ - (__m256d)__builtin_ia32_roundpd256((__v4df)(__m256d)(V), (M)) + ((__m256d)__builtin_ia32_roundpd256((__v4df)(__m256d)(V), (M))) /// Rounds the values stored in a 256-bit vector of [8 x float] as /// specified by the byte operand. The source values are rounded to integer @@ -432,7 +432,7 @@ _mm256_rcp_ps(__m256 __a) /// 11: Truncated. /// \returns A 256-bit vector of [8 x float] containing the rounded values. #define _mm256_round_ps(V, M) \ - (__m256)__builtin_ia32_roundps256((__v8sf)(__m256)(V), (M)) + ((__m256)__builtin_ia32_roundps256((__v8sf)(__m256)(V), (M))) /// Rounds up the values stored in a 256-bit vector of [4 x double]. The /// source values are rounded up to integer values and returned as 64-bit @@ -989,7 +989,7 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// returned vector. /// \returns A 128-bit vector of [2 x double] containing the copied values. #define _mm_permute_pd(A, C) \ - (__m128d)__builtin_ia32_vpermilpd((__v2df)(__m128d)(A), (int)(C)) + ((__m128d)__builtin_ia32_vpermilpd((__v2df)(__m128d)(A), (int)(C))) /// Copies the values in a 256-bit vector of [4 x double] as specified by /// the immediate integer operand. @@ -1029,7 +1029,7 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// returned vector. /// \returns A 256-bit vector of [4 x double] containing the copied values. #define _mm256_permute_pd(A, C) \ - (__m256d)__builtin_ia32_vpermilpd256((__v4df)(__m256d)(A), (int)(C)) + ((__m256d)__builtin_ia32_vpermilpd256((__v4df)(__m256d)(A), (int)(C))) /// Copies the values in a 128-bit vector of [4 x float] as specified by /// the immediate integer operand. @@ -1085,7 +1085,7 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// returned vector. /// \returns A 128-bit vector of [4 x float] containing the copied values. #define _mm_permute_ps(A, C) \ - (__m128)__builtin_ia32_vpermilps((__v4sf)(__m128)(A), (int)(C)) + ((__m128)__builtin_ia32_vpermilps((__v4sf)(__m128)(A), (int)(C))) /// Copies the values in a 256-bit vector of [8 x float] as specified by /// the immediate integer operand. @@ -1177,7 +1177,7 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// returned vector. /// \returns A 256-bit vector of [8 x float] containing the copied values. #define _mm256_permute_ps(A, C) \ - (__m256)__builtin_ia32_vpermilps256((__v8sf)(__m256)(A), (int)(C)) + ((__m256)__builtin_ia32_vpermilps256((__v8sf)(__m256)(A), (int)(C))) /// Permutes 128-bit data values stored in two 256-bit vectors of /// [4 x double], as specified by the immediate integer operand. @@ -1217,8 +1217,8 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// destination. /// \returns A 256-bit vector of [4 x double] containing the copied values. #define _mm256_permute2f128_pd(V1, V2, M) \ - (__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)(__m256d)(V1), \ - (__v4df)(__m256d)(V2), (int)(M)) + ((__m256d)__builtin_ia32_vperm2f128_pd256((__v4df)(__m256d)(V1), \ + (__v4df)(__m256d)(V2), (int)(M))) /// Permutes 128-bit data values stored in two 256-bit vectors of /// [8 x float], as specified by the immediate integer operand. @@ -1258,8 +1258,8 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// destination. /// \returns A 256-bit vector of [8 x float] containing the copied values. #define _mm256_permute2f128_ps(V1, V2, M) \ - (__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)(__m256)(V1), \ - (__v8sf)(__m256)(V2), (int)(M)) + ((__m256)__builtin_ia32_vperm2f128_ps256((__v8sf)(__m256)(V1), \ + (__v8sf)(__m256)(V2), (int)(M))) /// Permutes 128-bit data values stored in two 256-bit integer vectors, /// as specified by the immediate integer operand. @@ -1298,8 +1298,8 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// destination. /// \returns A 256-bit integer vector containing the copied values. #define _mm256_permute2f128_si256(V1, V2, M) \ - (__m256i)__builtin_ia32_vperm2f128_si256((__v8si)(__m256i)(V1), \ - (__v8si)(__m256i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_vperm2f128_si256((__v8si)(__m256i)(V1), \ + (__v8si)(__m256i)(V2), (int)(M))) /* Vector Blend */ /// Merges 64-bit double-precision data values stored in either of the @@ -1327,8 +1327,8 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// operand \a V2 is copied to the same position in the destination. /// \returns A 256-bit vector of [4 x double] containing the copied values. #define _mm256_blend_pd(V1, V2, M) \ - (__m256d)__builtin_ia32_blendpd256((__v4df)(__m256d)(V1), \ - (__v4df)(__m256d)(V2), (int)(M)) + ((__m256d)__builtin_ia32_blendpd256((__v4df)(__m256d)(V1), \ + (__v4df)(__m256d)(V2), (int)(M))) /// Merges 32-bit single-precision data values stored in either of the /// two 256-bit vectors of [8 x float], as specified by the immediate @@ -1355,8 +1355,8 @@ _mm256_permutevar_ps(__m256 __a, __m256i __c) /// operand \a V2 is copied to the same position in the destination. /// \returns A 256-bit vector of [8 x float] containing the copied values. #define _mm256_blend_ps(V1, V2, M) \ - (__m256)__builtin_ia32_blendps256((__v8sf)(__m256)(V1), \ - (__v8sf)(__m256)(V2), (int)(M)) + ((__m256)__builtin_ia32_blendps256((__v8sf)(__m256)(V1), \ + (__v8sf)(__m256)(V2), (int)(M))) /// Merges 64-bit double-precision data values stored in either of the /// two 256-bit vectors of [4 x double], as specified by the 256-bit vector @@ -1453,8 +1453,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// two parallel dot product computations. /// \returns A 256-bit vector of [8 x float] containing the two dot products. #define _mm256_dp_ps(V1, V2, M) \ - (__m256)__builtin_ia32_dpps256((__v8sf)(__m256)(V1), \ - (__v8sf)(__m256)(V2), (M)) + ((__m256)__builtin_ia32_dpps256((__v8sf)(__m256)(V1), \ + (__v8sf)(__m256)(V2), (M))) /* Vector shuffle */ /// Selects 8 float values from the 256-bit operands of [8 x float], as @@ -1507,8 +1507,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 11: Bits [127:96] and [255:224] are copied from the selected operand. /// \returns A 256-bit vector of [8 x float] containing the shuffled values. #define _mm256_shuffle_ps(a, b, mask) \ - (__m256)__builtin_ia32_shufps256((__v8sf)(__m256)(a), \ - (__v8sf)(__m256)(b), (int)(mask)) + ((__m256)__builtin_ia32_shufps256((__v8sf)(__m256)(a), \ + (__v8sf)(__m256)(b), (int)(mask))) /// Selects four double-precision values from the 256-bit operands of /// [4 x double], as specified by the immediate value operand. @@ -1553,8 +1553,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// destination. /// \returns A 256-bit vector of [4 x double] containing the shuffled values. #define _mm256_shuffle_pd(a, b, mask) \ - (__m256d)__builtin_ia32_shufpd256((__v4df)(__m256d)(a), \ - (__v4df)(__m256d)(b), (int)(mask)) + ((__m256d)__builtin_ia32_shufpd256((__v4df)(__m256d)(a), \ + (__v4df)(__m256d)(b), (int)(mask))) /* Compare */ #define _CMP_EQ_OQ 0x00 /* Equal (ordered, non-signaling) */ @@ -1647,8 +1647,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 128-bit vector of [2 x double] containing the comparison results. #define _mm_cmp_pd(a, b, c) \ - (__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \ - (__v2df)(__m128d)(b), (c)) + ((__m128d)__builtin_ia32_cmppd((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (c))) /// Compares each of the corresponding values of two 128-bit vectors of /// [4 x float], using the operation specified by the immediate integer @@ -1707,8 +1707,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 128-bit vector of [4 x float] containing the comparison results. #define _mm_cmp_ps(a, b, c) \ - (__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \ - (__v4sf)(__m128)(b), (c)) + ((__m128)__builtin_ia32_cmpps((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (c))) /// Compares each of the corresponding double-precision values of two /// 256-bit vectors of [4 x double], using the operation specified by the @@ -1767,8 +1767,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 256-bit vector of [4 x double] containing the comparison results. #define _mm256_cmp_pd(a, b, c) \ - (__m256d)__builtin_ia32_cmppd256((__v4df)(__m256d)(a), \ - (__v4df)(__m256d)(b), (c)) + ((__m256d)__builtin_ia32_cmppd256((__v4df)(__m256d)(a), \ + (__v4df)(__m256d)(b), (c))) /// Compares each of the corresponding values of two 256-bit vectors of /// [8 x float], using the operation specified by the immediate integer @@ -1827,8 +1827,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 256-bit vector of [8 x float] containing the comparison results. #define _mm256_cmp_ps(a, b, c) \ - (__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \ - (__v8sf)(__m256)(b), (c)) + ((__m256)__builtin_ia32_cmpps256((__v8sf)(__m256)(a), \ + (__v8sf)(__m256)(b), (c))) /// Compares each of the corresponding scalar double-precision values of /// two 128-bit vectors of [2 x double], using the operation specified by the @@ -1886,8 +1886,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 128-bit vector of [2 x double] containing the comparison results. #define _mm_cmp_sd(a, b, c) \ - (__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \ - (__v2df)(__m128d)(b), (c)) + ((__m128d)__builtin_ia32_cmpsd((__v2df)(__m128d)(a), \ + (__v2df)(__m128d)(b), (c))) /// Compares each of the corresponding scalar values of two 128-bit /// vectors of [4 x float], using the operation specified by the immediate @@ -1945,8 +1945,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// 0x1F: True (unordered, signaling) /// \returns A 128-bit vector of [4 x float] containing the comparison results. #define _mm_cmp_ss(a, b, c) \ - (__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \ - (__v4sf)(__m128)(b), (c)) + ((__m128)__builtin_ia32_cmpss((__v4sf)(__m128)(a), \ + (__v4sf)(__m128)(b), (c))) /// Takes a [8 x i32] vector and returns the vector element value /// indexed by the immediate constant operand. @@ -1964,7 +1964,7 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A 32-bit integer containing the extracted 32 bits of extended /// packed data. #define _mm256_extract_epi32(X, N) \ - (int)__builtin_ia32_vec_ext_v8si((__v8si)(__m256i)(X), (int)(N)) + ((int)__builtin_ia32_vec_ext_v8si((__v8si)(__m256i)(X), (int)(N))) /// Takes a [16 x i16] vector and returns the vector element value /// indexed by the immediate constant operand. @@ -1982,8 +1982,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A 32-bit integer containing the extracted 16 bits of zero extended /// packed data. #define _mm256_extract_epi16(X, N) \ - (int)(unsigned short)__builtin_ia32_vec_ext_v16hi((__v16hi)(__m256i)(X), \ - (int)(N)) + ((int)(unsigned short)__builtin_ia32_vec_ext_v16hi((__v16hi)(__m256i)(X), \ + (int)(N))) /// Takes a [32 x i8] vector and returns the vector element value /// indexed by the immediate constant operand. @@ -2001,8 +2001,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A 32-bit integer containing the extracted 8 bits of zero extended /// packed data. #define _mm256_extract_epi8(X, N) \ - (int)(unsigned char)__builtin_ia32_vec_ext_v32qi((__v32qi)(__m256i)(X), \ - (int)(N)) + ((int)(unsigned char)__builtin_ia32_vec_ext_v32qi((__v32qi)(__m256i)(X), \ + (int)(N))) #ifdef __x86_64__ /// Takes a [4 x i64] vector and returns the vector element value @@ -2021,7 +2021,7 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A 64-bit integer containing the extracted 64 bits of extended /// packed data. #define _mm256_extract_epi64(X, N) \ - (long long)__builtin_ia32_vec_ext_v4di((__v4di)(__m256i)(X), (int)(N)) + ((long long)__builtin_ia32_vec_ext_v4di((__v4di)(__m256i)(X), (int)(N))) #endif /// Takes a [8 x i32] vector and replaces the vector element value @@ -2043,8 +2043,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A copy of vector \a __a, after replacing its element indexed by /// \a __imm with \a __b. #define _mm256_insert_epi32(X, I, N) \ - (__m256i)__builtin_ia32_vec_set_v8si((__v8si)(__m256i)(X), \ - (int)(I), (int)(N)) + ((__m256i)__builtin_ia32_vec_set_v8si((__v8si)(__m256i)(X), \ + (int)(I), (int)(N))) /// Takes a [16 x i16] vector and replaces the vector element value @@ -2066,8 +2066,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A copy of vector \a __a, after replacing its element indexed by /// \a __imm with \a __b. #define _mm256_insert_epi16(X, I, N) \ - (__m256i)__builtin_ia32_vec_set_v16hi((__v16hi)(__m256i)(X), \ - (int)(I), (int)(N)) + ((__m256i)__builtin_ia32_vec_set_v16hi((__v16hi)(__m256i)(X), \ + (int)(I), (int)(N))) /// Takes a [32 x i8] vector and replaces the vector element value /// indexed by the immediate constant operand with a new value. Returns the @@ -2088,8 +2088,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A copy of vector \a __a, after replacing its element indexed by /// \a __imm with \a __b. #define _mm256_insert_epi8(X, I, N) \ - (__m256i)__builtin_ia32_vec_set_v32qi((__v32qi)(__m256i)(X), \ - (int)(I), (int)(N)) + ((__m256i)__builtin_ia32_vec_set_v32qi((__v32qi)(__m256i)(X), \ + (int)(I), (int)(N))) #ifdef __x86_64__ /// Takes a [4 x i64] vector and replaces the vector element value @@ -2111,8 +2111,8 @@ _mm256_blendv_ps(__m256 __a, __m256 __b, __m256 __c) /// \returns A copy of vector \a __a, after replacing its element indexed by /// \a __imm with \a __b. #define _mm256_insert_epi64(X, I, N) \ - (__m256i)__builtin_ia32_vec_set_v4di((__v4di)(__m256i)(X), \ - (long long)(I), (int)(N)) + ((__m256i)__builtin_ia32_vec_set_v4di((__v4di)(__m256i)(X), \ + (long long)(I), (int)(N))) #endif /* Conversion */ @@ -4592,8 +4592,8 @@ _mm256_zextsi128_si256(__m128i __a) /// result. /// \returns A 256-bit vector of [8 x float] containing the interleaved values. #define _mm256_insertf128_ps(V1, V2, M) \ - (__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)(__m256)(V1), \ - (__v4sf)(__m128)(V2), (int)(M)) + ((__m256)__builtin_ia32_vinsertf128_ps256((__v8sf)(__m256)(V1), \ + (__v4sf)(__m128)(V2), (int)(M))) /// Constructs a new 256-bit vector of [4 x double] by first duplicating /// a 256-bit vector of [4 x double] given in the first parameter, and then @@ -4630,8 +4630,8 @@ _mm256_zextsi128_si256(__m128i __a) /// result. /// \returns A 256-bit vector of [4 x double] containing the interleaved values. #define _mm256_insertf128_pd(V1, V2, M) \ - (__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)(__m256d)(V1), \ - (__v2df)(__m128d)(V2), (int)(M)) + ((__m256d)__builtin_ia32_vinsertf128_pd256((__v4df)(__m256d)(V1), \ + (__v2df)(__m128d)(V2), (int)(M))) /// Constructs a new 256-bit integer vector by first duplicating a /// 256-bit integer vector given in the first parameter, and then replacing @@ -4668,8 +4668,8 @@ _mm256_zextsi128_si256(__m128i __a) /// result. /// \returns A 256-bit integer vector containing the interleaved values. #define _mm256_insertf128_si256(V1, V2, M) \ - (__m256i)__builtin_ia32_vinsertf128_si256((__v8si)(__m256i)(V1), \ - (__v4si)(__m128i)(V2), (int)(M)) + ((__m256i)__builtin_ia32_vinsertf128_si256((__v8si)(__m256i)(V1), \ + (__v4si)(__m128i)(V2), (int)(M))) /* Vector extract. @@ -4698,7 +4698,7 @@ _mm256_zextsi128_si256(__m128i __a) /// If bit [0] of \a M is 1, bits [255:128] of \a V are copied to the result. /// \returns A 128-bit vector of [4 x float] containing the extracted bits. #define _mm256_extractf128_ps(V, M) \ - (__m128)__builtin_ia32_vextractf128_ps256((__v8sf)(__m256)(V), (int)(M)) + ((__m128)__builtin_ia32_vextractf128_ps256((__v8sf)(__m256)(V), (int)(M))) /// Extracts either the upper or the lower 128 bits from a 256-bit vector /// of [4 x double], as determined by the immediate integer parameter, and @@ -4722,7 +4722,7 @@ _mm256_zextsi128_si256(__m128i __a) /// If bit [0] of \a M is 1, bits [255:128] of \a V are copied to the result. /// \returns A 128-bit vector of [2 x double] containing the extracted bits. #define _mm256_extractf128_pd(V, M) \ - (__m128d)__builtin_ia32_vextractf128_pd256((__v4df)(__m256d)(V), (int)(M)) + ((__m128d)__builtin_ia32_vextractf128_pd256((__v4df)(__m256d)(V), (int)(M))) /// Extracts either the upper or the lower 128 bits from a 256-bit /// integer vector, as determined by the immediate integer parameter, and @@ -4746,177 +4746,7 @@ _mm256_zextsi128_si256(__m128i __a) /// If bit [0] of \a M is 1, bits [255:128] of \a V are copied to the result. /// \returns A 128-bit integer vector containing the extracted bits. #define _mm256_extractf128_si256(V, M) \ - (__m128i)__builtin_ia32_vextractf128_si256((__v8si)(__m256i)(V), (int)(M)) - -/* SIMD load ops (unaligned) */ -/// Loads two 128-bit floating-point vectors of [4 x float] from -/// unaligned memory locations and constructs a 256-bit floating-point vector -/// of [8 x float] by concatenating the two 128-bit vectors. -/// -/// \headerfile -/// -/// This intrinsic corresponds to load instructions followed by the -/// VINSERTF128 instruction. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location containing 4 consecutive -/// single-precision floating-point values. These values are to be copied to -/// bits[255:128] of the result. The address of the memory location does not -/// have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location containing 4 consecutive -/// single-precision floating-point values. These values are to be copied to -/// bits[127:0] of the result. The address of the memory location does not -/// have to be aligned. -/// \returns A 256-bit floating-point vector of [8 x float] containing the -/// concatenated result. -static __inline __m256 __DEFAULT_FN_ATTRS -_mm256_loadu2_m128(float const *__addr_hi, float const *__addr_lo) -{ - __m256 __v256 = _mm256_castps128_ps256(_mm_loadu_ps(__addr_lo)); - return _mm256_insertf128_ps(__v256, _mm_loadu_ps(__addr_hi), 1); -} - -/// Loads two 128-bit floating-point vectors of [2 x double] from -/// unaligned memory locations and constructs a 256-bit floating-point vector -/// of [4 x double] by concatenating the two 128-bit vectors. -/// -/// \headerfile -/// -/// This intrinsic corresponds to load instructions followed by the -/// VINSERTF128 instruction. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location containing two consecutive -/// double-precision floating-point values. These values are to be copied to -/// bits[255:128] of the result. The address of the memory location does not -/// have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location containing two consecutive -/// double-precision floating-point values. These values are to be copied to -/// bits[127:0] of the result. The address of the memory location does not -/// have to be aligned. -/// \returns A 256-bit floating-point vector of [4 x double] containing the -/// concatenated result. -static __inline __m256d __DEFAULT_FN_ATTRS -_mm256_loadu2_m128d(double const *__addr_hi, double const *__addr_lo) -{ - __m256d __v256 = _mm256_castpd128_pd256(_mm_loadu_pd(__addr_lo)); - return _mm256_insertf128_pd(__v256, _mm_loadu_pd(__addr_hi), 1); -} - -/// Loads two 128-bit integer vectors from unaligned memory locations and -/// constructs a 256-bit integer vector by concatenating the two 128-bit -/// vectors. -/// -/// \headerfile -/// -/// This intrinsic corresponds to load instructions followed by the -/// VINSERTF128 instruction. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location containing a 128-bit integer -/// vector. This vector is to be copied to bits[255:128] of the result. The -/// address of the memory location does not have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location containing a 128-bit integer -/// vector. This vector is to be copied to bits[127:0] of the result. The -/// address of the memory location does not have to be aligned. -/// \returns A 256-bit integer vector containing the concatenated result. -static __inline __m256i __DEFAULT_FN_ATTRS -_mm256_loadu2_m128i(__m128i_u const *__addr_hi, __m128i_u const *__addr_lo) -{ - __m256i __v256 = _mm256_castsi128_si256(_mm_loadu_si128(__addr_lo)); - return _mm256_insertf128_si256(__v256, _mm_loadu_si128(__addr_hi), 1); -} - -/* SIMD store ops (unaligned) */ -/// Stores the upper and lower 128 bits of a 256-bit floating-point -/// vector of [8 x float] into two different unaligned memory locations. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the VEXTRACTF128 instruction and the -/// store instructions. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __a -/// A 256-bit floating-point vector of [8 x float]. -static __inline void __DEFAULT_FN_ATTRS -_mm256_storeu2_m128(float *__addr_hi, float *__addr_lo, __m256 __a) -{ - __m128 __v128; - - __v128 = _mm256_castps256_ps128(__a); - _mm_storeu_ps(__addr_lo, __v128); - __v128 = _mm256_extractf128_ps(__a, 1); - _mm_storeu_ps(__addr_hi, __v128); -} - -/// Stores the upper and lower 128 bits of a 256-bit floating-point -/// vector of [4 x double] into two different unaligned memory locations. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the VEXTRACTF128 instruction and the -/// store instructions. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __a -/// A 256-bit floating-point vector of [4 x double]. -static __inline void __DEFAULT_FN_ATTRS -_mm256_storeu2_m128d(double *__addr_hi, double *__addr_lo, __m256d __a) -{ - __m128d __v128; - - __v128 = _mm256_castpd256_pd128(__a); - _mm_storeu_pd(__addr_lo, __v128); - __v128 = _mm256_extractf128_pd(__a, 1); - _mm_storeu_pd(__addr_hi, __v128); -} - -/// Stores the upper and lower 128 bits of a 256-bit integer vector into -/// two different unaligned memory locations. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the VEXTRACTF128 instruction and the -/// store instructions. -/// -/// \param __addr_hi -/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __addr_lo -/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be -/// copied to this memory location. The address of this memory location does -/// not have to be aligned. -/// \param __a -/// A 256-bit integer vector. -static __inline void __DEFAULT_FN_ATTRS -_mm256_storeu2_m128i(__m128i_u *__addr_hi, __m128i_u *__addr_lo, __m256i __a) -{ - __m128i __v128; - - __v128 = _mm256_castsi256_si128(__a); - _mm_storeu_si128(__addr_lo, __v128); - __v128 = _mm256_extractf128_si256(__a, 1); - _mm_storeu_si128(__addr_hi, __v128); -} + ((__m128i)__builtin_ia32_vextractf128_si256((__v8si)(__m256i)(V), (int)(M))) /// Constructs a 256-bit floating-point vector of [8 x float] by /// concatenating two 128-bit floating-point vectors of [4 x float]. @@ -5047,6 +4877,173 @@ _mm256_setr_m128i (__m128i __lo, __m128i __hi) return (__m256i)_mm256_set_m128i(__hi, __lo); } +/* SIMD load ops (unaligned) */ +/// Loads two 128-bit floating-point vectors of [4 x float] from +/// unaligned memory locations and constructs a 256-bit floating-point vector +/// of [8 x float] by concatenating the two 128-bit vectors. +/// +/// \headerfile +/// +/// This intrinsic corresponds to load instructions followed by the +/// VINSERTF128 instruction. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location containing 4 consecutive +/// single-precision floating-point values. These values are to be copied to +/// bits[255:128] of the result. The address of the memory location does not +/// have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location containing 4 consecutive +/// single-precision floating-point values. These values are to be copied to +/// bits[127:0] of the result. The address of the memory location does not +/// have to be aligned. +/// \returns A 256-bit floating-point vector of [8 x float] containing the +/// concatenated result. +static __inline __m256 __DEFAULT_FN_ATTRS +_mm256_loadu2_m128(float const *__addr_hi, float const *__addr_lo) +{ + return _mm256_set_m128(_mm_loadu_ps(__addr_hi), _mm_loadu_ps(__addr_lo)); +} + +/// Loads two 128-bit floating-point vectors of [2 x double] from +/// unaligned memory locations and constructs a 256-bit floating-point vector +/// of [4 x double] by concatenating the two 128-bit vectors. +/// +/// \headerfile +/// +/// This intrinsic corresponds to load instructions followed by the +/// VINSERTF128 instruction. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location containing two consecutive +/// double-precision floating-point values. These values are to be copied to +/// bits[255:128] of the result. The address of the memory location does not +/// have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location containing two consecutive +/// double-precision floating-point values. These values are to be copied to +/// bits[127:0] of the result. The address of the memory location does not +/// have to be aligned. +/// \returns A 256-bit floating-point vector of [4 x double] containing the +/// concatenated result. +static __inline __m256d __DEFAULT_FN_ATTRS +_mm256_loadu2_m128d(double const *__addr_hi, double const *__addr_lo) +{ + return _mm256_set_m128d(_mm_loadu_pd(__addr_hi), _mm_loadu_pd(__addr_lo)); +} + +/// Loads two 128-bit integer vectors from unaligned memory locations and +/// constructs a 256-bit integer vector by concatenating the two 128-bit +/// vectors. +/// +/// \headerfile +/// +/// This intrinsic corresponds to load instructions followed by the +/// VINSERTF128 instruction. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location containing a 128-bit integer +/// vector. This vector is to be copied to bits[255:128] of the result. The +/// address of the memory location does not have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location containing a 128-bit integer +/// vector. This vector is to be copied to bits[127:0] of the result. The +/// address of the memory location does not have to be aligned. +/// \returns A 256-bit integer vector containing the concatenated result. +static __inline __m256i __DEFAULT_FN_ATTRS +_mm256_loadu2_m128i(__m128i_u const *__addr_hi, __m128i_u const *__addr_lo) +{ + return _mm256_set_m128i(_mm_loadu_si128(__addr_hi), _mm_loadu_si128(__addr_lo)); +} + +/* SIMD store ops (unaligned) */ +/// Stores the upper and lower 128 bits of a 256-bit floating-point +/// vector of [8 x float] into two different unaligned memory locations. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VEXTRACTF128 instruction and the +/// store instructions. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __a +/// A 256-bit floating-point vector of [8 x float]. +static __inline void __DEFAULT_FN_ATTRS +_mm256_storeu2_m128(float *__addr_hi, float *__addr_lo, __m256 __a) +{ + __m128 __v128; + + __v128 = _mm256_castps256_ps128(__a); + _mm_storeu_ps(__addr_lo, __v128); + __v128 = _mm256_extractf128_ps(__a, 1); + _mm_storeu_ps(__addr_hi, __v128); +} + +/// Stores the upper and lower 128 bits of a 256-bit floating-point +/// vector of [4 x double] into two different unaligned memory locations. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VEXTRACTF128 instruction and the +/// store instructions. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __a +/// A 256-bit floating-point vector of [4 x double]. +static __inline void __DEFAULT_FN_ATTRS +_mm256_storeu2_m128d(double *__addr_hi, double *__addr_lo, __m256d __a) +{ + __m128d __v128; + + __v128 = _mm256_castpd256_pd128(__a); + _mm_storeu_pd(__addr_lo, __v128); + __v128 = _mm256_extractf128_pd(__a, 1); + _mm_storeu_pd(__addr_hi, __v128); +} + +/// Stores the upper and lower 128 bits of a 256-bit integer vector into +/// two different unaligned memory locations. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the VEXTRACTF128 instruction and the +/// store instructions. +/// +/// \param __addr_hi +/// A pointer to a 128-bit memory location. Bits[255:128] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __addr_lo +/// A pointer to a 128-bit memory location. Bits[127:0] of \a __a are to be +/// copied to this memory location. The address of this memory location does +/// not have to be aligned. +/// \param __a +/// A 256-bit integer vector. +static __inline void __DEFAULT_FN_ATTRS +_mm256_storeu2_m128i(__m128i_u *__addr_hi, __m128i_u *__addr_lo, __m256i __a) +{ + __m128i __v128; + + __v128 = _mm256_castsi256_si128(__a); + _mm_storeu_si128(__addr_lo, __v128); + __v128 = _mm256_extractf128_si256(__a, 1); + _mm_storeu_si128(__addr_hi, __v128); +} + #undef __DEFAULT_FN_ATTRS #undef __DEFAULT_FN_ATTRS128 diff --git a/clang/lib/Headers/cpuid.h b/clang/lib/Headers/cpuid.h index 34f0e76807c..6df1b4a1117 100644 --- a/clang/lib/Headers/cpuid.h +++ b/clang/lib/Headers/cpuid.h @@ -195,6 +195,7 @@ #define bit_PCONFIG 0x00040000 #define bit_IBT 0x00100000 #define bit_AMXBF16 0x00400000 +#define bit_AVX512FP16 0x00800000 #define bit_AMXTILE 0x01000000 #define bit_AMXINT8 0x02000000 diff --git a/clang/lib/Headers/crc32intrin.h b/clang/lib/Headers/crc32intrin.h new file mode 100644 index 00000000000..a0bd99d1b57 --- /dev/null +++ b/clang/lib/Headers/crc32intrin.h @@ -0,0 +1,100 @@ +/*===---- crc32intrin.h - SSE4.2 Accumulate CRC32 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 __CRC32INTRIN_H +#define __CRC32INTRIN_H + +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("crc32"))) + +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned char operand. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the CRC32B instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 8-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. +static __inline__ unsigned int __DEFAULT_FN_ATTRS +_mm_crc32_u8(unsigned int __C, unsigned char __D) +{ + return __builtin_ia32_crc32qi(__C, __D); +} + +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned short operand. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the CRC32W instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 16-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. +static __inline__ unsigned int __DEFAULT_FN_ATTRS +_mm_crc32_u16(unsigned int __C, unsigned short __D) +{ + return __builtin_ia32_crc32hi(__C, __D); +} + +/// Adds the first unsigned integer operand to the CRC-32C checksum of +/// the second unsigned integer operand. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the CRC32L instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 32-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. +static __inline__ unsigned int __DEFAULT_FN_ATTRS +_mm_crc32_u32(unsigned int __C, unsigned int __D) +{ + return __builtin_ia32_crc32si(__C, __D); +} + +#ifdef __x86_64__ +/// Adds the unsigned integer operand to the CRC-32C checksum of the +/// unsigned 64-bit integer operand. +/// +/// \headerfile +/// +/// This intrinsic corresponds to the CRC32Q instruction. +/// +/// \param __C +/// An unsigned integer operand to add to the CRC-32C checksum of operand +/// \a __D. +/// \param __D +/// An unsigned 64-bit integer operand used to compute the CRC-32C checksum. +/// \returns The result of adding operand \a __C to the CRC-32C checksum of +/// operand \a __D. +static __inline__ unsigned long long __DEFAULT_FN_ATTRS +_mm_crc32_u64(unsigned long long __C, unsigned long long __D) +{ + return __builtin_ia32_crc32di(__C, __D); +} +#endif /* __x86_64__ */ + +#undef __DEFAULT_FN_ATTRS + +#endif /* __CRC32INTRIN_H */ diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index bb759721fae..6e9c3032c21 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -10,6 +10,10 @@ #ifndef __EMMINTRIN_H #define __EMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include typedef double __m128d __attribute__((__vector_size__(16), __aligned__(16))); @@ -2818,10 +2822,10 @@ _mm_xor_si128(__m128i __a, __m128i __b) /// \a a. /// \returns A 128-bit integer vector containing the left-shifted value. #define _mm_slli_si128(a, imm) \ - (__m128i)__builtin_ia32_pslldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_pslldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm))) #define _mm_bslli_si128(a, imm) \ - (__m128i)__builtin_ia32_pslldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_pslldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm))) /// Left-shifts each 16-bit value in the 128-bit integer vector operand /// by the specified number of bits. Low-order bits are cleared. @@ -3035,10 +3039,10 @@ _mm_sra_epi32(__m128i __a, __m128i __count) /// \a a. /// \returns A 128-bit integer vector containing the right-shifted value. #define _mm_srli_si128(a, imm) \ - (__m128i)__builtin_ia32_psrldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_psrldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm))) #define _mm_bsrli_si128(a, imm) \ - (__m128i)__builtin_ia32_psrldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_psrldqi128_byteshift((__v2di)(__m128i)(a), (int)(imm))) /// Right-shifts each of 16-bit values in the 128-bit integer vector /// operand by the specified number of bits. High-order bits are cleared. @@ -4356,8 +4360,8 @@ _mm_packus_epi16(__m128i __a, __m128i __b) /// \returns An integer, whose lower 16 bits are selected from the 128-bit /// integer vector parameter and the remaining bits are assigned zeros. #define _mm_extract_epi16(a, imm) \ - (int)(unsigned short)__builtin_ia32_vec_ext_v8hi((__v8hi)(__m128i)(a), \ - (int)(imm)) + ((int)(unsigned short)__builtin_ia32_vec_ext_v8hi((__v8hi)(__m128i)(a), \ + (int)(imm))) /// Constructs a 128-bit integer vector by first making a copy of the /// 128-bit integer vector parameter, and then inserting the lower 16 bits @@ -4380,8 +4384,8 @@ _mm_packus_epi16(__m128i __a, __m128i __b) /// lower 16 bits of \a __b are written. /// \returns A 128-bit integer vector containing the constructed values. #define _mm_insert_epi16(a, b, imm) \ - (__m128i)__builtin_ia32_vec_set_v8hi((__v8hi)(__m128i)(a), (int)(b), \ - (int)(imm)) + ((__m128i)__builtin_ia32_vec_set_v8hi((__v8hi)(__m128i)(a), (int)(b), \ + (int)(imm))) /// Copies the values of the most significant bits from each 8-bit /// element in a 128-bit integer vector of [16 x i8] to create a 16-bit mask @@ -4430,7 +4434,7 @@ _mm_movemask_epi8(__m128i __a) /// 11: assign values from bits [127:96] of \a a. /// \returns A 128-bit integer vector containing the shuffled values. #define _mm_shuffle_epi32(a, imm) \ - (__m128i)__builtin_ia32_pshufd((__v4si)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_pshufd((__v4si)(__m128i)(a), (int)(imm))) /// Constructs a 128-bit integer vector by shuffling four lower 16-bit /// elements of a 128-bit integer vector of [8 x i16], using the immediate @@ -4460,7 +4464,7 @@ _mm_movemask_epi8(__m128i __a) /// 11: assign values from bits [63:48] of \a a. \n /// \returns A 128-bit integer vector containing the shuffled values. #define _mm_shufflelo_epi16(a, imm) \ - (__m128i)__builtin_ia32_pshuflw((__v8hi)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_pshuflw((__v8hi)(__m128i)(a), (int)(imm))) /// Constructs a 128-bit integer vector by shuffling four upper 16-bit /// elements of a 128-bit integer vector of [8 x i16], using the immediate @@ -4490,7 +4494,7 @@ _mm_movemask_epi8(__m128i __a) /// 11: assign values from bits [127:112] of \a a. \n /// \returns A 128-bit integer vector containing the shuffled values. #define _mm_shufflehi_epi16(a, imm) \ - (__m128i)__builtin_ia32_pshufhw((__v8hi)(__m128i)(a), (int)(imm)) + ((__m128i)__builtin_ia32_pshufhw((__v8hi)(__m128i)(a), (int)(imm))) /// Unpacks the high-order (index 8-15) values from two 128-bit vectors /// of [16 x i8] and interleaves them into a 128-bit vector of [16 x i8]. @@ -4844,8 +4848,8 @@ _mm_movemask_pd(__m128d __a) /// Bit[1] = 1: upper element of \a b copied to upper element of result. \n /// \returns A 128-bit vector of [2 x double] containing the shuffled values. #define _mm_shuffle_pd(a, b, i) \ - (__m128d)__builtin_ia32_shufpd((__v2df)(__m128d)(a), (__v2df)(__m128d)(b), \ - (int)(i)) + ((__m128d)__builtin_ia32_shufpd((__v2df)(__m128d)(a), (__v2df)(__m128d)(b), \ + (int)(i))) /// Casts a 128-bit floating-point vector of [2 x double] into a 128-bit /// floating-point vector of [4 x float]. diff --git a/clang/lib/Headers/f16cintrin.h b/clang/lib/Headers/f16cintrin.h index 109b604adae..13905e6fb0e 100644 --- a/clang/lib/Headers/f16cintrin.h +++ b/clang/lib/Headers/f16cintrin.h @@ -66,8 +66,8 @@ _cvtsh_ss(unsigned short __a) /// 1XX: Use MXCSR.RC for rounding /// \returns The converted 16-bit half-precision float value. #define _cvtss_sh(a, imm) \ - (unsigned short)(((__v8hi)__builtin_ia32_vcvtps2ph((__v4sf){a, 0, 0, 0}, \ - (imm)))[0]) + ((unsigned short)(((__v8hi)__builtin_ia32_vcvtps2ph((__v4sf){a, 0, 0, 0}, \ + (imm)))[0])) /// Converts a 128-bit vector containing 32-bit float values into a /// 128-bit vector containing 16-bit half-precision float values. @@ -93,7 +93,7 @@ _cvtsh_ss(unsigned short __a) /// values. The lower 64 bits are used to store the converted 16-bit /// half-precision floating-point values. #define _mm_cvtps_ph(a, imm) \ - (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)(__m128)(a), (imm)) + ((__m128i)__builtin_ia32_vcvtps2ph((__v4sf)(__m128)(a), (imm))) /// Converts a 128-bit vector containing 16-bit half-precision float /// values into a 128-bit vector containing 32-bit float values. @@ -136,7 +136,7 @@ _mm_cvtph_ps(__m128i __a) /// \returns A 128-bit vector containing the converted 16-bit half-precision /// float values. #define _mm256_cvtps_ph(a, imm) \ - (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)(__m256)(a), (imm)) + ((__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)(__m256)(a), (imm))) /// Converts a 128-bit vector containing 16-bit half-precision float /// values into a 256-bit vector of [8 x float]. diff --git a/clang/lib/Headers/gfniintrin.h b/clang/lib/Headers/gfniintrin.h index 11a321b7c91..a59238b0b13 100644 --- a/clang/lib/Headers/gfniintrin.h +++ b/clang/lib/Headers/gfniintrin.h @@ -28,14 +28,14 @@ #define __DEFAULT_FN_ATTRS_VL256 __attribute__((__always_inline__, __nodebug__, __target__("avx512bw,avx512vl,gfni"), __min_vector_width__(256))) #define _mm_gf2p8affineinv_epi64_epi8(A, B, I) \ - (__m128i)__builtin_ia32_vgf2p8affineinvqb_v16qi((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), \ - (char)(I)) + ((__m128i)__builtin_ia32_vgf2p8affineinvqb_v16qi((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), \ + (char)(I))) #define _mm_gf2p8affine_epi64_epi8(A, B, I) \ - (__m128i)__builtin_ia32_vgf2p8affineqb_v16qi((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), \ - (char)(I)) + ((__m128i)__builtin_ia32_vgf2p8affineqb_v16qi((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), \ + (char)(I))) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_gf2p8mul_epi8(__m128i __A, __m128i __B) @@ -46,14 +46,14 @@ _mm_gf2p8mul_epi8(__m128i __A, __m128i __B) #ifdef __AVXINTRIN_H #define _mm256_gf2p8affineinv_epi64_epi8(A, B, I) \ - (__m256i)__builtin_ia32_vgf2p8affineinvqb_v32qi((__v32qi)(__m256i)(A), \ - (__v32qi)(__m256i)(B), \ - (char)(I)) + ((__m256i)__builtin_ia32_vgf2p8affineinvqb_v32qi((__v32qi)(__m256i)(A), \ + (__v32qi)(__m256i)(B), \ + (char)(I))) #define _mm256_gf2p8affine_epi64_epi8(A, B, I) \ - (__m256i)__builtin_ia32_vgf2p8affineqb_v32qi((__v32qi)(__m256i)(A), \ - (__v32qi)(__m256i)(B), \ - (char)(I)) + ((__m256i)__builtin_ia32_vgf2p8affineqb_v32qi((__v32qi)(__m256i)(A), \ + (__v32qi)(__m256i)(B), \ + (char)(I))) static __inline__ __m256i __DEFAULT_FN_ATTRS_Y _mm256_gf2p8mul_epi8(__m256i __A, __m256i __B) @@ -65,32 +65,32 @@ _mm256_gf2p8mul_epi8(__m256i __A, __m256i __B) #ifdef __AVX512BWINTRIN_H #define _mm512_gf2p8affineinv_epi64_epi8(A, B, I) \ - (__m512i)__builtin_ia32_vgf2p8affineinvqb_v64qi((__v64qi)(__m512i)(A), \ - (__v64qi)(__m512i)(B), \ - (char)(I)) + ((__m512i)__builtin_ia32_vgf2p8affineinvqb_v64qi((__v64qi)(__m512i)(A), \ + (__v64qi)(__m512i)(B), \ + (char)(I))) #define _mm512_mask_gf2p8affineinv_epi64_epi8(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ - (__v64qi)_mm512_gf2p8affineinv_epi64_epi8(A, B, I), \ - (__v64qi)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ + (__v64qi)_mm512_gf2p8affineinv_epi64_epi8(A, B, I), \ + (__v64qi)(__m512i)(S))) #define _mm512_maskz_gf2p8affineinv_epi64_epi8(U, A, B, I) \ - (__m512i)_mm512_mask_gf2p8affineinv_epi64_epi8((__m512i)_mm512_setzero_si512(), \ - U, A, B, I) + _mm512_mask_gf2p8affineinv_epi64_epi8((__m512i)_mm512_setzero_si512(), \ + U, A, B, I) #define _mm512_gf2p8affine_epi64_epi8(A, B, I) \ - (__m512i)__builtin_ia32_vgf2p8affineqb_v64qi((__v64qi)(__m512i)(A), \ - (__v64qi)(__m512i)(B), \ - (char)(I)) + ((__m512i)__builtin_ia32_vgf2p8affineqb_v64qi((__v64qi)(__m512i)(A), \ + (__v64qi)(__m512i)(B), \ + (char)(I))) #define _mm512_mask_gf2p8affine_epi64_epi8(S, U, A, B, I) \ - (__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ - (__v64qi)_mm512_gf2p8affine_epi64_epi8(A, B, I), \ - (__v64qi)(__m512i)(S)) + ((__m512i)__builtin_ia32_selectb_512((__mmask64)(U), \ + (__v64qi)_mm512_gf2p8affine_epi64_epi8((A), (B), (I)), \ + (__v64qi)(__m512i)(S))) #define _mm512_maskz_gf2p8affine_epi64_epi8(U, A, B, I) \ - (__m512i)_mm512_mask_gf2p8affine_epi64_epi8((__m512i)_mm512_setzero_si512(), \ - U, A, B, I) + _mm512_mask_gf2p8affine_epi64_epi8((__m512i)_mm512_setzero_si512(), \ + U, A, B, I) static __inline__ __m512i __DEFAULT_FN_ATTRS_Z _mm512_gf2p8mul_epi8(__m512i __A, __m512i __B) @@ -117,40 +117,39 @@ _mm512_maskz_gf2p8mul_epi8(__mmask64 __U, __m512i __A, __m512i __B) #ifdef __AVX512VLBWINTRIN_H #define _mm_mask_gf2p8affineinv_epi64_epi8(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ - (__v16qi)_mm_gf2p8affineinv_epi64_epi8(A, B, I), \ - (__v16qi)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ + (__v16qi)_mm_gf2p8affineinv_epi64_epi8(A, B, I), \ + (__v16qi)(__m128i)(S))) #define _mm_maskz_gf2p8affineinv_epi64_epi8(U, A, B, I) \ - (__m128i)_mm_mask_gf2p8affineinv_epi64_epi8((__m128i)_mm_setzero_si128(), \ - U, A, B, I) + _mm_mask_gf2p8affineinv_epi64_epi8((__m128i)_mm_setzero_si128(), \ + U, A, B, I) #define _mm256_mask_gf2p8affineinv_epi64_epi8(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ - (__v32qi)_mm256_gf2p8affineinv_epi64_epi8(A, B, I), \ - (__v32qi)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ + (__v32qi)_mm256_gf2p8affineinv_epi64_epi8(A, B, I), \ + (__v32qi)(__m256i)(S))) #define _mm256_maskz_gf2p8affineinv_epi64_epi8(U, A, B, I) \ - (__m256i)_mm256_mask_gf2p8affineinv_epi64_epi8((__m256i)_mm256_setzero_si256(), \ - U, A, B, I) + _mm256_mask_gf2p8affineinv_epi64_epi8((__m256i)_mm256_setzero_si256(), \ + U, A, B, I) #define _mm_mask_gf2p8affine_epi64_epi8(S, U, A, B, I) \ - (__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ - (__v16qi)_mm_gf2p8affine_epi64_epi8(A, B, I), \ - (__v16qi)(__m128i)(S)) + ((__m128i)__builtin_ia32_selectb_128((__mmask16)(U), \ + (__v16qi)_mm_gf2p8affine_epi64_epi8(A, B, I), \ + (__v16qi)(__m128i)(S))) #define _mm_maskz_gf2p8affine_epi64_epi8(U, A, B, I) \ - (__m128i)_mm_mask_gf2p8affine_epi64_epi8((__m128i)_mm_setzero_si128(), \ - U, A, B, I) + _mm_mask_gf2p8affine_epi64_epi8((__m128i)_mm_setzero_si128(), U, A, B, I) #define _mm256_mask_gf2p8affine_epi64_epi8(S, U, A, B, I) \ - (__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ - (__v32qi)_mm256_gf2p8affine_epi64_epi8(A, B, I), \ - (__v32qi)(__m256i)(S)) + ((__m256i)__builtin_ia32_selectb_256((__mmask32)(U), \ + (__v32qi)_mm256_gf2p8affine_epi64_epi8(A, B, I), \ + (__v32qi)(__m256i)(S))) #define _mm256_maskz_gf2p8affine_epi64_epi8(U, A, B, I) \ - (__m256i)_mm256_mask_gf2p8affine_epi64_epi8((__m256i)_mm256_setzero_si256(), \ - U, A, B, I) + _mm256_mask_gf2p8affine_epi64_epi8((__m256i)_mm256_setzero_si256(), \ + U, A, B, I) static __inline__ __m128i __DEFAULT_FN_ATTRS_VL128 _mm_mask_gf2p8mul_epi8(__m128i __S, __mmask16 __U, __m128i __A, __m128i __B) diff --git a/clang/lib/Headers/ia32intrin.h b/clang/lib/Headers/ia32intrin.h index 00138effd50..ec8142b9c64 100644 --- a/clang/lib/Headers/ia32intrin.h +++ b/clang/lib/Headers/ia32intrin.h @@ -16,7 +16,7 @@ /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) -#define __DEFAULT_FN_ATTRS_SSE42 __attribute__((__always_inline__, __nodebug__, __target__("sse4.2"))) +#define __DEFAULT_FN_ATTRS_CRC32 __attribute__((__always_inline__, __nodebug__, __target__("crc32"))) #if defined(__cplusplus) && (__cplusplus >= 201103L) #define __DEFAULT_FN_ATTRS_CAST __attribute__((__always_inline__)) constexpr @@ -282,7 +282,7 @@ _castu64_f64(unsigned long long __A) { * \returns The result of adding operand \a __C to the CRC-32C checksum of * operand \a __D. */ -static __inline__ unsigned int __DEFAULT_FN_ATTRS_SSE42 +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32b(unsigned int __C, unsigned char __D) { return __builtin_ia32_crc32qi(__C, __D); @@ -303,7 +303,7 @@ __crc32b(unsigned int __C, unsigned char __D) * \returns The result of adding operand \a __C to the CRC-32C checksum of * operand \a __D. */ -static __inline__ unsigned int __DEFAULT_FN_ATTRS_SSE42 +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32w(unsigned int __C, unsigned short __D) { return __builtin_ia32_crc32hi(__C, __D); @@ -324,7 +324,7 @@ __crc32w(unsigned int __C, unsigned short __D) * \returns The result of adding operand \a __C to the CRC-32C checksum of * operand \a __D. */ -static __inline__ unsigned int __DEFAULT_FN_ATTRS_SSE42 +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CRC32 __crc32d(unsigned int __C, unsigned int __D) { return __builtin_ia32_crc32si(__C, __D); @@ -346,7 +346,7 @@ __crc32d(unsigned int __C, unsigned int __D) * \returns The result of adding operand \a __C to the CRC-32C checksum of * operand \a __D. */ -static __inline__ unsigned long long __DEFAULT_FN_ATTRS_SSE42 +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CRC32 __crc32q(unsigned long long __C, unsigned long long __D) { return __builtin_ia32_crc32di(__C, __D); @@ -435,7 +435,7 @@ __rorq(unsigned long long __X, int __C) { #undef __DEFAULT_FN_ATTRS #undef __DEFAULT_FN_ATTRS_CAST -#undef __DEFAULT_FN_ATTRS_SSE42 +#undef __DEFAULT_FN_ATTRS_CRC32 #undef __DEFAULT_FN_ATTRS_CONSTEXPR #endif /* __IA32INTRIN_H */ diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index 56d3dadf6a3..e5174f8785e 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -10,6 +10,10 @@ #ifndef __IMMINTRIN_H #define __IMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include #if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ @@ -210,6 +214,20 @@ #include #endif +/* + * FIXME: _Float16 type is legal only when HW support float16 operation. + * We use __AVX512FP16__ to identify if float16 is supported or not, so + * when float16 is not supported, the related header is not included. + * + */ +#if defined(__AVX512FP16__) +#include +#endif + +#if defined(__AVX512FP16__) && defined(__AVX512VL__) +#include +#endif + #if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ defined(__AVX512BF16__) #include @@ -525,13 +543,13 @@ extern "C" { #if defined(__i386__) || defined(__x86_64__) static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchange_HLEAcquire(long volatile *_Target, long _Value) { - __asm__ __volatile__(".byte 0xf2 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } static __inline__ long __DEFAULT_FN_ATTRS _InterlockedExchange_HLERelease(long volatile *_Target, long _Value) { - __asm__ __volatile__(".byte 0xf3 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } @@ -539,13 +557,13 @@ _InterlockedExchange_HLERelease(long volatile *_Target, long _Value) { #if defined(__x86_64__) static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64_HLEAcquire(__int64 volatile *_Target, __int64 _Value) { - __asm__ __volatile__(".byte 0xf2 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedExchange64_HLERelease(__int64 volatile *_Target, __int64 _Value) { - __asm__ __volatile__(".byte 0xf3 ; lock ; xchg %0, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; xchg {%0, %1|%1, %0}" : "+r" (_Value), "+m" (*_Target) :: "memory"); return _Value; } @@ -557,7 +575,7 @@ _InterlockedExchange64_HLERelease(__int64 volatile *_Target, __int64 _Value) { static __inline__ long __DEFAULT_FN_ATTRS _InterlockedCompareExchange_HLEAcquire(long volatile *_Destination, long _Exchange, long _Comparand) { - __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -565,7 +583,7 @@ _InterlockedCompareExchange_HLEAcquire(long volatile *_Destination, static __inline__ long __DEFAULT_FN_ATTRS _InterlockedCompareExchange_HLERelease(long volatile *_Destination, long _Exchange, long _Comparand) { - __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -575,7 +593,7 @@ _InterlockedCompareExchange_HLERelease(long volatile *_Destination, static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64_HLEAcquire(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf2 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; @@ -583,7 +601,7 @@ _InterlockedCompareExchange64_HLEAcquire(__int64 volatile *_Destination, static __inline__ __int64 __DEFAULT_FN_ATTRS _InterlockedCompareExchange64_HLERelease(__int64 volatile *_Destination, __int64 _Exchange, __int64 _Comparand) { - __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg %2, %1" + __asm__ __volatile__(".byte 0xf3 ; lock ; cmpxchg {%2, %1|%1, %2}" : "+a" (_Comparand), "+m" (*_Destination) : "r" (_Exchange) : "memory"); return _Comparand; diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index ff8eb8fca26..02e66d02067 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -97,8 +97,9 @@ unsigned long __readcr8(void); unsigned int __readdr(unsigned int); #ifdef __i386__ unsigned char __readfsbyte(unsigned long); -unsigned __int64 __readfsqword(unsigned long); unsigned short __readfsword(unsigned long); +unsigned long __readfsdword(unsigned long); +unsigned __int64 __readfsqword(unsigned long); #endif unsigned __int64 __readmsr(unsigned long); unsigned __int64 __readpmc(unsigned long); @@ -149,10 +150,8 @@ long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long); long _InterlockedExchangeAdd_HLERelease(long volatile *, long); __int64 _InterlockedExchangeAdd64_HLEAcquire(__int64 volatile *, __int64); __int64 _InterlockedExchangeAdd64_HLERelease(__int64 volatile *, __int64); -void __attribute__((__deprecated__( - "use other intrinsics or C++11 atomics instead"))) _ReadBarrier(void); -void __attribute__((__deprecated__( - "use other intrinsics or C++11 atomics instead"))) _ReadWriteBarrier(void); +void _ReadBarrier(void); +void _ReadWriteBarrier(void); unsigned int _rorx_u32(unsigned int, const unsigned int); int _sarx_i32(int, unsigned int); #if __STDC_HOSTED__ @@ -163,8 +162,7 @@ unsigned int _shrx_u32(unsigned int, unsigned int); void _Store_HLERelease(long volatile *, long); void _Store64_HLERelease(__int64 volatile *, __int64); void _StorePointer_HLERelease(void *volatile *, void *); -void __attribute__((__deprecated__( - "use other intrinsics or C++11 atomics instead"))) _WriteBarrier(void); +void _WriteBarrier(void); unsigned __int32 xbegin(void); void _xend(void); @@ -457,7 +455,9 @@ static __inline__ void __DEFAULT_FN_ATTRS __movsb(unsigned char *__dst, : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsb\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movsb\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -467,12 +467,14 @@ static __inline__ void __DEFAULT_FN_ATTRS __movsd(unsigned long *__dst, unsigned long const *__src, size_t __n) { #if defined(__x86_64__) - __asm__ __volatile__("rep movsl" + __asm__ __volatile__("rep movs{l|d}" : "+D"(__dst), "+S"(__src), "+c"(__n) : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsl\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movs{l|d}\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -487,7 +489,9 @@ static __inline__ void __DEFAULT_FN_ATTRS __movsw(unsigned short *__dst, : : "memory"); #else - __asm__ __volatile__("xchg %%esi, %1\nrep movsw\nxchg %%esi, %1" + __asm__ __volatile__("xchg {%%esi, %1|%1, esi}\n" + "rep movsw\n" + "xchg {%%esi, %1|%1, esi}" : "+D"(__dst), "+r"(__src), "+c"(__n) : : "memory"); @@ -496,7 +500,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __movsw(unsigned short *__dst, static __inline__ void __DEFAULT_FN_ATTRS __stosd(unsigned long *__dst, unsigned long __x, size_t __n) { - __asm__ __volatile__("rep stosl" + __asm__ __volatile__("rep stos{l|d}" : "+D"(__dst), "+c"(__n) : "a"(__x) : "memory"); @@ -538,9 +542,9 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst, #else /* x86-64 uses %rbx as the base register, so preserve it. */ #define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ - __asm("xchgq %%rbx,%q1\n" \ + __asm("xchg{q} {%%rbx, %q1|%q1, rbx}\n" \ "cpuid\n" \ - "xchgq %%rbx,%q1" \ + "xchg{q} {%%rbx, %q1|%q1, rbx}" \ : "=a"(__eax), "=r"(__ebx), "=c"(__ecx), "=d"(__edx) \ : "0"(__leaf), "2"(__count)) #endif @@ -574,6 +578,9 @@ void _WriteStatusReg(int, __int64); unsigned short __cdecl _byteswap_ushort(unsigned short val); unsigned long __cdecl _byteswap_ulong (unsigned long val); unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 val); + +__int64 __mulh(__int64 __a, __int64 __b); +unsigned __int64 __umulh(unsigned __int64 __a, unsigned __int64 __b); #endif /*----------------------------------------------------------------------------*\ @@ -597,13 +604,17 @@ __readmsr(unsigned long __register) { static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) { unsigned __LPTRINT_TYPE__ __cr3_val; - __asm__ __volatile__ ("mov %%cr3, %0" : "=r"(__cr3_val) : : "memory"); + __asm__ __volatile__( + "mov {%%cr3, %0|%0, cr3}" + : "=r"(__cr3_val) + : + : "memory"); return __cr3_val; } static __inline__ void __DEFAULT_FN_ATTRS __writecr3(unsigned __INTPTR_TYPE__ __cr3_val) { - __asm__ ("mov %0, %%cr3" : : "r"(__cr3_val) : "memory"); + __asm__ ("mov {%0, %%cr3|cr3, %0}" : : "r"(__cr3_val) : "memory"); } #ifdef __cplusplus diff --git a/clang/lib/Headers/keylockerintrin.h b/clang/lib/Headers/keylockerintrin.h index 68b0a568961..ad9428e6c8b 100644 --- a/clang/lib/Headers/keylockerintrin.h +++ b/clang/lib/Headers/keylockerintrin.h @@ -99,7 +99,7 @@ _mm_loadiwkey (unsigned int __ctl, __m128i __intkey, } /// Wrap a 128-bit AES key from __key into a key handle and output in -/// ((__m128i*)__h) to ((__m128i*)__h) + 5 and a 32-bit value as return. +/// ((__m128i*)__h) to ((__m128i*)__h) + 2 and a 32-bit value as return. /// The explicit source operand __htype specifies handle restrictions. /// /// \headerfile @@ -120,9 +120,6 @@ _mm_loadiwkey (unsigned int __ctl, __m128i __intkey, /// MEM[__h+127:__h] := Handle[127:0] // AAD /// MEM[__h+255:__h+128] := Handle[255:128] // Integrity Tag /// MEM[__h+383:__h+256] := Handle[383:256] // CipherText -/// MEM[__h+511:__h+384] := 0 // Reserved for future usage -/// MEM[__h+639:__h+512] := 0 // Reserved for future usage -/// MEM[__h+767:__h+640] := 0 // Reserved for future usage /// OF := 0 /// SF := 0 /// ZF := 0 @@ -136,7 +133,7 @@ _mm_encodekey128_u32(unsigned int __htype, __m128i __key, void *__h) { } /// Wrap a 256-bit AES key from __key_hi:__key_lo into a key handle, then -/// output handle in ((__m128i*)__h) to ((__m128i*)__h) + 6 and +/// output handle in ((__m128i*)__h) to ((__m128i*)__h) + 3 and /// a 32-bit value as return. /// The explicit source operand __htype specifies handle restrictions. /// @@ -160,9 +157,6 @@ _mm_encodekey128_u32(unsigned int __htype, __m128i __key, void *__h) { /// MEM[__h+255:__h+128] := Handle[255:128] // Tag /// MEM[__h+383:__h+256] := Handle[383:256] // CipherText[127:0] /// MEM[__h+511:__h+384] := Handle[511:384] // CipherText[255:128] -/// MEM[__h+639:__h+512] := 0 // Reserved for future usage -/// MEM[__h+767:__h+640] := 0 // Reserved for future usage -/// MEM[__h+895:__h+768] := 0 Integrity// Reserved for future usage /// OF := 0 /// SF := 0 /// ZF := 0 diff --git a/clang/lib/Headers/mmintrin.h b/clang/lib/Headers/mmintrin.h index 79a8b55016b..03bac92198a 100644 --- a/clang/lib/Headers/mmintrin.h +++ b/clang/lib/Headers/mmintrin.h @@ -10,6 +10,10 @@ #ifndef __MMINTRIN_H #define __MMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + typedef long long __m64 __attribute__((__vector_size__(8), __aligned__(8))); typedef long long __v1di __attribute__((__vector_size__(8))); diff --git a/clang/lib/Headers/nmmintrin.h b/clang/lib/Headers/nmmintrin.h index 672aea49668..59fc7ec99e6 100644 --- a/clang/lib/Headers/nmmintrin.h +++ b/clang/lib/Headers/nmmintrin.h @@ -10,6 +10,10 @@ #ifndef __NMMINTRIN_H #define __NMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + /* To match expectations of gcc we put the sse4.2 definitions into smmintrin.h, just include it now then. */ #include diff --git a/clang/lib/Headers/opencl-c-base.h b/clang/lib/Headers/opencl-c-base.h index 3c5e2c97393..9c81ddb5e2a 100644 --- a/clang/lib/Headers/opencl-c-base.h +++ b/clang/lib/Headers/opencl-c-base.h @@ -12,8 +12,8 @@ // Define extension macros #if (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= 200) -// For SPIR all extensions are supported. -#if defined(__SPIR__) +// For SPIR and SPIR-V all extensions are supported. +#if defined(__SPIR__) || defined(__SPIRV__) #define cl_khr_subgroup_extended_types 1 #define cl_khr_subgroup_non_uniform_vote 1 #define cl_khr_subgroup_ballot 1 @@ -25,12 +25,31 @@ #define cl_khr_integer_dot_product 1 #define __opencl_c_integer_dot_product_input_4x8bit 1 #define __opencl_c_integer_dot_product_input_4x8bit_packed 1 +#define cl_ext_float_atomics 1 +#ifdef cl_khr_fp16 +#define __opencl_c_ext_fp16_global_atomic_load_store 1 +#define __opencl_c_ext_fp16_local_atomic_load_store 1 +#define __opencl_c_ext_fp16_global_atomic_add 1 +#define __opencl_c_ext_fp16_local_atomic_add 1 +#define __opencl_c_ext_fp16_global_atomic_min_max 1 +#define __opencl_c_ext_fp16_local_atomic_min_max 1 +#endif +#ifdef cl_khr_fp64 +#define __opencl_c_ext_fp64_global_atomic_add 1 +#define __opencl_c_ext_fp64_local_atomic_add 1 +#define __opencl_c_ext_fp64_global_atomic_min_max 1 +#define __opencl_c_ext_fp64_local_atomic_min_max 1 +#endif +#define __opencl_c_ext_fp32_global_atomic_add 1 +#define __opencl_c_ext_fp32_local_atomic_add 1 +#define __opencl_c_ext_fp32_global_atomic_min_max 1 +#define __opencl_c_ext_fp32_local_atomic_min_max 1 -#endif // defined(__SPIR__) +#endif // defined(__SPIR__) || defined(__SPIRV__) #endif // (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ >= 200) // Define feature macros for OpenCL C 2.0 -#if (defined(__OPENCL_CPP_VERSION__) || __OPENCL_C_VERSION__ == 200) +#if (__OPENCL_CPP_VERSION__ == 100 || __OPENCL_C_VERSION__ == 200) #define __opencl_c_pipes 1 #define __opencl_c_generic_address_space 1 #define __opencl_c_work_group_collective_functions 1 @@ -45,12 +64,12 @@ #endif // Define header-only feature macros for OpenCL C 3.0. -#if (__OPENCL_C_VERSION__ == 300) -// For the SPIR target all features are supported. -#if defined(__SPIR__) +#if (__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300) +// For the SPIR and SPIR-V target all features are supported. +#if defined(__SPIR__) || defined(__SPIRV__) #define __opencl_c_atomic_scope_all_devices 1 #endif // defined(__SPIR__) -#endif // (__OPENCL_C_VERSION__ == 300) +#endif // (__OPENCL_CPP_VERSION__ == 202100 || __OPENCL_C_VERSION__ == 300) // built-in scalar data types: @@ -329,11 +348,17 @@ typedef enum memory_scope { memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE, #if defined(__opencl_c_atomic_scope_all_devices) memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES, -#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) memory_scope_all_devices = memory_scope_all_svm_devices, -#endif // __OPENCL_C_VERSION__ >= CL_VERSION_3_0 +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif // defined(__opencl_c_atomic_scope_all_devices) -#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) +/** + * Subgroups have different requirements on forward progress, so just test + * all the relevant macros. + * CL 3.0 sub-groups "they are not guaranteed to make independent forward progress" + * KHR subgroups "Subgroups within a workgroup are independent, make forward progress with respect to each other" + */ +#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) || defined(__opencl_c_subgroups) memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP #endif } memory_scope; @@ -572,6 +597,26 @@ typedef struct { #define as_intptr_t(x) __builtin_astype((x), intptr_t) #define as_uintptr_t(x) __builtin_astype((x), uintptr_t) +// C++ for OpenCL - __remove_address_space +#if defined(__OPENCL_CPP_VERSION__) +template struct __remove_address_space { using type = _Tp; }; +template struct __remove_address_space<__generic _Tp> { + using type = _Tp; +}; +template struct __remove_address_space<__global _Tp> { + using type = _Tp; +}; +template struct __remove_address_space<__private _Tp> { + using type = _Tp; +}; +template struct __remove_address_space<__local _Tp> { + using type = _Tp; +}; +template struct __remove_address_space<__constant _Tp> { + using type = _Tp; +}; +#endif + // OpenCL v1.1 s6.9, v1.2/2.0 s6.10 - Function qualifiers #define __kernel_exec(X, typen) __kernel \ diff --git a/clang/lib/Headers/opencl-c.h b/clang/lib/Headers/opencl-c.h index fc50dd718c4..32af848a94c 100644 --- a/clang/lib/Headers/opencl-c.h +++ b/clang/lib/Headers/opencl-c.h @@ -23,11 +23,14 @@ #endif //cl_khr_3d_image_writes #endif //__OPENCL_C_VERSION__ < CL_VERSION_2_0 - -#if (defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)) && defined(__SPIR__) +#if (defined(__OPENCL_CPP_VERSION__) || \ + (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)) && \ + (defined(__SPIR__) || defined(__SPIRV__)) #pragma OPENCL EXTENSION cl_intel_planar_yuv : begin #pragma OPENCL EXTENSION cl_intel_planar_yuv : end -#endif // (defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)) && defined(__SPIR__) +#endif // (defined(__OPENCL_CPP_VERSION__) || + // (__OPENCL_C_VERSION__ >= CL_VERSION_1_2)) && + // (defined(__SPIR__) || defined(__SPIRV__)) #define __ovld __attribute__((overloadable)) #define __conv __attribute__((convergent)) @@ -12070,33 +12073,28 @@ void __ovld vstore_half16_rtn(double16 data, size_t offset, __private half *p); * The address computed as (p + (offset * 4)) * must be aligned to sizeof (half) * 4 bytes. */ -float __ovld vloada_half(size_t offset, const __constant half *p); float2 __ovld vloada_half2(size_t offset, const __constant half *p); float3 __ovld vloada_half3(size_t offset, const __constant half *p); float4 __ovld vloada_half4(size_t offset, const __constant half *p); float8 __ovld vloada_half8(size_t offset, const __constant half *p); float16 __ovld vloada_half16(size_t offset, const __constant half *p); #if defined(__opencl_c_generic_address_space) -float __ovld vloada_half(size_t offset, const half *p); float2 __ovld vloada_half2(size_t offset, const half *p); float3 __ovld vloada_half3(size_t offset, const half *p); float4 __ovld vloada_half4(size_t offset, const half *p); float8 __ovld vloada_half8(size_t offset, const half *p); float16 __ovld vloada_half16(size_t offset, const half *p); #else -float __ovld vloada_half(size_t offset, const __global half *p); float2 __ovld vloada_half2(size_t offset, const __global half *p); float3 __ovld vloada_half3(size_t offset, const __global half *p); float4 __ovld vloada_half4(size_t offset, const __global half *p); float8 __ovld vloada_half8(size_t offset, const __global half *p); float16 __ovld vloada_half16(size_t offset, const __global half *p); -float __ovld vloada_half(size_t offset, const __local half *p); float2 __ovld vloada_half2(size_t offset, const __local half *p); float3 __ovld vloada_half3(size_t offset, const __local half *p); float4 __ovld vloada_half4(size_t offset, const __local half *p); float8 __ovld vloada_half8(size_t offset, const __local half *p); float16 __ovld vloada_half16(size_t offset, const __local half *p); -float __ovld vloada_half(size_t offset, const __private half *p); float2 __ovld vloada_half2(size_t offset, const __private half *p); float3 __ovld vloada_half3(size_t offset, const __private half *p); float4 __ovld vloada_half4(size_t offset, const __private half *p); @@ -12121,35 +12119,30 @@ float16 __ovld vloada_half16(size_t offset, const __private half *p); * round to nearest even. */ #if defined(__opencl_c_generic_address_space) -void __ovld vstorea_half(float data, size_t offset, half *p); void __ovld vstorea_half2(float2 data, size_t offset, half *p); void __ovld vstorea_half3(float3 data, size_t offset, half *p); void __ovld vstorea_half4(float4 data, size_t offset, half *p); void __ovld vstorea_half8(float8 data, size_t offset, half *p); void __ovld vstorea_half16(float16 data, size_t offset, half *p); -void __ovld vstorea_half_rte(float data, size_t offset, half *p); void __ovld vstorea_half2_rte(float2 data, size_t offset, half *p); void __ovld vstorea_half3_rte(float3 data, size_t offset, half *p); void __ovld vstorea_half4_rte(float4 data, size_t offset, half *p); void __ovld vstorea_half8_rte(float8 data, size_t offset, half *p); void __ovld vstorea_half16_rte(float16 data, size_t offset, half *p); -void __ovld vstorea_half_rtz(float data, size_t offset, half *p); void __ovld vstorea_half2_rtz(float2 data, size_t offset, half *p); void __ovld vstorea_half3_rtz(float3 data, size_t offset, half *p); void __ovld vstorea_half4_rtz(float4 data, size_t offset, half *p); void __ovld vstorea_half8_rtz(float8 data, size_t offset, half *p); void __ovld vstorea_half16_rtz(float16 data, size_t offset, half *p); -void __ovld vstorea_half_rtp(float data, size_t offset, half *p); void __ovld vstorea_half2_rtp(float2 data, size_t offset, half *p); void __ovld vstorea_half3_rtp(float3 data, size_t offset, half *p); void __ovld vstorea_half4_rtp(float4 data, size_t offset, half *p); void __ovld vstorea_half8_rtp(float8 data, size_t offset, half *p); void __ovld vstorea_half16_rtp(float16 data, size_t offset, half *p); -void __ovld vstorea_half_rtn(float data, size_t offset, half *p); void __ovld vstorea_half2_rtn(float2 data, size_t offset, half *p); void __ovld vstorea_half3_rtn(float3 data, size_t offset, half *p); void __ovld vstorea_half4_rtn(float4 data, size_t offset, half *p); @@ -12157,35 +12150,30 @@ void __ovld vstorea_half8_rtn(float8 data, size_t offset, half *p); void __ovld vstorea_half16_rtn(float16 data, size_t offset, half *p); #ifdef cl_khr_fp64 -void __ovld vstorea_half(double data, size_t offset, half *p); void __ovld vstorea_half2(double2 data, size_t offset, half *p); void __ovld vstorea_half3(double3 data, size_t offset, half *p); void __ovld vstorea_half4(double4 data, size_t offset, half *p); void __ovld vstorea_half8(double8 data, size_t offset, half *p); void __ovld vstorea_half16(double16 data, size_t offset, half *p); -void __ovld vstorea_half_rte(double data, size_t offset, half *p); void __ovld vstorea_half2_rte(double2 data, size_t offset, half *p); void __ovld vstorea_half3_rte(double3 data, size_t offset, half *p); void __ovld vstorea_half4_rte(double4 data, size_t offset, half *p); void __ovld vstorea_half8_rte(double8 data, size_t offset, half *p); void __ovld vstorea_half16_rte(double16 data, size_t offset, half *p); -void __ovld vstorea_half_rtz(double data, size_t offset, half *p); void __ovld vstorea_half2_rtz(double2 data, size_t offset, half *p); void __ovld vstorea_half3_rtz(double3 data, size_t offset, half *p); void __ovld vstorea_half4_rtz(double4 data, size_t offset, half *p); void __ovld vstorea_half8_rtz(double8 data, size_t offset, half *p); void __ovld vstorea_half16_rtz(double16 data, size_t offset, half *p); -void __ovld vstorea_half_rtp(double data, size_t offset, half *p); void __ovld vstorea_half2_rtp(double2 data, size_t offset, half *p); void __ovld vstorea_half3_rtp(double3 data, size_t offset, half *p); void __ovld vstorea_half4_rtp(double4 data, size_t offset, half *p); void __ovld vstorea_half8_rtp(double8 data, size_t offset, half *p); void __ovld vstorea_half16_rtp(double16 data, size_t offset, half *p); -void __ovld vstorea_half_rtn(double data, size_t offset, half *p); void __ovld vstorea_half2_rtn(double2 data, size_t offset, half *p); void __ovld vstorea_half3_rtn(double3 data, size_t offset, half *p); void __ovld vstorea_half4_rtn(double4 data, size_t offset, half *p); @@ -12194,105 +12182,90 @@ void __ovld vstorea_half16_rtn(double16 data, size_t offset, half *p); #endif //cl_khr_fp64 #else -void __ovld vstorea_half(float data, size_t offset, __global half *p); void __ovld vstorea_half2(float2 data, size_t offset, __global half *p); void __ovld vstorea_half3(float3 data, size_t offset, __global half *p); void __ovld vstorea_half4(float4 data, size_t offset, __global half *p); void __ovld vstorea_half8(float8 data, size_t offset, __global half *p); void __ovld vstorea_half16(float16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rte(float data, size_t offset, __global half *p); void __ovld vstorea_half2_rte(float2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rte(float3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rte(float4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rte(float8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rte(float16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtz(float data, size_t offset, __global half *p); void __ovld vstorea_half2_rtz(float2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtz(float3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtz(float4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtz(float8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtz(float16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtp(float data, size_t offset, __global half *p); void __ovld vstorea_half2_rtp(float2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtp(float3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtp(float4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtp(float8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtp(float16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtn(float data, size_t offset, __global half *p); void __ovld vstorea_half2_rtn(float2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtn(float3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtn(float4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtn(float8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtn(float16 data, size_t offset, __global half *p); -void __ovld vstorea_half(float data, size_t offset, __local half *p); void __ovld vstorea_half2(float2 data, size_t offset, __local half *p); void __ovld vstorea_half3(float3 data, size_t offset, __local half *p); void __ovld vstorea_half4(float4 data, size_t offset, __local half *p); void __ovld vstorea_half8(float8 data, size_t offset, __local half *p); void __ovld vstorea_half16(float16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rte(float data, size_t offset, __local half *p); void __ovld vstorea_half2_rte(float2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rte(float3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rte(float4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rte(float8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rte(float16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtz(float data, size_t offset, __local half *p); void __ovld vstorea_half2_rtz(float2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtz(float3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtz(float4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtz(float8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtz(float16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtp(float data, size_t offset, __local half *p); void __ovld vstorea_half2_rtp(float2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtp(float3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtp(float4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtp(float8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtp(float16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtn(float data, size_t offset, __local half *p); void __ovld vstorea_half2_rtn(float2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtn(float3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtn(float4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtn(float8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtn(float16 data, size_t offset, __local half *p); -void __ovld vstorea_half(float data, size_t offset, __private half *p); void __ovld vstorea_half2(float2 data, size_t offset, __private half *p); void __ovld vstorea_half3(float3 data, size_t offset, __private half *p); void __ovld vstorea_half4(float4 data, size_t offset, __private half *p); void __ovld vstorea_half8(float8 data, size_t offset, __private half *p); void __ovld vstorea_half16(float16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rte(float data, size_t offset, __private half *p); void __ovld vstorea_half2_rte(float2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rte(float3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rte(float4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rte(float8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rte(float16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtz(float data, size_t offset, __private half *p); void __ovld vstorea_half2_rtz(float2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rtz(float3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rtz(float4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rtz(float8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rtz(float16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtp(float data, size_t offset, __private half *p); void __ovld vstorea_half2_rtp(float2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rtp(float3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rtp(float4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rtp(float8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rtp(float16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtn(float data, size_t offset, __private half *p); void __ovld vstorea_half2_rtn(float2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rtn(float3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rtn(float4 data, size_t offset, __private half *p); @@ -12300,105 +12273,90 @@ void __ovld vstorea_half8_rtn(float8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rtn(float16 data, size_t offset, __private half *p); #ifdef cl_khr_fp64 -void __ovld vstorea_half(double data, size_t offset, __global half *p); void __ovld vstorea_half2(double2 data, size_t offset, __global half *p); void __ovld vstorea_half3(double3 data, size_t offset, __global half *p); void __ovld vstorea_half4(double4 data, size_t offset, __global half *p); void __ovld vstorea_half8(double8 data, size_t offset, __global half *p); void __ovld vstorea_half16(double16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rte(double data, size_t offset, __global half *p); void __ovld vstorea_half2_rte(double2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rte(double3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rte(double4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rte(double8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rte(double16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtz(double data, size_t offset, __global half *p); void __ovld vstorea_half2_rtz(double2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtz(double3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtz(double4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtz(double8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtz(double16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtp(double data, size_t offset, __global half *p); void __ovld vstorea_half2_rtp(double2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtp(double3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtp(double4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtp(double8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtp(double16 data, size_t offset, __global half *p); -void __ovld vstorea_half_rtn(double data, size_t offset, __global half *p); void __ovld vstorea_half2_rtn(double2 data, size_t offset, __global half *p); void __ovld vstorea_half3_rtn(double3 data, size_t offset, __global half *p); void __ovld vstorea_half4_rtn(double4 data, size_t offset, __global half *p); void __ovld vstorea_half8_rtn(double8 data, size_t offset, __global half *p); void __ovld vstorea_half16_rtn(double16 data, size_t offset, __global half *p); -void __ovld vstorea_half(double data, size_t offset, __local half *p); void __ovld vstorea_half2(double2 data, size_t offset, __local half *p); void __ovld vstorea_half3(double3 data, size_t offset, __local half *p); void __ovld vstorea_half4(double4 data, size_t offset, __local half *p); void __ovld vstorea_half8(double8 data, size_t offset, __local half *p); void __ovld vstorea_half16(double16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rte(double data, size_t offset, __local half *p); void __ovld vstorea_half2_rte(double2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rte(double3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rte(double4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rte(double8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rte(double16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtz(double data, size_t offset, __local half *p); void __ovld vstorea_half2_rtz(double2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtz(double3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtz(double4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtz(double8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtz(double16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtp(double data, size_t offset, __local half *p); void __ovld vstorea_half2_rtp(double2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtp(double3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtp(double4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtp(double8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtp(double16 data, size_t offset, __local half *p); -void __ovld vstorea_half_rtn(double data, size_t offset, __local half *p); void __ovld vstorea_half2_rtn(double2 data, size_t offset, __local half *p); void __ovld vstorea_half3_rtn(double3 data, size_t offset, __local half *p); void __ovld vstorea_half4_rtn(double4 data, size_t offset, __local half *p); void __ovld vstorea_half8_rtn(double8 data, size_t offset, __local half *p); void __ovld vstorea_half16_rtn(double16 data, size_t offset, __local half *p); -void __ovld vstorea_half(double data, size_t offset, __private half *p); void __ovld vstorea_half2(double2 data, size_t offset, __private half *p); void __ovld vstorea_half3(double3 data, size_t offset, __private half *p); void __ovld vstorea_half4(double4 data, size_t offset, __private half *p); void __ovld vstorea_half8(double8 data, size_t offset, __private half *p); void __ovld vstorea_half16(double16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rte(double data, size_t offset, __private half *p); void __ovld vstorea_half2_rte(double2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rte(double3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rte(double4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rte(double8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rte(double16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtz(double data, size_t offset, __private half *p); void __ovld vstorea_half2_rtz(double2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rtz(double3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rtz(double4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rtz(double8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rtz(double16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtp(double data, size_t offset, __private half *p); void __ovld vstorea_half2_rtp(double2 data, size_t offset, __private half *p); void __ovld vstorea_half3_rtp(double3 data, size_t offset, __private half *p); void __ovld vstorea_half4_rtp(double4 data, size_t offset, __private half *p); void __ovld vstorea_half8_rtp(double8 data, size_t offset, __private half *p); void __ovld vstorea_half16_rtp(double16 data, size_t offset, __private half *p); -void __ovld vstorea_half_rtn(double data, size_t offset, __private half *p); void __ovld vstorea_half2_rtn(double2 data,size_t offset, __private half *p); void __ovld vstorea_half3_rtn(double3 data,size_t offset, __private half *p); void __ovld vstorea_half4_rtn(double4 data,size_t offset, __private half *p); @@ -13289,6 +13247,7 @@ unsigned long __ovld atom_xor(volatile __local unsigned long *p, unsigned long v #endif // atomic_init() +#if defined(__opencl_c_generic_address_space) void __ovld atomic_init(volatile atomic_int *object, int value); void __ovld atomic_init(volatile atomic_uint *object, uint value); void __ovld atomic_init(volatile atomic_float *object, float value); @@ -13299,6 +13258,25 @@ void __ovld atomic_init(volatile atomic_ulong *object, ulong value); void __ovld atomic_init(volatile atomic_double *object, double value); #endif //cl_khr_fp64 #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +void __ovld atomic_init(volatile __global atomic_int *object, int value); +void __ovld atomic_init(volatile __local atomic_int *object, int value); +void __ovld atomic_init(volatile __global atomic_uint *object, uint value); +void __ovld atomic_init(volatile __local atomic_uint *object, uint value); +void __ovld atomic_init(volatile __global atomic_float *object, float value); +void __ovld atomic_init(volatile __local atomic_float *object, float value); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +void __ovld atomic_init(volatile __global atomic_long *object, long value); +void __ovld atomic_init(volatile __local atomic_long *object, long value); +void __ovld atomic_init(volatile __global atomic_ulong *object, ulong value); +void __ovld atomic_init(volatile __local atomic_ulong *object, ulong value); +#ifdef cl_khr_fp64 +void __ovld atomic_init(volatile __global atomic_double *object, double value); +void __ovld atomic_init(volatile __local atomic_double *object, double value); +#endif //cl_khr_fp64 +#endif +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) // atomic_work_item_fence() void __ovld atomic_work_item_fence(cl_mem_fence_flags flags, memory_order order, memory_scope scope); @@ -13308,6 +13286,7 @@ void __ovld atomic_work_item_fence(cl_mem_fence_flags flags, memory_order order, // add/sub: atomic type argument can be uintptr_t/intptr_t, value type argument can be ptrdiff_t. #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_fetch_add(volatile atomic_int *object, int operand); uint __ovld atomic_fetch_add(volatile atomic_uint *object, uint operand); int __ovld atomic_fetch_sub(volatile atomic_int *object, int operand); @@ -13322,7 +13301,6 @@ int __ovld atomic_fetch_min(volatile atomic_int *object, int operand); uint __ovld atomic_fetch_min(volatile atomic_uint *object, uint operand); int __ovld atomic_fetch_max(volatile atomic_int *object, int operand); uint __ovld atomic_fetch_max(volatile atomic_uint *object, uint operand); - #if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) long __ovld atomic_fetch_add(volatile atomic_long *object, long operand); ulong __ovld atomic_fetch_add(volatile atomic_ulong *object, ulong operand); @@ -13341,9 +13319,93 @@ ulong __ovld atomic_fetch_max(volatile atomic_ulong *object, ulong operand); uintptr_t __ovld atomic_fetch_add(volatile atomic_uintptr_t *object, ptrdiff_t operand); uintptr_t __ovld atomic_fetch_sub(volatile atomic_uintptr_t *object, ptrdiff_t operand); #endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_fetch_add(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_add(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_add(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_add(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_sub(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_sub(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_sub(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_sub(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_or(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_or(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_or(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_or(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_xor(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_xor(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_xor(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_xor(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_and(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_and(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_and(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_and(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_min(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_min(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_min(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_min(volatile __local atomic_uint *object, uint operand); +int __ovld atomic_fetch_max(volatile __global atomic_int *object, int operand); +int __ovld atomic_fetch_max(volatile __local atomic_int *object, int operand); +uint __ovld atomic_fetch_max(volatile __global atomic_uint *object, uint operand); +uint __ovld atomic_fetch_max(volatile __local atomic_uint *object, uint operand); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +long __ovld atomic_fetch_add(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_add(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_add(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_add(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_add(volatile __global atomic_uintptr_t *object, ptrdiff_t operand); +uintptr_t __ovld atomic_fetch_add(volatile __local atomic_uintptr_t *object, ptrdiff_t operand); +long __ovld atomic_fetch_sub(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_sub(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_sub(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_sub(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_sub(volatile __global atomic_uintptr_t *object, ptrdiff_t operand); +uintptr_t __ovld atomic_fetch_sub(volatile __local atomic_uintptr_t *object, ptrdiff_t operand); +long __ovld atomic_fetch_or(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_or(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_or(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_or(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_or(volatile __global atomic_uintptr_t *object, intptr_t operand); +uintptr_t __ovld atomic_fetch_or(volatile __local atomic_uintptr_t *object, intptr_t operand); +intptr_t __ovld atomic_fetch_or(volatile __global atomic_intptr_t *object, uintptr_t operand); +intptr_t __ovld atomic_fetch_or(volatile __local atomic_intptr_t *object, uintptr_t operand); +long __ovld atomic_fetch_xor(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_xor(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_xor(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_xor(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_xor(volatile __global atomic_uintptr_t *object, intptr_t operand); +uintptr_t __ovld atomic_fetch_xor(volatile __local atomic_uintptr_t *object, intptr_t operand); +intptr_t __ovld atomic_fetch_xor(volatile __global atomic_intptr_t *object, uintptr_t operand); +intptr_t __ovld atomic_fetch_xor(volatile __local atomic_intptr_t *object, uintptr_t operand); +long __ovld atomic_fetch_and(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_and(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_and(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_and(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_and(volatile __global atomic_uintptr_t *object, intptr_t operand); +uintptr_t __ovld atomic_fetch_and(volatile __local atomic_uintptr_t *object, intptr_t operand); +intptr_t __ovld atomic_fetch_and(volatile __global atomic_intptr_t *object, uintptr_t operand); +intptr_t __ovld atomic_fetch_and(volatile __local atomic_intptr_t *object, uintptr_t operand); +long __ovld atomic_fetch_min(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_min(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_min(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_min(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_min(volatile __global atomic_uintptr_t *object, intptr_t operand); +uintptr_t __ovld atomic_fetch_min(volatile __local atomic_uintptr_t *object, intptr_t operand); +intptr_t __ovld atomic_fetch_min(volatile __global atomic_intptr_t *object, uintptr_t operand); +intptr_t __ovld atomic_fetch_min(volatile __local atomic_intptr_t *object, uintptr_t operand); +long __ovld atomic_fetch_max(volatile __global atomic_long *object, long operand); +long __ovld atomic_fetch_max(volatile __local atomic_long *object, long operand); +ulong __ovld atomic_fetch_max(volatile __global atomic_ulong *object, ulong operand); +ulong __ovld atomic_fetch_max(volatile __local atomic_ulong *object, ulong operand); +uintptr_t __ovld atomic_fetch_add(volatile __global atomic_uintptr_t *object, ptrdiff_t operand); +uintptr_t __ovld atomic_fetch_sub(volatile __local atomic_uintptr_t *object, ptrdiff_t operand); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif #if defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_fetch_add_explicit(volatile atomic_int *object, int operand, memory_order order); uint __ovld atomic_fetch_add_explicit(volatile atomic_uint *object, uint operand, memory_order order); int __ovld atomic_fetch_sub_explicit(volatile atomic_int *object, int operand, memory_order order); @@ -13376,8 +13438,92 @@ ulong __ovld atomic_fetch_max_explicit(volatile atomic_ulong *object, ulong oper uintptr_t __ovld atomic_fetch_add_explicit(volatile atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); uintptr_t __ovld atomic_fetch_sub_explicit(volatile atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); #endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_fetch_add_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_add_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_add_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_add_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_sub_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_sub_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_sub_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_sub_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_or_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_or_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_or_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_or_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_xor_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_xor_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_xor_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_xor_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_and_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_and_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_and_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_and_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_min_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_min_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_min_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_min_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +int __ovld atomic_fetch_max_explicit(volatile __global atomic_int *object, int operand, memory_order order); +int __ovld atomic_fetch_max_explicit(volatile __local atomic_int *object, int operand, memory_order order); +uint __ovld atomic_fetch_max_explicit(volatile __global atomic_uint *object, uint operand, memory_order order); +uint __ovld atomic_fetch_max_explicit(volatile __local atomic_uint *object, uint operand, memory_order order); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +long __ovld atomic_fetch_add_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_add_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_add_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_add_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +long __ovld atomic_fetch_sub_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_sub_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_sub_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_sub_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +long __ovld atomic_fetch_or_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_or_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_or_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_or_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_or_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_or_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_or_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_or_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order); +long __ovld atomic_fetch_xor_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_xor_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_xor_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_xor_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_xor_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_xor_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_xor_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_xor_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order); +long __ovld atomic_fetch_and_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_and_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_and_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_and_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_and_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_and_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_and_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_and_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order); +long __ovld atomic_fetch_min_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_min_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_min_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_min_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_min_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_min_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_min_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order); +intptr_t __ovld atomic_fetch_min_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order); +long __ovld atomic_fetch_max_explicit(volatile __global atomic_long *object, long operand, memory_order order); +long __ovld atomic_fetch_max_explicit(volatile __local atomic_long *object, long operand, memory_order order); +ulong __ovld atomic_fetch_max_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order); +ulong __ovld atomic_fetch_max_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) int __ovld atomic_fetch_add_explicit(volatile atomic_int *object, int operand, memory_order order, memory_scope scope); uint __ovld atomic_fetch_add_explicit(volatile atomic_uint *object, uint operand, memory_order order, memory_scope scope); int __ovld atomic_fetch_sub_explicit(volatile atomic_int *object, int operand, memory_order order, memory_scope scope); @@ -13407,15 +13553,469 @@ long __ovld atomic_fetch_min_explicit(volatile atomic_long *object, long operand ulong __ovld atomic_fetch_min_explicit(volatile atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); long __ovld atomic_fetch_max_explicit(volatile atomic_long *object, long operand, memory_order order, memory_scope scope); ulong __ovld atomic_fetch_max_explicit(volatile atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); -#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) -#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) uintptr_t __ovld atomic_fetch_add_explicit(volatile atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); uintptr_t __ovld atomic_fetch_sub_explicit(volatile atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_fetch_add_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_add_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_add_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_add_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_sub_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_sub_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_sub_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_sub_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_or_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_or_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_or_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_or_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_xor_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_xor_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_xor_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_xor_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_and_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_and_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_and_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_and_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_min_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_min_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_min_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_min_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_max_explicit(volatile __global atomic_int *object, int operand, memory_order order, memory_scope scope); +int __ovld atomic_fetch_max_explicit(volatile __local atomic_int *object, int operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_max_explicit(volatile __global atomic_uint *object, uint operand, memory_order order, memory_scope scope); +uint __ovld atomic_fetch_max_explicit(volatile __local atomic_uint *object, uint operand, memory_order order, memory_scope scope); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +long __ovld atomic_fetch_add_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_add_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_add_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_add_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_sub_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_sub_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_sub_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_sub_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_or_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_or_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_or_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_or_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_or_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_or_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_or_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_or_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_xor_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_xor_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_xor_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_xor_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_xor_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_xor_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_xor_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_xor_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_and_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_and_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_and_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_and_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_and_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_and_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_and_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_and_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_min_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_min_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_min_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_min_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_min_explicit(volatile __global atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_min_explicit(volatile __local atomic_uintptr_t *object, intptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_min_explicit(volatile __global atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +intptr_t __ovld atomic_fetch_min_explicit(volatile __local atomic_intptr_t *object, uintptr_t operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_max_explicit(volatile __global atomic_long *object, long operand, memory_order order, memory_scope scope); +long __ovld atomic_fetch_max_explicit(volatile __local atomic_long *object, long operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_max_explicit(volatile __global atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +ulong __ovld atomic_fetch_max_explicit(volatile __local atomic_ulong *object, ulong operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_add_explicit(volatile __global atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +uintptr_t __ovld atomic_fetch_sub_explicit(volatile __local atomic_uintptr_t *object, ptrdiff_t operand, memory_order order, memory_scope scope); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) + +// The functionality added by cl_ext_float_atomics extension +#if defined(cl_ext_float_atomics) + +#if defined(__opencl_c_ext_fp16_global_atomic_load_store) +void __ovld atomic_store(volatile __global atomic_half *object, half operand); +void __ovld atomic_store_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +void __ovld atomic_store_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_load(volatile __global atomic_half *object); +half __ovld atomic_load_explicit(volatile __global atomic_half *object, + memory_order order); +half __ovld atomic_load_explicit(volatile __global atomic_half *object, + memory_order order, memory_scope scope); +half __ovld atomic_exchange(volatile __global atomic_half *object, + half operand); +half __ovld atomic_exchange_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +half __ovld atomic_exchange_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_load_store) + +#if defined(__opencl_c_ext_fp16_local_atomic_load_store) +void __ovld atomic_store(volatile __local atomic_half *object, half operand); +void __ovld atomic_store_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_load(volatile __local atomic_half *object); +half __ovld atomic_load_explicit(volatile __local atomic_half *object, + memory_order order); +half __ovld atomic_load_explicit(volatile __local atomic_half *object, + memory_order order, memory_scope scope); +half __ovld atomic_exchange(volatile __local atomic_half *object, half operand); +half __ovld atomic_exchange_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +half __ovld atomic_exchange_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_local_atomic_load_store) + +#if defined(__opencl_c_ext_fp16_global_atomic_load_store) && \ + defined(__opencl_c_ext_fp16_local_atomic_load_store) +void __ovld atomic_store(volatile atomic_half *object, half operand); +void __ovld atomic_store_explicit(volatile atomic_half *object, half operand, + memory_order order); +void __ovld atomic_store_explicit(volatile atomic_half *object, half operand, + memory_order order, memory_scope scope); +half __ovld atomic_load(volatile atomic_half *object); +half __ovld atomic_load_explicit(volatile atomic_half *object, + memory_order order); +half __ovld atomic_load_explicit(volatile atomic_half *object, + memory_order order, memory_scope scope); +half __ovld atomic_exchange(volatile atomic_half *object, half operand); +half __ovld atomic_exchange_explicit(volatile atomic_half *object, half operand, + memory_order order); +half __ovld atomic_exchange_explicit(volatile atomic_half *object, half operand, + memory_order order, memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_load_store) && + // defined(__opencl_c_ext_fp16_local_atomic_load_store) + +#if defined(__opencl_c_ext_fp16_global_atomic_min_max) +half __ovld atomic_fetch_min(volatile __global atomic_half *object, + half operand); +half __ovld atomic_fetch_max(volatile __global atomic_half *object, + half operand); +half __ovld atomic_fetch_min_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_max_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_min_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_max_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_min_max) + +#if defined(__opencl_c_ext_fp16_local_atomic_min_max) +half __ovld atomic_fetch_min(volatile __local atomic_half *object, + half operand); +half __ovld atomic_fetch_max(volatile __local atomic_half *object, + half operand); +half __ovld atomic_fetch_min_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_max_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_min_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_max_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp16_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp16_local_atomic_min_max) +half __ovld atomic_fetch_min(volatile atomic_half *object, half operand); +half __ovld atomic_fetch_max(volatile atomic_half *object, half operand); +half __ovld atomic_fetch_min_explicit(volatile atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_max_explicit(volatile atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_min_explicit(volatile atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_max_explicit(volatile atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp16_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp32_global_atomic_min_max) +float __ovld atomic_fetch_min(volatile __global atomic_float *object, + float operand); +float __ovld atomic_fetch_max(volatile __global atomic_float *object, + float operand); +float __ovld atomic_fetch_min_explicit(volatile __global atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_max_explicit(volatile __global atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_min_explicit(volatile __global atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_max_explicit(volatile __global atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_global_atomic_min_max) + +#if defined(__opencl_c_ext_fp32_local_atomic_min_max) +float __ovld atomic_fetch_min(volatile __local atomic_float *object, + float operand); +float __ovld atomic_fetch_max(volatile __local atomic_float *object, + float operand); +float __ovld atomic_fetch_min_explicit(volatile __local atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_max_explicit(volatile __local atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_min_explicit(volatile __local atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_max_explicit(volatile __local atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp32_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp32_local_atomic_min_max) +float __ovld atomic_fetch_min(volatile atomic_float *object, float operand); +float __ovld atomic_fetch_max(volatile atomic_float *object, float operand); +float __ovld atomic_fetch_min_explicit(volatile atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_max_explicit(volatile atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_min_explicit(volatile atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_max_explicit(volatile atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp32_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp64_global_atomic_min_max) +double __ovld atomic_fetch_min(volatile __global atomic_double *object, + double operand); +double __ovld atomic_fetch_max(volatile __global atomic_double *object, + double operand); +double __ovld atomic_fetch_min_explicit(volatile __global atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_max_explicit(volatile __global atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_min_explicit(volatile __global atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_max_explicit(volatile __global atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_global_atomic_min_max) + +#if defined(__opencl_c_ext_fp64_local_atomic_min_max) +double __ovld atomic_fetch_min(volatile __local atomic_double *object, + double operand); +double __ovld atomic_fetch_max(volatile __local atomic_double *object, + double operand); +double __ovld atomic_fetch_min_explicit(volatile __local atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_max_explicit(volatile __local atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_min_explicit(volatile __local atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_max_explicit(volatile __local atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp64_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp64_local_atomic_min_max) +double __ovld atomic_fetch_min(volatile atomic_double *object, double operand); +double __ovld atomic_fetch_max(volatile atomic_double *object, double operand); +double __ovld atomic_fetch_min_explicit(volatile atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_max_explicit(volatile atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_min_explicit(volatile atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_max_explicit(volatile atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_global_atomic_min_max) && \ + defined(__opencl_c_ext_fp64_local_atomic_min_max) + +#if defined(__opencl_c_ext_fp16_global_atomic_add) +half __ovld atomic_fetch_add(volatile __global atomic_half *object, + half operand); +half __ovld atomic_fetch_sub(volatile __global atomic_half *object, + half operand); +half __ovld atomic_fetch_add_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_sub_explicit(volatile __global atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_add_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_sub_explicit(volatile __global atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_add) + +#if defined(__opencl_c_ext_fp16_local_atomic_add) +half __ovld atomic_fetch_add(volatile __local atomic_half *object, + half operand); +half __ovld atomic_fetch_sub(volatile __local atomic_half *object, + half operand); +half __ovld atomic_fetch_add_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_sub_explicit(volatile __local atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_add_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_sub_explicit(volatile __local atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_local_atomic_add) + +#if defined(__opencl_c_ext_fp16_global_atomic_add) && \ + defined(__opencl_c_ext_fp16_local_atomic_add) +half __ovld atomic_fetch_add(volatile atomic_half *object, half operand); +half __ovld atomic_fetch_sub(volatile atomic_half *object, half operand); +half __ovld atomic_fetch_add_explicit(volatile atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_sub_explicit(volatile atomic_half *object, + half operand, memory_order order); +half __ovld atomic_fetch_add_explicit(volatile atomic_half *object, + half operand, memory_order order, + memory_scope scope); +half __ovld atomic_fetch_sub_explicit(volatile atomic_half *object, + half operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp16_global_atomic_add) && \ + defined(__opencl_c_ext_fp16_local_atomic_add) + +#if defined(__opencl_c_ext_fp32_global_atomic_add) +float __ovld atomic_fetch_add(volatile __global atomic_float *object, + float operand); +float __ovld atomic_fetch_sub(volatile __global atomic_float *object, + float operand); +float __ovld atomic_fetch_add_explicit(volatile __global atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_sub_explicit(volatile __global atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_add_explicit(volatile __global atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_sub_explicit(volatile __global atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_global_atomic_add) + +#if defined(__opencl_c_ext_fp32_local_atomic_add) +float __ovld atomic_fetch_add(volatile __local atomic_float *object, + float operand); +float __ovld atomic_fetch_sub(volatile __local atomic_float *object, + float operand); +float __ovld atomic_fetch_add_explicit(volatile __local atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_sub_explicit(volatile __local atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_add_explicit(volatile __local atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_sub_explicit(volatile __local atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_local_atomic_add) + +#if defined(__opencl_c_ext_fp32_global_atomic_add) && \ + defined(__opencl_c_ext_fp32_local_atomic_add) +float __ovld atomic_fetch_add(volatile atomic_float *object, float operand); +float __ovld atomic_fetch_sub(volatile atomic_float *object, float operand); +float __ovld atomic_fetch_add_explicit(volatile atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_sub_explicit(volatile atomic_float *object, + float operand, memory_order order); +float __ovld atomic_fetch_add_explicit(volatile atomic_float *object, + float operand, memory_order order, + memory_scope scope); +float __ovld atomic_fetch_sub_explicit(volatile atomic_float *object, + float operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp32_global_atomic_add) && \ + defined(__opencl_c_ext_fp32_local_atomic_add) + +#if defined(__opencl_c_ext_fp64_global_atomic_add) +double __ovld atomic_fetch_add(volatile __global atomic_double *object, + double operand); +double __ovld atomic_fetch_sub(volatile __global atomic_double *object, + double operand); +double __ovld atomic_fetch_add_explicit(volatile __global atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_sub_explicit(volatile __global atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_add_explicit(volatile __global atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_sub_explicit(volatile __global atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_global_atomic_add) + +#if defined(__opencl_c_ext_fp64_local_atomic_add) +double __ovld atomic_fetch_add(volatile __local atomic_double *object, + double operand); +double __ovld atomic_fetch_sub(volatile __local atomic_double *object, + double operand); +double __ovld atomic_fetch_add_explicit(volatile __local atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_sub_explicit(volatile __local atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_add_explicit(volatile __local atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_sub_explicit(volatile __local atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_local_atomic_add) + +#if defined(__opencl_c_ext_fp64_global_atomic_add) && \ + defined(__opencl_c_ext_fp64_local_atomic_add) +double __ovld atomic_fetch_add(volatile atomic_double *object, double operand); +double __ovld atomic_fetch_sub(volatile atomic_double *object, double operand); +double __ovld atomic_fetch_add_explicit(volatile atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_sub_explicit(volatile atomic_double *object, + double operand, memory_order order); +double __ovld atomic_fetch_add_explicit(volatile atomic_double *object, + double operand, memory_order order, + memory_scope scope); +double __ovld atomic_fetch_sub_explicit(volatile atomic_double *object, + double operand, memory_order order, + memory_scope scope); +#endif // defined(__opencl_c_ext_fp64_global_atomic_add) && \ + defined(__opencl_c_ext_fp64_local_atomic_add) + +#endif // cl_ext_float_atomics // atomic_store() #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) void __ovld atomic_store(volatile atomic_int *object, int desired); void __ovld atomic_store(volatile atomic_uint *object, uint desired); void __ovld atomic_store(volatile atomic_float *object, float desired); @@ -13427,9 +14027,29 @@ void __ovld atomic_store(volatile atomic_double *object, double desired); void __ovld atomic_store(volatile atomic_long *object, long desired); void __ovld atomic_store(volatile atomic_ulong *object, ulong desired); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +void __ovld atomic_store(volatile __global atomic_int *object, int desired); +void __ovld atomic_store(volatile __local atomic_int *object, int desired); +void __ovld atomic_store(volatile __global atomic_uint *object, uint desired); +void __ovld atomic_store(volatile __local atomic_uint *object, uint desired); +void __ovld atomic_store(volatile __global atomic_float *object, float desired); +void __ovld atomic_store(volatile __local atomic_float *object, float desired); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +void __ovld atomic_store(volatile __global atomic_double *object, double desired); +void __ovld atomic_store(volatile __local atomic_double *object, double desired); +#endif //cl_khr_fp64 +void __ovld atomic_store(volatile __global atomic_long *object, long desired); +void __ovld atomic_store(volatile __local atomic_long *object, long desired); +void __ovld atomic_store(volatile __global atomic_ulong *object, ulong desired); +void __ovld atomic_store(volatile __local atomic_ulong *object, ulong desired); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif #if defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) void __ovld atomic_store_explicit(volatile atomic_int *object, int desired, memory_order order); void __ovld atomic_store_explicit(volatile atomic_uint *object, uint desired, memory_order order); void __ovld atomic_store_explicit(volatile atomic_float *object, float desired, memory_order order); @@ -13440,8 +14060,28 @@ void __ovld atomic_store_explicit(volatile atomic_double *object, double desired void __ovld atomic_store_explicit(volatile atomic_long *object, long desired, memory_order order); void __ovld atomic_store_explicit(volatile atomic_ulong *object, ulong desired, memory_order order); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +void __ovld atomic_store_explicit(volatile __global atomic_int *object, int desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_int *object, int desired, memory_order order); +void __ovld atomic_store_explicit(volatile __global atomic_uint *object, uint desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_uint *object, uint desired, memory_order order); +void __ovld atomic_store_explicit(volatile __global atomic_float *object, float desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_float *object, float desired, memory_order order); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +void __ovld atomic_store_explicit(volatile __global atomic_double *object, double desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_double *object, double desired, memory_order order); +#endif +void __ovld atomic_store_explicit(volatile __global atomic_long *object, long desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_long *object, long desired, memory_order order); +void __ovld atomic_store_explicit(volatile __global atomic_ulong *object, ulong desired, memory_order order); +void __ovld atomic_store_explicit(volatile __local atomic_ulong *object, ulong desired, memory_order order); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) void __ovld atomic_store_explicit(volatile atomic_int *object, int desired, memory_order order, memory_scope scope); void __ovld atomic_store_explicit(volatile atomic_uint *object, uint desired, memory_order order, memory_scope scope); void __ovld atomic_store_explicit(volatile atomic_float *object, float desired, memory_order order, memory_scope scope); @@ -13452,9 +14092,29 @@ void __ovld atomic_store_explicit(volatile atomic_double *object, double desired void __ovld atomic_store_explicit(volatile atomic_long *object, long desired, memory_order order, memory_scope scope); void __ovld atomic_store_explicit(volatile atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +void __ovld atomic_store_explicit(volatile __global atomic_int *object, int desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_int *object, int desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __global atomic_uint *object, uint desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_uint *object, uint desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __global atomic_float *object, float desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_float *object, float desired, memory_order order, memory_scope scope); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +void __ovld atomic_store_explicit(volatile __global atomic_double *object, double desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_double *object, double desired, memory_order order, memory_scope scope); +#endif //cl_khr_fp64 +void __ovld atomic_store_explicit(volatile __global atomic_long *object, long desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_long *object, long desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __global atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); +void __ovld atomic_store_explicit(volatile __local atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) // atomic_load() #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_load(volatile atomic_int *object); uint __ovld atomic_load(volatile atomic_uint *object); float __ovld atomic_load(volatile atomic_float *object); @@ -13465,9 +14125,29 @@ double __ovld atomic_load(volatile atomic_double *object); long __ovld atomic_load(volatile atomic_long *object); ulong __ovld atomic_load(volatile atomic_ulong *object); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_load(volatile __global atomic_int *object); +int __ovld atomic_load(volatile __local atomic_int *object); +uint __ovld atomic_load(volatile __global atomic_uint *object); +uint __ovld atomic_load(volatile __local atomic_uint *object); +float __ovld atomic_load(volatile __global atomic_float *object); +float __ovld atomic_load(volatile __local atomic_float *object); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_load(volatile __global atomic_double *object); +double __ovld atomic_load(volatile __local atomic_double *object); +#endif //cl_khr_fp64 +long __ovld atomic_load(volatile __global atomic_long *object); +long __ovld atomic_load(volatile __local atomic_long *object); +ulong __ovld atomic_load(volatile __global atomic_ulong *object); +ulong __ovld atomic_load(volatile __local atomic_ulong *object); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif #if defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_load_explicit(volatile atomic_int *object, memory_order order); uint __ovld atomic_load_explicit(volatile atomic_uint *object, memory_order order); float __ovld atomic_load_explicit(volatile atomic_float *object, memory_order order); @@ -13478,8 +14158,28 @@ double __ovld atomic_load_explicit(volatile atomic_double *object, memory_order long __ovld atomic_load_explicit(volatile atomic_long *object, memory_order order); ulong __ovld atomic_load_explicit(volatile atomic_ulong *object, memory_order order); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_load_explicit(volatile __global atomic_int *object, memory_order order); +int __ovld atomic_load_explicit(volatile __local atomic_int *object, memory_order order); +uint __ovld atomic_load_explicit(volatile __global atomic_uint *object, memory_order order); +uint __ovld atomic_load_explicit(volatile __local atomic_uint *object, memory_order order); +float __ovld atomic_load_explicit(volatile __global atomic_float *object, memory_order order); +float __ovld atomic_load_explicit(volatile __local atomic_float *object, memory_order order); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_load_explicit(volatile __global atomic_double *object, memory_order order); +double __ovld atomic_load_explicit(volatile __local atomic_double *object, memory_order order); +#endif //cl_khr_fp64 +long __ovld atomic_load_explicit(volatile __global atomic_long *object, memory_order order); +long __ovld atomic_load_explicit(volatile __local atomic_long *object, memory_order order); +ulong __ovld atomic_load_explicit(volatile __global atomic_ulong *object, memory_order order); +ulong __ovld atomic_load_explicit(volatile __local atomic_ulong *object, memory_order order); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) int __ovld atomic_load_explicit(volatile atomic_int *object, memory_order order, memory_scope scope); uint __ovld atomic_load_explicit(volatile atomic_uint *object, memory_order order, memory_scope scope); float __ovld atomic_load_explicit(volatile atomic_float *object, memory_order order, memory_scope scope); @@ -13490,10 +14190,30 @@ double __ovld atomic_load_explicit(volatile atomic_double *object, memory_order long __ovld atomic_load_explicit(volatile atomic_long *object, memory_order order, memory_scope scope); ulong __ovld atomic_load_explicit(volatile atomic_ulong *object, memory_order order, memory_scope scope); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_load_explicit(volatile __global atomic_int *object, memory_order order, memory_scope scope); +int __ovld atomic_load_explicit(volatile __local atomic_int *object, memory_order order, memory_scope scope); +uint __ovld atomic_load_explicit(volatile __global atomic_uint *object, memory_order order, memory_scope scope); +uint __ovld atomic_load_explicit(volatile __local atomic_uint *object, memory_order order, memory_scope scope); +float __ovld atomic_load_explicit(volatile __global atomic_float *object, memory_order order, memory_scope scope); +float __ovld atomic_load_explicit(volatile __local atomic_float *object, memory_order order, memory_scope scope); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_load_explicit(volatile __global atomic_double *object, memory_order order, memory_scope scope); +double __ovld atomic_load_explicit(volatile __local atomic_double *object, memory_order order, memory_scope scope); +#endif +long __ovld atomic_load_explicit(volatile __global atomic_long *object, memory_order order, memory_scope scope); +long __ovld atomic_load_explicit(volatile __local atomic_long *object, memory_order order, memory_scope scope); +ulong __ovld atomic_load_explicit(volatile __global atomic_ulong *object, memory_order order, memory_scope scope); +ulong __ovld atomic_load_explicit(volatile __local atomic_ulong *object, memory_order order, memory_scope scope); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) // atomic_exchange() #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_exchange(volatile atomic_int *object, int desired); uint __ovld atomic_exchange(volatile atomic_uint *object, uint desired); float __ovld atomic_exchange(volatile atomic_float *object, float desired); @@ -13504,9 +14224,29 @@ double __ovld atomic_exchange(volatile atomic_double *object, double desired); long __ovld atomic_exchange(volatile atomic_long *object, long desired); ulong __ovld atomic_exchange(volatile atomic_ulong *object, ulong desired); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_exchange(volatile __global atomic_int *object, int desired); +int __ovld atomic_exchange(volatile __local atomic_int *object, int desired); +uint __ovld atomic_exchange(volatile __global atomic_uint *object, uint desired); +uint __ovld atomic_exchange(volatile __local atomic_uint *object, uint desired); +float __ovld atomic_exchange(volatile __global atomic_float *object, float desired); +float __ovld atomic_exchange(volatile __local atomic_float *object, float desired); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_exchange(volatile __global atomic_double *object, double desired); +double __ovld atomic_exchange(volatile __local atomic_double *object, double desired); +#endif //cl_khr_fp64 +long __ovld atomic_exchange(volatile __global atomic_long *object, long desired); +long __ovld atomic_exchange(volatile __local atomic_long *object, long desired); +ulong __ovld atomic_exchange(volatile __global atomic_ulong *object, ulong desired); +ulong __ovld atomic_exchange(volatile __local atomic_ulong *object, ulong desired); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif #if defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) int __ovld atomic_exchange_explicit(volatile atomic_int *object, int desired, memory_order order); uint __ovld atomic_exchange_explicit(volatile atomic_uint *object, uint desired, memory_order order); float __ovld atomic_exchange_explicit(volatile atomic_float *object, float desired, memory_order order); @@ -13517,8 +14257,28 @@ double __ovld atomic_exchange_explicit(volatile atomic_double *object, double de long __ovld atomic_exchange_explicit(volatile atomic_long *object, long desired, memory_order order); ulong __ovld atomic_exchange_explicit(volatile atomic_ulong *object, ulong desired, memory_order order); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_exchange_explicit(volatile __global atomic_int *object, int desired, memory_order order); +int __ovld atomic_exchange_explicit(volatile __local atomic_int *object, int desired, memory_order order); +uint __ovld atomic_exchange_explicit(volatile __global atomic_uint *object, uint desired, memory_order order); +uint __ovld atomic_exchange_explicit(volatile __local atomic_uint *object, uint desired, memory_order order); +float __ovld atomic_exchange_explicit(volatile __global atomic_float *object, float desired, memory_order order); +float __ovld atomic_exchange_explicit(volatile __local atomic_float *object, float desired, memory_order order); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_exchange_explicit(volatile __global atomic_double *object, double desired, memory_order order); +double __ovld atomic_exchange_explicit(volatile __local atomic_double *object, double desired, memory_order order); +#endif //cl_khr_fp64 +long __ovld atomic_exchange_explicit(volatile __global atomic_long *object, long desired, memory_order order); +long __ovld atomic_exchange_explicit(volatile __local atomic_long *object, long desired, memory_order order); +ulong __ovld atomic_exchange_explicit(volatile __global atomic_ulong *object, ulong desired, memory_order order); +ulong __ovld atomic_exchange_explicit(volatile __local atomic_ulong *object, ulong desired, memory_order order); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics)wi +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) int __ovld atomic_exchange_explicit(volatile atomic_int *object, int desired, memory_order order, memory_scope scope); uint __ovld atomic_exchange_explicit(volatile atomic_uint *object, uint desired, memory_order order, memory_scope scope); float __ovld atomic_exchange_explicit(volatile atomic_float *object, float desired, memory_order order, memory_scope scope); @@ -13529,16 +14289,35 @@ double __ovld atomic_exchange_explicit(volatile atomic_double *object, double de long __ovld atomic_exchange_explicit(volatile atomic_long *object, long desired, memory_order order, memory_scope scope); ulong __ovld atomic_exchange_explicit(volatile atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +int __ovld atomic_exchange_explicit(volatile __global atomic_int *object, int desired, memory_order order, memory_scope scope); +int __ovld atomic_exchange_explicit(volatile __local atomic_int *object, int desired, memory_order order, memory_scope scope); +uint __ovld atomic_exchange_explicit(volatile __global atomic_uint *object, uint desired, memory_order order, memory_scope scope); +uint __ovld atomic_exchange_explicit(volatile __local atomic_uint *object, uint desired, memory_order order, memory_scope scope); +float __ovld atomic_exchange_explicit(volatile __global atomic_float *object, float desired, memory_order order, memory_scope scope); +float __ovld atomic_exchange_explicit(volatile __local atomic_float *object, float desired, memory_order order, memory_scope scope); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +double __ovld atomic_exchange_explicit(volatile __global atomic_double *object, double desired, memory_order order, memory_scope scope); +double __ovld atomic_exchange_explicit(volatile __local atomic_double *object, double desired, memory_order order, memory_scope scope); +#endif //cl_khr_fp64 +long __ovld atomic_exchange_explicit(volatile __global atomic_long *object, long desired, memory_order order, memory_scope scope); +long __ovld atomic_exchange_explicit(volatile __local atomic_long *object, long desired, memory_order order, memory_scope scope); +ulong __ovld atomic_exchange_explicit(volatile __global atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); +ulong __ovld atomic_exchange_explicit(volatile __local atomic_ulong *object, ulong desired, memory_order order, memory_scope scope); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) // atomic_compare_exchange_strong() and atomic_compare_exchange_weak() #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_compare_exchange_strong(volatile atomic_int *object, int *expected, int desired); bool __ovld atomic_compare_exchange_strong(volatile atomic_uint *object, uint *expected, uint desired); bool __ovld atomic_compare_exchange_weak(volatile atomic_int *object, int *expected, int desired); bool __ovld atomic_compare_exchange_weak(volatile atomic_uint *object, uint *expected, uint desired); bool __ovld atomic_compare_exchange_strong(volatile atomic_float *object, float *expected, float desired); bool __ovld atomic_compare_exchange_weak(volatile atomic_float *object, float *expected, float desired); - #if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) #ifdef cl_khr_fp64 bool __ovld atomic_compare_exchange_strong(volatile atomic_double *object, double *expected, double desired); @@ -13549,8 +14328,88 @@ bool __ovld atomic_compare_exchange_weak(volatile atomic_long *object, long *exp bool __ovld atomic_compare_exchange_strong(volatile atomic_ulong *object, ulong *expected, ulong desired); bool __ovld atomic_compare_exchange_weak(volatile atomic_ulong *object, ulong *expected, ulong desired); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_int *object, __global int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_int *object, __local int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_int *object, __private int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_int *object, __global int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_int *object, __local int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_int *object, __private int *expected, int desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_uint *object, __global uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_uint *object, __local uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_uint *object, __private uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_uint *object, __global uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_uint *object, __local uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_uint *object, __private uint *expected, uint desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_float *object, __global float *expected, float desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_float *object, __local float *expected, float desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_float *object, __private float *expected, float desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_float *object, __global float *expected, float desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_float *object, __local float *expected, float desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_float *object, __private float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_int *object, __global int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_int *object, __local int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_int *object, __private int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_int *object, __global int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_int *object, __local int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_int *object, __private int *expected, int desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_uint *object, __global uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_uint *object, __local uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_uint *object, __private uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_uint *object, __global uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_uint *object, __local uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_uint *object, __private uint *expected, uint desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_float *object, __global float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_float *object, __local float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_float *object, __private float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_float *object, __global float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_float *object, __local float *expected, float desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_float *object, __private float *expected, float desired); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_double *object, __global double *expected, double desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_double *object, __local double *expected, double desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_double *object, __private double *expected, double desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_double *object, __global double *expected, double desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_double *object, __local double *expected, double desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_double *object, __private double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_double *object, __global double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_double *object, __local double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_double *object, __private double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_double *object, __global double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_double *object, __local double *expected, double desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_double *object, __private double *expected, double desired); +#endif //cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_long *object, __global long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_long *object, __local long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_long *object, __private long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_long *object, __global long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_long *object, __local long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_long *object, __private long *expected, long desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_ulong *object, __global ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_ulong *object, __local ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_strong(volatile __global atomic_ulong *object, __private ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_ulong *object, __global ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_ulong *object, __local ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_strong(volatile __local atomic_ulong *object, __private ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_long *object, __global long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_long *object, __local long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_long *object, __private long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_long *object, __global long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_long *object, __local long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_long *object, __private long *expected, long desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_ulong *object, __global ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_ulong *object, __local ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __global atomic_ulong *object, __private ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_ulong *object, __global ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_ulong *object, __local ulong *expected, ulong desired); +bool __ovld atomic_compare_exchange_weak(volatile __local atomic_ulong *object, __private ulong *expected, ulong desired); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_int *object, int *expected, int desired, memory_order success, memory_order failure); bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_uint *object, uint *expected, @@ -13579,7 +14438,159 @@ bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_ulong *objec bool __ovld atomic_compare_exchange_weak_explicit(volatile atomic_ulong *object, ulong *expected, ulong desired, memory_order success, memory_order failure); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure); +#endif //cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_int *object, int *expected, int desired, memory_order success, memory_order failure, memory_scope scope); bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_uint *object, uint *expected, @@ -13608,20 +14619,195 @@ bool __ovld atomic_compare_exchange_strong_explicit(volatile atomic_ulong *objec bool __ovld atomic_compare_exchange_weak_explicit(volatile atomic_ulong *object, ulong *expected, ulong desired, memory_order success, memory_order failure, memory_scope scope); #endif +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __global int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __local int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_int *object, __private int *expected, + int desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __global uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __local uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_uint *object, __private uint *expected, + uint desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __global float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __local float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_float *object, __private float *expected, + float desired, memory_order success, memory_order failure, memory_scope scope); +#if defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#ifdef cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __global double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __local double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_double *object, __private double *expected, + double desired, memory_order success, memory_order failure, memory_scope scope); +#endif //cl_khr_fp64 +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __global atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_strong_explicit(volatile __local atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __global long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __local long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_long *object, __private long *expected, + long desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __global atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __global ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __local ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +bool __ovld atomic_compare_exchange_weak_explicit(volatile __local atomic_ulong *object, __private ulong *expected, + ulong desired, memory_order success, memory_order failure, memory_scope scope); +#endif //defined(cl_khr_int64_base_atomics) && defined(cl_khr_int64_extended_atomics) +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) // atomic_flag_test_and_set() and atomic_flag_clear() #if defined(__opencl_c_atomic_order_seq_cst) && defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_flag_test_and_set(volatile atomic_flag *object); void __ovld atomic_flag_clear(volatile atomic_flag *object); +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_flag_test_and_set(volatile __global atomic_flag *object); +bool __ovld atomic_flag_test_and_set(volatile __local atomic_flag *object); +void __ovld atomic_flag_clear(volatile __global atomic_flag *object); +void __ovld atomic_flag_clear(volatile __local atomic_flag *object); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif #if defined(__opencl_c_atomic_scope_device) +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order); void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order); +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_flag_test_and_set_explicit(volatile __global atomic_flag *object, memory_order order); +bool __ovld atomic_flag_test_and_set_explicit(volatile __local atomic_flag *object, memory_order order); +void __ovld atomic_flag_clear_explicit(volatile __global atomic_flag *object, memory_order order); +void __ovld atomic_flag_clear_explicit(volatile __local atomic_flag *object, memory_order order); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif +#if defined(__opencl_c_generic_address_space) bool __ovld atomic_flag_test_and_set_explicit(volatile atomic_flag *object, memory_order order, memory_scope scope); void __ovld atomic_flag_clear_explicit(volatile atomic_flag *object, memory_order order, memory_scope scope); +#endif //defined(__opencl_c_generic_address_space) +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) +bool __ovld atomic_flag_test_and_set_explicit(volatile __global atomic_flag *object, memory_order order, memory_scope scope); +bool __ovld atomic_flag_test_and_set_explicit(volatile __local atomic_flag *object, memory_order order, memory_scope scope); +void __ovld atomic_flag_clear_explicit(volatile __global atomic_flag *object, memory_order order, memory_scope scope); +void __ovld atomic_flag_clear_explicit(volatile __local atomic_flag *object, memory_order order, memory_scope scope); +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) #endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) // OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions @@ -15155,7 +16341,7 @@ int __ovld get_image_num_samples(read_write image2d_array_msaa_depth_t image); // OpenCL v2.0 s6.13.15 - Work-group Functions -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_work_group_collective_functions) int __ovld __conv work_group_all(int predicate); int __ovld __conv work_group_any(int predicate); @@ -15253,12 +16439,12 @@ double __ovld __conv work_group_scan_inclusive_min(double x); double __ovld __conv work_group_scan_inclusive_max(double x); #endif //cl_khr_fp64 -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_work_group_collective_functions) // OpenCL v2.0 s6.13.16 - Pipe Functions -#if defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#if defined(__opencl_c_pipes) bool __ovld is_valid_reserve_id(reserve_id_t reserve_id); -#endif //defined(__OPENCL_CPP_VERSION__) || (__OPENCL_C_VERSION__ >= CL_VERSION_2_0) +#endif //defined(__opencl_c_pipes) // OpenCL v2.0 s6.13.17 - Enqueue Kernels @@ -15295,7 +16481,7 @@ queue_t __ovld get_default_queue(void); // OpenCL Extension v2.0 s9.17 - Sub-groups -#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) +#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) || defined(__opencl_c_subgroups) // Shared Sub Group Functions uint __ovld get_sub_group_size(void); uint __ovld get_max_sub_group_size(void); @@ -15394,7 +16580,7 @@ double __ovld __conv sub_group_scan_inclusive_min(double x); double __ovld __conv sub_group_scan_inclusive_max(double x); #endif //cl_khr_fp64 -#endif //cl_khr_subgroups cl_intel_subgroups +#endif //cl_khr_subgroups cl_intel_subgroups __opencl_c_subgroups #if defined(cl_khr_subgroup_extended_types) char __ovld __conv sub_group_broadcast( char value, uint index ); diff --git a/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h b/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h index 953857badfc..279fb26fbaf 100644 --- a/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h +++ b/clang/lib/Headers/openmp_wrappers/__clang_openmp_device_functions.h @@ -14,13 +14,13 @@ #error "This file is for OpenMP compilation only." #endif -#pragma omp begin declare variant match( \ - device = {arch(nvptx, nvptx64)}, implementation = {extension(match_any)}) - #ifdef __cplusplus extern "C" { #endif +#pragma omp begin declare variant match( \ + device = {arch(nvptx, nvptx64)}, implementation = {extension(match_any)}) + #define __CUDA__ #define __OPENMP_NVPTX__ @@ -33,12 +33,34 @@ extern "C" { #undef __OPENMP_NVPTX__ #undef __CUDA__ +#pragma omp end declare variant + +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +// Import types which will be used by __clang_hip_libdevice_declares.h +#ifndef __cplusplus +#include +#include +#endif + +#define __OPENMP_AMDGCN__ +#pragma push_macro("__device__") +#define __device__ + +/// Include declarations for libdevice functions. +#include <__clang_hip_libdevice_declares.h> + +#pragma pop_macro("__device__") +#undef __OPENMP_AMDGCN__ + +#pragma omp end declare variant +#endif + #ifdef __cplusplus } // extern "C" #endif -#pragma omp end declare variant - // Ensure we make `_ZdlPv`, aka. `operator delete(void*)` available without the // need to `include ` in C++ mode. #ifdef __cplusplus diff --git a/clang/lib/Headers/openmp_wrappers/cmath b/clang/lib/Headers/openmp_wrappers/cmath index 1aff66af7d5..22a720aca95 100644 --- a/clang/lib/Headers/openmp_wrappers/cmath +++ b/clang/lib/Headers/openmp_wrappers/cmath @@ -75,4 +75,58 @@ __DEVICE__ float tgamma(float __x) { return ::tgammaf(__x); } #pragma omp end declare variant +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +#pragma push_macro("__constant__") +#define __constant__ __attribute__((constant)) +#define __OPENMP_AMDGCN__ + +#include <__clang_hip_cmath.h> + +#pragma pop_macro("__constant__") +#undef __OPENMP_AMDGCN__ + +// Define overloads otherwise which are absent +#define __DEVICE__ static constexpr __attribute__((always_inline, nothrow)) + +__DEVICE__ float acos(float __x) { return ::acosf(__x); } +__DEVICE__ float acosh(float __x) { return ::acoshf(__x); } +__DEVICE__ float asin(float __x) { return ::asinf(__x); } +__DEVICE__ float asinh(float __x) { return ::asinhf(__x); } +__DEVICE__ float atan(float __x) { return ::atanf(__x); } +__DEVICE__ float atan2(float __x, float __y) { return ::atan2f(__x, __y); } +__DEVICE__ float atanh(float __x) { return ::atanhf(__x); } +__DEVICE__ float cbrt(float __x) { return ::cbrtf(__x); } +__DEVICE__ float cosh(float __x) { return ::coshf(__x); } +__DEVICE__ float erf(float __x) { return ::erff(__x); } +__DEVICE__ float erfc(float __x) { return ::erfcf(__x); } +__DEVICE__ float exp2(float __x) { return ::exp2f(__x); } +__DEVICE__ float expm1(float __x) { return ::expm1f(__x); } +__DEVICE__ float fdim(float __x, float __y) { return ::fdimf(__x, __y); } +__DEVICE__ float hypot(float __x, float __y) { return ::hypotf(__x, __y); } +__DEVICE__ int ilogb(float __x) { return ::ilogbf(__x); } +__DEVICE__ float ldexp(float __arg, int __exp) { + return ::ldexpf(__arg, __exp); +} +__DEVICE__ float lgamma(float __x) { return ::lgammaf(__x); } +__DEVICE__ float log1p(float __x) { return ::log1pf(__x); } +__DEVICE__ float logb(float __x) { return ::logbf(__x); } +__DEVICE__ float nextafter(float __x, float __y) { + return ::nextafterf(__x, __y); +} +__DEVICE__ float remainder(float __x, float __y) { + return ::remainderf(__x, __y); +} +__DEVICE__ float scalbn(float __x, int __y) { return ::scalbnf(__x, __y); } +__DEVICE__ float sinh(float __x) { return ::sinhf(__x); } +__DEVICE__ float tan(float __x) { return ::tanf(__x); } +__DEVICE__ float tanh(float __x) { return ::tanhf(__x); } +__DEVICE__ float tgamma(float __x) { return ::tgammaf(__x); } + +#undef __DEVICE__ + +#pragma omp end declare variant +#endif // __AMDGCN__ + #endif diff --git a/clang/lib/Headers/openmp_wrappers/complex b/clang/lib/Headers/openmp_wrappers/complex index dfd6193c97c..1ceecc1af8a 100644 --- a/clang/lib/Headers/openmp_wrappers/complex +++ b/clang/lib/Headers/openmp_wrappers/complex @@ -17,9 +17,18 @@ // We require std::math functions in the complex builtins below. #include +#ifdef __NVPTX__ #define __OPENMP_NVPTX__ #include <__clang_cuda_complex_builtins.h> #undef __OPENMP_NVPTX__ +#endif // __NVPTX__ + +#ifdef __AMDGCN__ +#define __OPENMP_AMDGCN__ +#include <__clang_cuda_complex_builtins.h> +#undef __OPENMP_AMDGCN__ +#endif // __AMDGCN__ + #endif // Grab the host header too. @@ -36,11 +45,11 @@ #ifndef _LIBCPP_STD_VER #pragma omp begin declare variant match( \ - device = {arch(nvptx, nvptx64)}, \ + device = {arch(amdgcn, nvptx, nvptx64)}, \ implementation = {extension(match_any, allow_templates)}) #include #pragma omp end declare variant -#endif +#endif // _LIBCPP_STD_VER diff --git a/clang/lib/Headers/openmp_wrappers/complex.h b/clang/lib/Headers/openmp_wrappers/complex.h index 15dc415b812..7e7c0866426 100644 --- a/clang/lib/Headers/openmp_wrappers/complex.h +++ b/clang/lib/Headers/openmp_wrappers/complex.h @@ -17,10 +17,19 @@ // We require math functions in the complex builtins below. #include +#ifdef __NVPTX__ #define __OPENMP_NVPTX__ #include <__clang_cuda_complex_builtins.h> #undef __OPENMP_NVPTX__ #endif +#ifdef __AMDGCN__ +#define __OPENMP_AMDGCN__ +#include <__clang_cuda_complex_builtins.h> +#undef __OPENMP_AMDGCN__ +#endif + +#endif + // Grab the host header too. #include_next diff --git a/clang/lib/Headers/openmp_wrappers/math.h b/clang/lib/Headers/openmp_wrappers/math.h index c64af8b13ec..1e3c07cfdb8 100644 --- a/clang/lib/Headers/openmp_wrappers/math.h +++ b/clang/lib/Headers/openmp_wrappers/math.h @@ -48,4 +48,14 @@ #pragma omp end declare variant +#ifdef __AMDGCN__ +#pragma omp begin declare variant match(device = {arch(amdgcn)}) + +#define __OPENMP_AMDGCN__ +#include <__clang_hip_math.h> +#undef __OPENMP_AMDGCN__ + +#pragma omp end declare variant +#endif + #endif diff --git a/clang/lib/Headers/pmmintrin.h b/clang/lib/Headers/pmmintrin.h index a83b2eb6d8e..eda83567cd0 100644 --- a/clang/lib/Headers/pmmintrin.h +++ b/clang/lib/Headers/pmmintrin.h @@ -10,6 +10,10 @@ #ifndef __PMMINTRIN_H #define __PMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include /* Define the default attributes for the functions in this file. */ diff --git a/clang/lib/Headers/ppc_wrappers/smmintrin.h b/clang/lib/Headers/ppc_wrappers/smmintrin.h index 64f0c761994..f41264b2758 100644 --- a/clang/lib/Headers/ppc_wrappers/smmintrin.h +++ b/clang/lib/Headers/ppc_wrappers/smmintrin.h @@ -32,7 +32,7 @@ #if defined(__linux__) && defined(__ppc64__) #include -#include +#include extern __inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__)) diff --git a/clang/lib/Headers/prfchwintrin.h b/clang/lib/Headers/prfchwintrin.h index 6e8a4ef2ec9..d2f91aa0123 100644 --- a/clang/lib/Headers/prfchwintrin.h +++ b/clang/lib/Headers/prfchwintrin.h @@ -47,9 +47,12 @@ _m_prefetch(void *__P) /// \param __P /// A pointer specifying the memory address to be prefetched. static __inline__ void __attribute__((__always_inline__, __nodebug__)) -_m_prefetchw(void *__P) +_m_prefetchw(volatile const void *__P) { - __builtin_prefetch (__P, 1, 3 /* _MM_HINT_T0 */); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wcast-qual" + __builtin_prefetch ((const void*)__P, 1, 3 /* _MM_HINT_T0 */); +#pragma clang diagnostic pop } #endif /* __PRFCHWINTRIN_H */ diff --git a/clang/lib/Headers/smmintrin.h b/clang/lib/Headers/smmintrin.h index 025830a7428..710e55aaa12 100644 --- a/clang/lib/Headers/smmintrin.h +++ b/clang/lib/Headers/smmintrin.h @@ -10,6 +10,10 @@ #ifndef __SMMINTRIN_H #define __SMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include /* Define the default attributes for the functions in this file. */ @@ -231,7 +235,7 @@ /// 11: Truncated /// \returns A 128-bit vector of [4 x float] containing the rounded values. #define _mm_round_ps(X, M) \ - (__m128)__builtin_ia32_roundps((__v4sf)(__m128)(X), (M)) + ((__m128)__builtin_ia32_roundps((__v4sf)(__m128)(X), (M))) /// Copies three upper elements of the first 128-bit vector operand to /// the corresponding three upper elements of the 128-bit result vector of @@ -272,8 +276,8 @@ /// \returns A 128-bit vector of [4 x float] containing the copied and rounded /// values. #define _mm_round_ss(X, Y, M) \ - (__m128)__builtin_ia32_roundss((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (M)) + ((__m128)__builtin_ia32_roundss((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (M))) /// Rounds each element of the 128-bit vector of [2 x double] to an /// integer value according to the rounding control specified by the second @@ -306,7 +310,7 @@ /// 11: Truncated /// \returns A 128-bit vector of [2 x double] containing the rounded values. #define _mm_round_pd(X, M) \ - (__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M)) + ((__m128d)__builtin_ia32_roundpd((__v2df)(__m128d)(X), (M))) /// Copies the upper element of the first 128-bit vector operand to the /// corresponding upper element of the 128-bit result vector of [2 x double]. @@ -347,8 +351,8 @@ /// \returns A 128-bit vector of [2 x double] containing the copied and rounded /// values. #define _mm_round_sd(X, Y, M) \ - (__m128d)__builtin_ia32_roundsd((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (M)) + ((__m128d)__builtin_ia32_roundsd((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (M))) /* SSE4 Packed Blending Intrinsics. */ /// Returns a 128-bit vector of [2 x double] where the values are @@ -376,8 +380,8 @@ /// is copied to the same position in the result. /// \returns A 128-bit vector of [2 x double] containing the copied values. #define _mm_blend_pd(V1, V2, M) \ - (__m128d) __builtin_ia32_blendpd ((__v2df)(__m128d)(V1), \ - (__v2df)(__m128d)(V2), (int)(M)) + ((__m128d) __builtin_ia32_blendpd ((__v2df)(__m128d)(V1), \ + (__v2df)(__m128d)(V2), (int)(M))) /// Returns a 128-bit vector of [4 x float] where the values are selected /// from either the first or second operand as specified by the third @@ -404,8 +408,8 @@ /// is copied to the same position in the result. /// \returns A 128-bit vector of [4 x float] containing the copied values. #define _mm_blend_ps(V1, V2, M) \ - (__m128) __builtin_ia32_blendps ((__v4sf)(__m128)(V1), \ - (__v4sf)(__m128)(V2), (int)(M)) + ((__m128) __builtin_ia32_blendps ((__v4sf)(__m128)(V1), \ + (__v4sf)(__m128)(V2), (int)(M))) /// Returns a 128-bit vector of [2 x double] where the values are /// selected from either the first or second operand as specified by the @@ -513,8 +517,8 @@ _mm_blendv_epi8 (__m128i __V1, __m128i __V2, __m128i __M) /// is copied to the same position in the result. /// \returns A 128-bit vector of [8 x i16] containing the copied values. #define _mm_blend_epi16(V1, V2, M) \ - (__m128i) __builtin_ia32_pblendw128 ((__v8hi)(__m128i)(V1), \ - (__v8hi)(__m128i)(V2), (int)(M)) + ((__m128i) __builtin_ia32_pblendw128 ((__v8hi)(__m128i)(V1), \ + (__v8hi)(__m128i)(V2), (int)(M))) /* SSE4 Dword Multiply Instructions. */ /// Multiples corresponding elements of two 128-bit vectors of [4 x i32] @@ -590,8 +594,8 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) /// in the corresponding element; otherwise that element is set to zero. /// \returns A 128-bit vector of [4 x float] containing the dot product. #define _mm_dp_ps(X, Y, M) \ - (__m128) __builtin_ia32_dpps((__v4sf)(__m128)(X), \ - (__v4sf)(__m128)(Y), (M)) + ((__m128) __builtin_ia32_dpps((__v4sf)(__m128)(X), \ + (__v4sf)(__m128)(Y), (M))) /// Computes the dot product of the two 128-bit vectors of [2 x double] /// and returns it in the elements of the 128-bit result vector of @@ -625,8 +629,8 @@ _mm_mul_epi32 (__m128i __V1, __m128i __V2) /// each [2 x double] vector. If a bit is set, the dot product is returned in /// the corresponding element; otherwise that element is set to zero. #define _mm_dp_pd(X, Y, M) \ - (__m128d) __builtin_ia32_dppd((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), (M)) + ((__m128d) __builtin_ia32_dppd((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), (M))) /* SSE4 Streaming Load Hint Instruction. */ /// Loads integer values from a 128-bit aligned memory location to a @@ -865,15 +869,13 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 10: Bits [95:64] of parameter \a X are returned. \n /// 11: Bits [127:96] of parameter \a X are returned. /// \returns A 32-bit integer containing the extracted 32 bits of float data. -#define _mm_extract_ps(X, N) (__extension__ \ - ({ union { int __i; float __f; } __t; \ - __t.__f = __builtin_ia32_vec_ext_v4sf((__v4sf)(__m128)(X), (int)(N)); \ - __t.__i;})) +#define _mm_extract_ps(X, N) \ + __builtin_bit_cast(int, __builtin_ia32_vec_ext_v4sf((__v4sf)(__m128)(X), (int)(N))) /* Miscellaneous insert and extract macros. */ /* Extract a single-precision float from X at index N into D. */ #define _MM_EXTRACT_FLOAT(D, X, N) \ - { (D) = __builtin_ia32_vec_ext_v4sf((__v4sf)(__m128)(X), (int)(N)); } + do { (D) = __builtin_ia32_vec_ext_v4sf((__v4sf)(__m128)(X), (int)(N)); } while (0) /* Or together 2 sets of indexes (X and Y) with the zeroing bits (Z) to create an index suitable for _mm_insert_ps. */ @@ -925,8 +927,8 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 1111: Bits [127:120] of the result are used for insertion. /// \returns A 128-bit integer vector containing the constructed values. #define _mm_insert_epi8(X, I, N) \ - (__m128i)__builtin_ia32_vec_set_v16qi((__v16qi)(__m128i)(X), \ - (int)(I), (int)(N)) + ((__m128i)__builtin_ia32_vec_set_v16qi((__v16qi)(__m128i)(X), \ + (int)(I), (int)(N))) /// Constructs a 128-bit vector of [4 x i32] by first making a copy of /// the 128-bit integer vector parameter, and then inserting the 32-bit @@ -957,8 +959,8 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 11: Bits [127:96] of the result are used for insertion. /// \returns A 128-bit integer vector containing the constructed values. #define _mm_insert_epi32(X, I, N) \ - (__m128i)__builtin_ia32_vec_set_v4si((__v4si)(__m128i)(X), \ - (int)(I), (int)(N)) + ((__m128i)__builtin_ia32_vec_set_v4si((__v4si)(__m128i)(X), \ + (int)(I), (int)(N))) #ifdef __x86_64__ /// Constructs a 128-bit vector of [2 x i64] by first making a copy of @@ -988,8 +990,8 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 1: Bits [127:64] of the result are used for insertion. \n /// \returns A 128-bit integer vector containing the constructed values. #define _mm_insert_epi64(X, I, N) \ - (__m128i)__builtin_ia32_vec_set_v2di((__v2di)(__m128i)(X), \ - (long long)(I), (int)(N)) + ((__m128i)__builtin_ia32_vec_set_v2di((__v2di)(__m128i)(X), \ + (long long)(I), (int)(N))) #endif /* __x86_64__ */ /* Extract int from packed integer array at index. This returns the element @@ -1031,8 +1033,8 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 128-bit integer vector parameter and the remaining bits are assigned /// zeros. #define _mm_extract_epi8(X, N) \ - (int)(unsigned char)__builtin_ia32_vec_ext_v16qi((__v16qi)(__m128i)(X), \ - (int)(N)) + ((int)(unsigned char)__builtin_ia32_vec_ext_v16qi((__v16qi)(__m128i)(X), \ + (int)(N))) /// Extracts a 32-bit element from the 128-bit integer vector of /// [4 x i32], using the immediate value parameter \a N as a selector. @@ -1057,7 +1059,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// \returns An integer, whose lower 32 bits are selected from the 128-bit /// integer vector parameter and the remaining bits are assigned zeros. #define _mm_extract_epi32(X, N) \ - (int)__builtin_ia32_vec_ext_v4si((__v4si)(__m128i)(X), (int)(N)) + ((int)__builtin_ia32_vec_ext_v4si((__v4si)(__m128i)(X), (int)(N))) #ifdef __x86_64__ /// Extracts a 64-bit element from the 128-bit integer vector of @@ -1080,7 +1082,7 @@ _mm_max_epu32 (__m128i __V1, __m128i __V2) /// 1: Bits [127:64] are returned. \n /// \returns A 64-bit integer. #define _mm_extract_epi64(X, N) \ - (long long)__builtin_ia32_vec_ext_v2di((__v2di)(__m128i)(X), (int)(N)) + ((long long)__builtin_ia32_vec_ext_v2di((__v2di)(__m128i)(X), (int)(N))) #endif /* __x86_64 */ /* SSE4 128-bit Packed Integer Comparisons. */ @@ -1514,8 +1516,8 @@ _mm_packus_epi32(__m128i __V1, __m128i __V2) /// \returns A 128-bit integer vector containing the sums of the sets of /// absolute differences between both operands. #define _mm_mpsadbw_epu8(X, Y, M) \ - (__m128i) __builtin_ia32_mpsadbw128((__v16qi)(__m128i)(X), \ - (__v16qi)(__m128i)(Y), (M)) + ((__m128i) __builtin_ia32_mpsadbw128((__v16qi)(__m128i)(X), \ + (__v16qi)(__m128i)(Y), (M))) /// Finds the minimum unsigned 16-bit element in the input 128-bit /// vector of [8 x u16] and returns it and along with its index. @@ -1624,8 +1626,8 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns a 128-bit integer vector representing the result mask of /// the comparison. #define _mm_cmpistrm(A, B, M) \ - (__m128i)__builtin_ia32_pcmpistrm128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((__m128i)__builtin_ia32_pcmpistrm128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with implicitly defined lengths that is contained in source operands @@ -1678,8 +1680,8 @@ _mm_minpos_epu16(__m128i __V) /// 1: The index of the most significant set bit. \n /// \returns Returns an integer representing the result index of the comparison. #define _mm_cmpistri(A, B, M) \ - (int)__builtin_ia32_pcmpistri128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistri128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -1738,9 +1740,9 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns a 128-bit integer vector representing the result mask of /// the comparison. #define _mm_cmpestrm(A, LA, B, LB, M) \ - (__m128i)__builtin_ia32_pcmpestrm128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((__m128i)__builtin_ia32_pcmpestrm128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -1797,9 +1799,9 @@ _mm_minpos_epu16(__m128i __V) /// 1: The index of the most significant set bit. \n /// \returns Returns an integer representing the result index of the comparison. #define _mm_cmpestri(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestri128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestri128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /* SSE4.2 Packed Comparison Intrinsics and EFlag Reading. */ /// Uses the immediate operand \a M to perform a comparison of string @@ -1849,8 +1851,8 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the bit mask is zero and the length of the string in /// \a B is the maximum; otherwise, returns 0. #define _mm_cmpistra(A, B, M) \ - (int)__builtin_ia32_pcmpistria128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistria128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with implicitly defined lengths that is contained in source operands @@ -1898,8 +1900,8 @@ _mm_minpos_epu16(__m128i __V) /// to the size of \a A or \a B. /// \returns Returns 1 if the bit mask is non-zero, otherwise, returns 0. #define _mm_cmpistrc(A, B, M) \ - (int)__builtin_ia32_pcmpistric128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistric128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with implicitly defined lengths that is contained in source operands @@ -1946,8 +1948,8 @@ _mm_minpos_epu16(__m128i __V) /// to the size of \a A or \a B. \n /// \returns Returns bit 0 of the resulting bit mask. #define _mm_cmpistro(A, B, M) \ - (int)__builtin_ia32_pcmpistrio128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistrio128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with implicitly defined lengths that is contained in source operands @@ -1996,8 +1998,8 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the length of the string in \a A is less than the /// maximum, otherwise, returns 0. #define _mm_cmpistrs(A, B, M) \ - (int)__builtin_ia32_pcmpistris128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistris128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with implicitly defined lengths that is contained in source operands @@ -2046,8 +2048,8 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the length of the string in \a B is less than the /// maximum, otherwise, returns 0. #define _mm_cmpistrz(A, B, M) \ - (int)__builtin_ia32_pcmpistriz128((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (int)(M)) + ((int)__builtin_ia32_pcmpistriz128((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -2100,9 +2102,9 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the bit mask is zero and the length of the string in /// \a B is the maximum, otherwise, returns 0. #define _mm_cmpestra(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestria128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestria128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -2154,9 +2156,9 @@ _mm_minpos_epu16(__m128i __V) /// to the size of \a A or \a B. \n /// \returns Returns 1 if the resulting mask is non-zero, otherwise, returns 0. #define _mm_cmpestrc(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestric128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -2207,9 +2209,9 @@ _mm_minpos_epu16(__m128i __V) /// to the size of \a A or \a B. /// \returns Returns bit 0 of the resulting bit mask. #define _mm_cmpestro(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestrio128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestrio128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -2262,9 +2264,9 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the length of the string in \a A is less than the /// maximum, otherwise, returns 0. #define _mm_cmpestrs(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestris128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestris128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /// Uses the immediate operand \a M to perform a comparison of string /// data with explicitly defined lengths that is contained in source operands @@ -2316,9 +2318,9 @@ _mm_minpos_epu16(__m128i __V) /// \returns Returns 1 if the length of the string in \a B is less than the /// maximum, otherwise, returns 0. #define _mm_cmpestrz(A, LA, B, LB, M) \ - (int)__builtin_ia32_pcmpestriz128((__v16qi)(__m128i)(A), (int)(LA), \ - (__v16qi)(__m128i)(B), (int)(LB), \ - (int)(M)) + ((int)__builtin_ia32_pcmpestriz128((__v16qi)(__m128i)(A), (int)(LA), \ + (__v16qi)(__m128i)(B), (int)(LB), \ + (int)(M))) /* SSE4.2 Compare Packed Data -- Greater Than. */ /// Compares each of the corresponding 64-bit values of the 128-bit @@ -2340,91 +2342,10 @@ _mm_cmpgt_epi64(__m128i __V1, __m128i __V2) return (__m128i)((__v2di)__V1 > (__v2di)__V2); } -/* SSE4.2 Accumulate CRC32. */ -/// Adds the unsigned integer operand to the CRC-32C checksum of the -/// unsigned char operand. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the CRC32B instruction. -/// -/// \param __C -/// An unsigned integer operand to add to the CRC-32C checksum of operand -/// \a __D. -/// \param __D -/// An unsigned 8-bit integer operand used to compute the CRC-32C checksum. -/// \returns The result of adding operand \a __C to the CRC-32C checksum of -/// operand \a __D. -static __inline__ unsigned int __DEFAULT_FN_ATTRS -_mm_crc32_u8(unsigned int __C, unsigned char __D) -{ - return __builtin_ia32_crc32qi(__C, __D); -} - -/// Adds the unsigned integer operand to the CRC-32C checksum of the -/// unsigned short operand. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the CRC32W instruction. -/// -/// \param __C -/// An unsigned integer operand to add to the CRC-32C checksum of operand -/// \a __D. -/// \param __D -/// An unsigned 16-bit integer operand used to compute the CRC-32C checksum. -/// \returns The result of adding operand \a __C to the CRC-32C checksum of -/// operand \a __D. -static __inline__ unsigned int __DEFAULT_FN_ATTRS -_mm_crc32_u16(unsigned int __C, unsigned short __D) -{ - return __builtin_ia32_crc32hi(__C, __D); -} - -/// Adds the first unsigned integer operand to the CRC-32C checksum of -/// the second unsigned integer operand. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the CRC32L instruction. -/// -/// \param __C -/// An unsigned integer operand to add to the CRC-32C checksum of operand -/// \a __D. -/// \param __D -/// An unsigned 32-bit integer operand used to compute the CRC-32C checksum. -/// \returns The result of adding operand \a __C to the CRC-32C checksum of -/// operand \a __D. -static __inline__ unsigned int __DEFAULT_FN_ATTRS -_mm_crc32_u32(unsigned int __C, unsigned int __D) -{ - return __builtin_ia32_crc32si(__C, __D); -} - -#ifdef __x86_64__ -/// Adds the unsigned integer operand to the CRC-32C checksum of the -/// unsigned 64-bit integer operand. -/// -/// \headerfile -/// -/// This intrinsic corresponds to the CRC32Q instruction. -/// -/// \param __C -/// An unsigned integer operand to add to the CRC-32C checksum of operand -/// \a __D. -/// \param __D -/// An unsigned 64-bit integer operand used to compute the CRC-32C checksum. -/// \returns The result of adding operand \a __C to the CRC-32C checksum of -/// operand \a __D. -static __inline__ unsigned long long __DEFAULT_FN_ATTRS -_mm_crc32_u64(unsigned long long __C, unsigned long long __D) -{ - return __builtin_ia32_crc32di(__C, __D); -} -#endif /* __x86_64__ */ - #undef __DEFAULT_FN_ATTRS #include +#include + #endif /* __SMMINTRIN_H */ diff --git a/clang/lib/Headers/tmmintrin.h b/clang/lib/Headers/tmmintrin.h index 35533e115c7..bcffa818780 100644 --- a/clang/lib/Headers/tmmintrin.h +++ b/clang/lib/Headers/tmmintrin.h @@ -10,6 +10,10 @@ #ifndef __TMMINTRIN_H #define __TMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include /* Define the default attributes for the functions in this file. */ @@ -145,8 +149,8 @@ _mm_abs_epi32(__m128i __a) /// \returns A 128-bit integer vector containing the concatenated right-shifted /// value. #define _mm_alignr_epi8(a, b, n) \ - (__m128i)__builtin_ia32_palignr128((__v16qi)(__m128i)(a), \ - (__v16qi)(__m128i)(b), (n)) + ((__m128i)__builtin_ia32_palignr128((__v16qi)(__m128i)(a), \ + (__v16qi)(__m128i)(b), (n))) /// Concatenates the two 64-bit integer vector operands, and right-shifts /// the result by the number of bytes specified in the immediate operand. @@ -168,7 +172,7 @@ _mm_abs_epi32(__m128i __a) /// \returns A 64-bit integer vector containing the concatenated right-shifted /// value. #define _mm_alignr_pi8(a, b, n) \ - (__m64)__builtin_ia32_palignr((__v8qi)(__m64)(a), (__v8qi)(__m64)(b), (n)) + ((__m64)__builtin_ia32_palignr((__v8qi)(__m64)(a), (__v8qi)(__m64)(b), (n))) /// Horizontally adds the adjacent pairs of values contained in 2 packed /// 128-bit vectors of [8 x i16]. diff --git a/clang/lib/Headers/vpclmulqdqintrin.h b/clang/lib/Headers/vpclmulqdqintrin.h index 44daadb07d5..485692ea2b5 100644 --- a/clang/lib/Headers/vpclmulqdqintrin.h +++ b/clang/lib/Headers/vpclmulqdqintrin.h @@ -15,15 +15,15 @@ #define __VPCLMULQDQINTRIN_H #define _mm256_clmulepi64_epi128(A, B, I) \ - (__m256i)__builtin_ia32_pclmulqdq256((__v4di)(__m256i)(A), \ - (__v4di)(__m256i)(B), \ - (char)(I)) + ((__m256i)__builtin_ia32_pclmulqdq256((__v4di)(__m256i)(A), \ + (__v4di)(__m256i)(B), \ + (char)(I))) #ifdef __AVX512FINTRIN_H #define _mm512_clmulepi64_epi128(A, B, I) \ - (__m512i)__builtin_ia32_pclmulqdq512((__v8di)(__m512i)(A), \ - (__v8di)(__m512i)(B), \ - (char)(I)) + ((__m512i)__builtin_ia32_pclmulqdq512((__v8di)(__m512i)(A), \ + (__v8di)(__m512i)(B), \ + (char)(I))) #endif // __AVX512FINTRIN_H #endif /* __VPCLMULQDQINTRIN_H */ diff --git a/clang/lib/Headers/wasm_simd128.h b/clang/lib/Headers/wasm_simd128.h index 712fa037809..3889a2769fa 100644 --- a/clang/lib/Headers/wasm_simd128.h +++ b/clang/lib/Headers/wasm_simd128.h @@ -276,12 +276,28 @@ wasm_i8x16_make(int8_t __c0, int8_t __c1, int8_t __c2, int8_t __c3, int8_t __c4, __c12, __c13, __c14, __c15}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u8x16_make(uint8_t __c0, uint8_t __c1, uint8_t __c2, uint8_t __c3, + uint8_t __c4, uint8_t __c5, uint8_t __c6, uint8_t __c7, + uint8_t __c8, uint8_t __c9, uint8_t __c10, uint8_t __c11, + uint8_t __c12, uint8_t __c13, uint8_t __c14, uint8_t __c15) { + return (v128_t)(__u8x16){__c0, __c1, __c2, __c3, __c4, __c5, + __c6, __c7, __c8, __c9, __c10, __c11, + __c12, __c13, __c14, __c15}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_make(int16_t __c0, int16_t __c1, int16_t __c2, int16_t __c3, int16_t __c4, int16_t __c5, int16_t __c6, int16_t __c7) { return (v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u16x8_make(uint16_t __c0, uint16_t __c1, uint16_t __c2, uint16_t __c3, + uint16_t __c4, uint16_t __c5, uint16_t __c6, uint16_t __c7) { + return (v128_t)(__u16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_make(int32_t __c0, int32_t __c1, int32_t __c2, @@ -289,11 +305,23 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_make(int32_t __c0, return (v128_t)(__i32x4){__c0, __c1, __c2, __c3}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_make(uint32_t __c0, + uint32_t __c1, + uint32_t __c2, + uint32_t __c3) { + return (v128_t)(__u32x4){__c0, __c1, __c2, __c3}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_make(int64_t __c0, int64_t __c1) { return (v128_t)(__i64x2){__c0, __c1}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_make(uint64_t __c0, + uint64_t __c1) { + return (v128_t)(__u64x2){__c0, __c1}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_make(float __c0, float __c1, float __c2, @@ -324,6 +352,24 @@ wasm_i8x16_const(int8_t __c0, int8_t __c1, int8_t __c2, int8_t __c3, __c12, __c13, __c14, __c15}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u8x16_const(uint8_t __c0, uint8_t __c1, uint8_t __c2, uint8_t __c3, + uint8_t __c4, uint8_t __c5, uint8_t __c6, uint8_t __c7, + uint8_t __c8, uint8_t __c9, uint8_t __c10, uint8_t __c11, + uint8_t __c12, uint8_t __c13, uint8_t __c14, uint8_t __c15) + __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2) + __REQUIRE_CONSTANT(__c3) __REQUIRE_CONSTANT(__c4) + __REQUIRE_CONSTANT(__c5) __REQUIRE_CONSTANT(__c6) + __REQUIRE_CONSTANT(__c7) __REQUIRE_CONSTANT(__c8) + __REQUIRE_CONSTANT(__c9) __REQUIRE_CONSTANT(__c10) + __REQUIRE_CONSTANT(__c11) __REQUIRE_CONSTANT(__c12) + __REQUIRE_CONSTANT(__c13) __REQUIRE_CONSTANT(__c14) + __REQUIRE_CONSTANT(__c15) { + return (v128_t)(__u8x16){__c0, __c1, __c2, __c3, __c4, __c5, + __c6, __c7, __c8, __c9, __c10, __c11, + __c12, __c13, __c14, __c15}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_const(int16_t __c0, int16_t __c1, int16_t __c2, int16_t __c3, int16_t __c4, int16_t __c5, int16_t __c6, int16_t __c7) @@ -334,6 +380,16 @@ wasm_i16x8_const(int16_t __c0, int16_t __c1, int16_t __c2, int16_t __c3, return (v128_t)(__i16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u16x8_const(uint16_t __c0, uint16_t __c1, uint16_t __c2, uint16_t __c3, + uint16_t __c4, uint16_t __c5, uint16_t __c6, uint16_t __c7) + __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2) + __REQUIRE_CONSTANT(__c3) __REQUIRE_CONSTANT(__c4) + __REQUIRE_CONSTANT(__c5) __REQUIRE_CONSTANT(__c6) + __REQUIRE_CONSTANT(__c7) { + return (v128_t)(__u16x8){__c0, __c1, __c2, __c3, __c4, __c5, __c6, __c7}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_const(int32_t __c0, int32_t __c1, int32_t __c2, int32_t __c3) __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2) @@ -341,12 +397,25 @@ wasm_i32x4_const(int32_t __c0, int32_t __c1, int32_t __c2, int32_t __c3) return (v128_t)(__i32x4){__c0, __c1, __c2, __c3}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS +wasm_u32x4_const(uint32_t __c0, uint32_t __c1, uint32_t __c2, uint32_t __c3) + __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2) + __REQUIRE_CONSTANT(__c3) { + return (v128_t)(__u32x4){__c0, __c1, __c2, __c3}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_const(int64_t __c0, int64_t __c1) __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) { return (v128_t)(__i64x2){__c0, __c1}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_const(uint64_t __c0, + uint64_t __c1) + __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) { + return (v128_t)(__u64x2){__c0, __c1}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_const(float __c0, float __c1, float __c2, float __c3) __REQUIRE_CONSTANT(__c0) __REQUIRE_CONSTANT(__c1) __REQUIRE_CONSTANT(__c2) @@ -366,21 +435,42 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_const_splat(int8_t __c) __c, __c, __c, __c, __c, __c, __c, __c}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_const_splat(uint8_t __c) + __REQUIRE_CONSTANT(__c) { + return (v128_t)(__u8x16){__c, __c, __c, __c, __c, __c, __c, __c, + __c, __c, __c, __c, __c, __c, __c, __c}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_const_splat(int16_t __c) __REQUIRE_CONSTANT(__c) { return (v128_t)(__i16x8){__c, __c, __c, __c, __c, __c, __c, __c}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_const_splat(uint16_t __c) + __REQUIRE_CONSTANT(__c) { + return (v128_t)(__u16x8){__c, __c, __c, __c, __c, __c, __c, __c}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_const_splat(int32_t __c) __REQUIRE_CONSTANT(__c) { return (v128_t)(__i32x4){__c, __c, __c, __c}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_const_splat(uint32_t __c) + __REQUIRE_CONSTANT(__c) { + return (v128_t)(__u32x4){__c, __c, __c, __c}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_const_splat(int64_t __c) __REQUIRE_CONSTANT(__c) { return (v128_t)(__i64x2){__c, __c}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_const_splat(uint64_t __c) + __REQUIRE_CONSTANT(__c) { + return (v128_t)(__u64x2){__c, __c}; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_const_splat(float __c) __REQUIRE_CONSTANT(__c) { return (v128_t)(__f32x4){__c, __c, __c, __c}; @@ -396,6 +486,11 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_splat(int8_t __a) { __a, __a, __a, __a, __a, __a, __a, __a}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_splat(uint8_t __a) { + return (v128_t)(__u8x16){__a, __a, __a, __a, __a, __a, __a, __a, + __a, __a, __a, __a, __a, __a, __a, __a}; +} + static __inline__ int8_t __DEFAULT_FN_ATTRS wasm_i8x16_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { @@ -417,10 +512,23 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_replace_lane(v128_t __a, return (v128_t)__v; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_replace_lane(v128_t __a, + int __i, + uint8_t __b) + __REQUIRE_CONSTANT(__i) { + __u8x16 __v = (__u8x16)__a; + __v[__i] = __b; + return (v128_t)__v; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_splat(int16_t __a) { return (v128_t)(__i16x8){__a, __a, __a, __a, __a, __a, __a, __a}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_splat(uint16_t __a) { + return (v128_t)(__u16x8){__a, __a, __a, __a, __a, __a, __a, __a}; +} + static __inline__ int16_t __DEFAULT_FN_ATTRS wasm_i16x8_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { @@ -441,16 +549,32 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_replace_lane(v128_t __a, return (v128_t)__v; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_replace_lane( + v128_t __a, int __i, uint16_t __b) __REQUIRE_CONSTANT(__i) { + __u16x8 __v = (__u16x8)__a; + __v[__i] = __b; + return (v128_t)__v; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_splat(int32_t __a) { return (v128_t)(__i32x4){__a, __a, __a, __a}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_splat(uint32_t __a) { + return (v128_t)(__u32x4){__a, __a, __a, __a}; +} + static __inline__ int32_t __DEFAULT_FN_ATTRS wasm_i32x4_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { return ((__i32x4)__a)[__i]; } +static __inline__ uint32_t __DEFAULT_FN_ATTRS +wasm_u32x4_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { + return ((__u32x4)__a)[__i]; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_replace_lane(v128_t __a, int __i, int32_t __b) @@ -460,16 +584,32 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_replace_lane(v128_t __a, return (v128_t)__v; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_replace_lane( + v128_t __a, int __i, uint32_t __b) __REQUIRE_CONSTANT(__i) { + __u32x4 __v = (__u32x4)__a; + __v[__i] = __b; + return (v128_t)__v; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_splat(int64_t __a) { return (v128_t)(__i64x2){__a, __a}; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_splat(uint64_t __a) { + return (v128_t)(__u64x2){__a, __a}; +} + static __inline__ int64_t __DEFAULT_FN_ATTRS wasm_i64x2_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { return ((__i64x2)__a)[__i]; } +static __inline__ uint64_t __DEFAULT_FN_ATTRS +wasm_u64x2_extract_lane(v128_t __a, int __i) __REQUIRE_CONSTANT(__i) { + return ((__u64x2)__a)[__i]; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_replace_lane(v128_t __a, int __i, int64_t __b) @@ -479,6 +619,13 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_replace_lane(v128_t __a, return (v128_t)__v; } +static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_replace_lane( + v128_t __a, int __i, uint64_t __b) __REQUIRE_CONSTANT(__i) { + __u64x2 __v = (__u64x2)__a; + __v[__i] = __b; + return (v128_t)__v; +} + static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_splat(float __a) { return (v128_t)(__f32x4){__a, __a, __a, __a}; } @@ -804,7 +951,7 @@ static __inline__ bool __DEFAULT_FN_ATTRS wasm_i8x16_all_true(v128_t __a) { return __builtin_wasm_all_true_i8x16((__i8x16)__a); } -static __inline__ int32_t __DEFAULT_FN_ATTRS wasm_i8x16_bitmask(v128_t __a) { +static __inline__ uint32_t __DEFAULT_FN_ATTRS wasm_i8x16_bitmask(v128_t __a) { return __builtin_wasm_bitmask_i8x16((__i8x16)__a); } @@ -813,17 +960,17 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_popcnt(v128_t __a) { } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shl(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i8x16)__a << __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i8x16_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i8x16)__a >> __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u8x16_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__u8x16)__a >> __b); } @@ -894,22 +1041,22 @@ static __inline__ bool __DEFAULT_FN_ATTRS wasm_i16x8_all_true(v128_t __a) { return __builtin_wasm_all_true_i16x8((__i16x8)__a); } -static __inline__ int32_t __DEFAULT_FN_ATTRS wasm_i16x8_bitmask(v128_t __a) { +static __inline__ uint32_t __DEFAULT_FN_ATTRS wasm_i16x8_bitmask(v128_t __a) { return __builtin_wasm_bitmask_i16x8((__i16x8)__a); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_shl(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i16x8)__a << __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i16x8_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i16x8)__a >> __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u16x8_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__u16x8)__a >> __b); } @@ -985,22 +1132,22 @@ static __inline__ bool __DEFAULT_FN_ATTRS wasm_i32x4_all_true(v128_t __a) { return __builtin_wasm_all_true_i32x4((__i32x4)__a); } -static __inline__ int32_t __DEFAULT_FN_ATTRS wasm_i32x4_bitmask(v128_t __a) { +static __inline__ uint32_t __DEFAULT_FN_ATTRS wasm_i32x4_bitmask(v128_t __a) { return __builtin_wasm_bitmask_i32x4((__i32x4)__a); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_shl(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i32x4)__a << __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i32x4_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i32x4)__a >> __b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u32x4_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__u32x4)__a >> __b); } @@ -1056,22 +1203,22 @@ static __inline__ bool __DEFAULT_FN_ATTRS wasm_i64x2_all_true(v128_t __a) { return __builtin_wasm_all_true_i64x2((__i64x2)__a); } -static __inline__ int32_t __DEFAULT_FN_ATTRS wasm_i64x2_bitmask(v128_t __a) { +static __inline__ uint32_t __DEFAULT_FN_ATTRS wasm_i64x2_bitmask(v128_t __a) { return __builtin_wasm_bitmask_i64x2((__i64x2)__a); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_shl(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i64x2)__a << (int64_t)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_i64x2_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__i64x2)__a >> (int64_t)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_u64x2_shr(v128_t __a, - int32_t __b) { + uint32_t __b) { return (v128_t)((__u64x2)__a >> (int64_t)__b); } @@ -1150,14 +1297,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_max(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_pmin(v128_t __a, v128_t __b) { - __i32x4 __mask = (__i32x4)((__f32x4)__b < (__f32x4)__a); - return (v128_t)((((__i32x4)__b) & __mask) | (((__i32x4)__a) & ~__mask)); + return (v128_t)__builtin_wasm_pmin_f32x4((__f32x4)__a, (__f32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f32x4_pmax(v128_t __a, v128_t __b) { - __i32x4 __mask = (__i32x4)((__f32x4)__a < (__f32x4)__b); - return (v128_t)((((__i32x4)__b) & __mask) | (((__i32x4)__a) & ~__mask)); + return (v128_t)__builtin_wasm_pmax_f32x4((__f32x4)__a, (__f32x4)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_abs(v128_t __a) { @@ -1220,14 +1365,12 @@ static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_max(v128_t __a, static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_pmin(v128_t __a, v128_t __b) { - __i64x2 __mask = (__i64x2)((__f64x2)__b < (__f64x2)__a); - return (v128_t)((((__i64x2)__b) & __mask) | (((__i64x2)__a) & ~__mask)); + return (v128_t)__builtin_wasm_pmin_f64x2((__f64x2)__a, (__f64x2)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS wasm_f64x2_pmax(v128_t __a, v128_t __b) { - __i64x2 __mask = (__i64x2)((__f64x2)__a < (__f64x2)__b); - return (v128_t)((((__i64x2)__b) & __mask) | (((__i64x2)__a) & ~__mask)); + return (v128_t)__builtin_wasm_pmax_f64x2((__f64x2)__a, (__f64x2)__b); } static __inline__ v128_t __DEFAULT_FN_ATTRS diff --git a/clang/lib/Headers/wmmintrin.h b/clang/lib/Headers/wmmintrin.h index f932ca81089..49148dbf3ac 100644 --- a/clang/lib/Headers/wmmintrin.h +++ b/clang/lib/Headers/wmmintrin.h @@ -10,6 +10,10 @@ #ifndef __WMMINTRIN_H #define __WMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include #include <__wmmintrin_aes.h> diff --git a/clang/lib/Headers/x86gprintrin.h b/clang/lib/Headers/x86gprintrin.h index 1fc6cab4b28..01e741f1eb6 100644 --- a/clang/lib/Headers/x86gprintrin.h +++ b/clang/lib/Headers/x86gprintrin.h @@ -20,4 +20,16 @@ #include #endif +#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \ + defined(__CRC32__) +#include +#endif + +#define __SSC_MARK(Tag) \ + __asm__ __volatile__("mov {%%ebx, %%eax|eax, ebx}; " \ + "mov {%0, %%ebx|ebx, %0}; " \ + ".byte 0x64, 0x67, 0x90; " \ + "mov {%%eax, %%ebx|ebx, eax};" ::"i"(Tag) \ + : "%eax"); + #endif /* __X86GPRINTRIN_H */ diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index f4686691c7e..1612d3d2773 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -10,6 +10,10 @@ #ifndef __XMMINTRIN_H #define __XMMINTRIN_H +#if !defined(__i386__) && !defined(__x86_64__) +#error "This header is only meant to be used on x86 and x64 architecture" +#endif + #include typedef int __v4si __attribute__((__vector_size__(16))); @@ -2181,7 +2185,7 @@ void _mm_sfence(void); /// 3: Bits [63:48] are copied to the destination. /// \returns A 16-bit integer containing the extracted 16 bits of packed data. #define _mm_extract_pi16(a, n) \ - (int)__builtin_ia32_vec_ext_v4hi((__v4hi)a, (int)n) + ((int)__builtin_ia32_vec_ext_v4hi((__v4hi)a, (int)n)) /// Copies data from the 64-bit vector of [4 x i16] to the destination, /// and inserts the lower 16-bits of an integer operand at the 16-bit offset @@ -2212,7 +2216,7 @@ void _mm_sfence(void); /// \returns A 64-bit integer vector containing the copied packed data from the /// operands. #define _mm_insert_pi16(a, d, n) \ - (__m64)__builtin_ia32_vec_set_v4hi((__v4hi)a, (int)d, (int)n) + ((__m64)__builtin_ia32_vec_set_v4hi((__v4hi)a, (int)d, (int)n)) /// Compares each of the corresponding packed 16-bit integer values of /// the 64-bit integer vectors, and writes the greater value to the @@ -2359,7 +2363,7 @@ _mm_mulhi_pu16(__m64 __a, __m64 __b) /// 11: assigned from bits [63:48] of \a a. /// \returns A 64-bit integer vector containing the shuffled values. #define _mm_shuffle_pi16(a, n) \ - (__m64)__builtin_ia32_pshufw((__v4hi)(__m64)(a), (n)) + ((__m64)__builtin_ia32_pshufw((__v4hi)(__m64)(a), (n))) /// Conditionally copies the values from each 8-bit element in the first /// 64-bit integer vector operand to the specified memory location, as @@ -2601,8 +2605,8 @@ void _mm_setcsr(unsigned int __i); /// 11: Bits [127:96] copied from the specified operand. /// \returns A 128-bit vector of [4 x float] containing the shuffled values. #define _mm_shuffle_ps(a, b, mask) \ - (__m128)__builtin_ia32_shufps((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), \ - (int)(mask)) + ((__m128)__builtin_ia32_shufps((__v4sf)(__m128)(a), (__v4sf)(__m128)(b), \ + (int)(mask))) /// Unpacks the high-order (index 2,3) values from two 128-bit vectors of /// [4 x float] and interleaves them into a 128-bit vector of [4 x float]. diff --git a/clang/lib/Headers/xopintrin.h b/clang/lib/Headers/xopintrin.h index 5cedde41b62..976cdf4902a 100644 --- a/clang/lib/Headers/xopintrin.h +++ b/clang/lib/Headers/xopintrin.h @@ -225,16 +225,16 @@ _mm_rot_epi64(__m128i __A, __m128i __B) } #define _mm_roti_epi8(A, N) \ - (__m128i)__builtin_ia32_vprotbi((__v16qi)(__m128i)(A), (N)) + ((__m128i)__builtin_ia32_vprotbi((__v16qi)(__m128i)(A), (N))) #define _mm_roti_epi16(A, N) \ - (__m128i)__builtin_ia32_vprotwi((__v8hi)(__m128i)(A), (N)) + ((__m128i)__builtin_ia32_vprotwi((__v8hi)(__m128i)(A), (N))) #define _mm_roti_epi32(A, N) \ - (__m128i)__builtin_ia32_vprotdi((__v4si)(__m128i)(A), (N)) + ((__m128i)__builtin_ia32_vprotdi((__v4si)(__m128i)(A), (N))) #define _mm_roti_epi64(A, N) \ - (__m128i)__builtin_ia32_vprotqi((__v2di)(__m128i)(A), (N)) + ((__m128i)__builtin_ia32_vprotqi((__v2di)(__m128i)(A), (N))) static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_shl_epi8(__m128i __A, __m128i __B) @@ -285,36 +285,36 @@ _mm_sha_epi64(__m128i __A, __m128i __B) } #define _mm_com_epu8(A, B, N) \ - (__m128i)__builtin_ia32_vpcomub((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomub((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (N))) #define _mm_com_epu16(A, B, N) \ - (__m128i)__builtin_ia32_vpcomuw((__v8hi)(__m128i)(A), \ - (__v8hi)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomuw((__v8hi)(__m128i)(A), \ + (__v8hi)(__m128i)(B), (N))) #define _mm_com_epu32(A, B, N) \ - (__m128i)__builtin_ia32_vpcomud((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomud((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), (N))) #define _mm_com_epu64(A, B, N) \ - (__m128i)__builtin_ia32_vpcomuq((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomuq((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), (N))) #define _mm_com_epi8(A, B, N) \ - (__m128i)__builtin_ia32_vpcomb((__v16qi)(__m128i)(A), \ - (__v16qi)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomb((__v16qi)(__m128i)(A), \ + (__v16qi)(__m128i)(B), (N))) #define _mm_com_epi16(A, B, N) \ - (__m128i)__builtin_ia32_vpcomw((__v8hi)(__m128i)(A), \ - (__v8hi)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomw((__v8hi)(__m128i)(A), \ + (__v8hi)(__m128i)(B), (N))) #define _mm_com_epi32(A, B, N) \ - (__m128i)__builtin_ia32_vpcomd((__v4si)(__m128i)(A), \ - (__v4si)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomd((__v4si)(__m128i)(A), \ + (__v4si)(__m128i)(B), (N))) #define _mm_com_epi64(A, B, N) \ - (__m128i)__builtin_ia32_vpcomq((__v2di)(__m128i)(A), \ - (__v2di)(__m128i)(B), (N)) + ((__m128i)__builtin_ia32_vpcomq((__v2di)(__m128i)(A), \ + (__v2di)(__m128i)(B), (N))) #define _MM_PCOMCTRL_LT 0 #define _MM_PCOMCTRL_LE 1 @@ -710,23 +710,23 @@ _mm_comtrue_epi64(__m128i __A, __m128i __B) } #define _mm_permute2_pd(X, Y, C, I) \ - (__m128d)__builtin_ia32_vpermil2pd((__v2df)(__m128d)(X), \ - (__v2df)(__m128d)(Y), \ - (__v2di)(__m128i)(C), (I)) + ((__m128d)__builtin_ia32_vpermil2pd((__v2df)(__m128d)(X), \ + (__v2df)(__m128d)(Y), \ + (__v2di)(__m128i)(C), (I))) #define _mm256_permute2_pd(X, Y, C, I) \ - (__m256d)__builtin_ia32_vpermil2pd256((__v4df)(__m256d)(X), \ - (__v4df)(__m256d)(Y), \ - (__v4di)(__m256i)(C), (I)) + ((__m256d)__builtin_ia32_vpermil2pd256((__v4df)(__m256d)(X), \ + (__v4df)(__m256d)(Y), \ + (__v4di)(__m256i)(C), (I))) #define _mm_permute2_ps(X, Y, C, I) \ - (__m128)__builtin_ia32_vpermil2ps((__v4sf)(__m128)(X), (__v4sf)(__m128)(Y), \ - (__v4si)(__m128i)(C), (I)) + ((__m128)__builtin_ia32_vpermil2ps((__v4sf)(__m128)(X), (__v4sf)(__m128)(Y), \ + (__v4si)(__m128i)(C), (I))) #define _mm256_permute2_ps(X, Y, C, I) \ - (__m256)__builtin_ia32_vpermil2ps256((__v8sf)(__m256)(X), \ - (__v8sf)(__m256)(Y), \ - (__v8si)(__m256i)(C), (I)) + ((__m256)__builtin_ia32_vpermil2ps256((__v8sf)(__m256)(X), \ + (__v8sf)(__m256)(Y), \ + (__v8si)(__m256i)(C), (I))) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_frcz_ss(__m128 __A) diff --git a/clang/lib/Index/FileIndexRecord.cpp b/clang/lib/Index/FileIndexRecord.cpp index d392a2bedeb..d4d1d2f70a9 100644 --- a/clang/lib/Index/FileIndexRecord.cpp +++ b/clang/lib/Index/FileIndexRecord.cpp @@ -1,9 +1,8 @@ //===--- FileIndexRecord.cpp - Index data per file --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index 00adb3644ff..3139aedaf01 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -8,6 +8,7 @@ #include "IndexingContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" #include "clang/AST/DeclVisitor.h" #include "clang/Index/IndexDataConsumer.h" @@ -372,6 +373,15 @@ public: return true; } + bool VisitEnumDecl(const EnumDecl *ED) { + TRY_TO(VisitTagDecl(ED)); + // Indexing for enumdecl itself is handled inside TagDecl, we just want to + // visit integer-base here, which is different than other TagDecl bases. + if (auto *TSI = ED->getIntegerTypeSourceInfo()) + IndexCtx.indexTypeSourceInfo(TSI, ED, ED, /*isBase=*/true); + return true; + } + bool handleReferencedProtocols(const ObjCProtocolList &ProtList, const ObjCContainerDecl *ContD, SourceLocation SuperLoc) { diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index 6db763ca6f2..41edd431dd5 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -705,6 +705,7 @@ void USRGenerator::VisitType(QualType T) { c = 'f'; break; case BuiltinType::Double: c = 'd'; break; + case BuiltinType::Ibm128: // FIXME: Need separate tag case BuiltinType::LongDouble: c = 'D'; break; case BuiltinType::Float128: diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 9a368d9122b..705235aafa0 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -60,4 +60,15 @@ llvm::Error IncrementalExecutor::runCtors() const { return Jit->initialize(Jit->getMainJITDylib()); } +llvm::Expected +IncrementalExecutor::getSymbolAddress(llvm::StringRef Name, + SymbolNameKind NameKind) const { + auto Sym = (NameKind == LinkerName) ? Jit->lookupLinkerMangled(Name) + : Jit->lookup(Name); + + if (!Sym) + return Sym.takeError(); + return Sym->getAddress(); +} + } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index b4c6ddec104..24447994d5f 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -35,12 +35,16 @@ class IncrementalExecutor { llvm::orc::ThreadSafeContext &TSCtx; public: + enum SymbolNameKind { IRName, LinkerName }; + IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, const llvm::Triple &Triple); ~IncrementalExecutor(); llvm::Error addModule(std::unique_ptr M); llvm::Error runCtors() const; + llvm::Expected + getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; }; } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 897e2cd1aae..84eabc3a210 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -65,6 +65,8 @@ public: case frontend::ParseSyntaxOnly: Act = CreateFrontendAction(CI); break; + case frontend::PluginAction: + LLVM_FALLTHROUGH; case frontend::EmitAssembly: LLVM_FALLTHROUGH; case frontend::EmitObj: @@ -289,4 +291,11 @@ IncrementalParser::Parse(llvm::StringRef input) { return PTU; } + +llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { + CodeGenerator *CG = getCodeGen(Act.get()); + assert(CG); + return CG->GetMangledName(GD); +} + } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.h b/clang/lib/Interpreter/IncrementalParser.h index aa8142cbe49..e5ce798025d 100644 --- a/clang/lib/Interpreter/IncrementalParser.h +++ b/clang/lib/Interpreter/IncrementalParser.h @@ -15,6 +15,8 @@ #include "clang/Interpreter/PartialTranslationUnit.h" +#include "clang/AST/GlobalDecl.h" + #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -69,6 +71,10 @@ public: /// \c TranslationUnitDecl and \c llvm::Module corresponding to the input. llvm::Expected Parse(llvm::StringRef Input); + /// Uses the CodeGenModule mangled name cache and avoids recomputing. + ///\returns the mangled name of a \c GD. + llvm::StringRef GetMangledName(GlobalDecl GD) const; + private: llvm::Expected ParseOrWrapTopLevelDecl(); }; diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 937504f3473..b2e7727be39 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -30,13 +30,13 @@ #include "clang/Lex/PreprocessorOptions.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/Host.h" using namespace clang; // FIXME: Figure out how to unify with namespace init_convenience from -// tools/clang-import-test/clang-import-test.cpp and -// examples/clang-interpreter/main.cpp +// tools/clang-import-test/clang-import-test.cpp namespace { /// Retrieves the clang CC1 specific flags out of the compilation's jobs. /// \returns NULL on error. @@ -47,14 +47,14 @@ GetCC1Arguments(DiagnosticsEngine *Diagnostics, // failed. Extract that job from the Compilation. const driver::JobList &Jobs = Compilation->getJobs(); if (!Jobs.size() || !isa(*Jobs.begin())) - return llvm::createStringError(std::errc::state_not_recoverable, + return llvm::createStringError(llvm::errc::not_supported, "Driver initialization failed. " "Unable to create a driver job"); // The one job we find should be to invoke clang again. const driver::Command *Cmd = cast(&(*Jobs.begin())); if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") - return llvm::createStringError(std::errc::state_not_recoverable, + return llvm::createStringError(llvm::errc::not_supported, "Driver initialization failed"); return &Cmd->getArguments(); @@ -89,13 +89,13 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { // Create the actual diagnostics engine. Clang->createDiagnostics(); if (!Clang->hasDiagnostics()) - return llvm::createStringError(std::errc::state_not_recoverable, + return llvm::createStringError(llvm::errc::not_supported, "Initialization failed. " "Unable to create diagnostics engine"); DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); if (!Success) - return llvm::createStringError(std::errc::state_not_recoverable, + return llvm::createStringError(llvm::errc::not_supported, "Initialization failed. " "Unable to flush diagnostics"); @@ -106,12 +106,16 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { Clang->setTarget(TargetInfo::CreateTargetInfo( Clang->getDiagnostics(), Clang->getInvocation().TargetOpts)); if (!Clang->hasTarget()) - return llvm::createStringError(std::errc::state_not_recoverable, + return llvm::createStringError(llvm::errc::not_supported, "Initialization failed. " "Target is missing"); Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts()); + // Don't clear the AST before backend codegen since we do codegen multiple + // times, reusing the same AST. + Clang->getCodeGenOpts().ClearASTBeforeBackend = false; + return std::move(Clang); } @@ -143,19 +147,13 @@ IncrementalCompilerBuilder::create(std::vector &ClangArgv) { // driver to construct. ClangArgv.push_back("<<< inputs >>>"); - CompilerInvocation Invocation; // Buffer diagnostics from argument parsing so that we can output them using a // well formed diagnostic object. IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + IntrusiveRefCntPtr DiagOpts = + CreateAndPopulateDiagOpts(ClangArgv); TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); - unsigned MissingArgIndex, MissingArgCount; - const llvm::opt::OptTable &Opts = driver::getDriverOptTable(); - llvm::opt::InputArgList ParsedArgs = - Opts.ParseArgs(ArrayRef(ClangArgv).slice(1), - MissingArgIndex, MissingArgCount); - ParseDiagnosticArgs(*DiagOpts, ParsedArgs, &Diags); driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], llvm::sys::getProcessTriple(), Diags); @@ -223,3 +221,33 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) { return llvm::Error::success(); } + +llvm::Expected +Interpreter::getSymbolAddress(GlobalDecl GD) const { + if (!IncrExecutor) + return llvm::make_error("Operation failed. " + "No execution engine", + std::error_code()); + llvm::StringRef MangledName = IncrParser->GetMangledName(GD); + return getSymbolAddress(MangledName); +} + +llvm::Expected +Interpreter::getSymbolAddress(llvm::StringRef IRName) const { + if (!IncrExecutor) + return llvm::make_error("Operation failed. " + "No execution engine", + std::error_code()); + + return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName); +} + +llvm::Expected +Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const { + if (!IncrExecutor) + return llvm::make_error("Operation failed. " + "No execution engine", + std::error_code()); + + return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName); +} diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp index cfca167f8bf..f597c56837f 100644 --- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp +++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp @@ -131,17 +131,17 @@ LLVM_NODISCARD static bool isRawStringLiteral(const char *First, --Current; if (*Current != 'R') return false; - if (First == Current || !isIdentifierBody(*--Current)) + if (First == Current || !isAsciiIdentifierContinue(*--Current)) return true; // Check for a prefix of "u", "U", or "L". if (*Current == 'u' || *Current == 'U' || *Current == 'L') - return First == Current || !isIdentifierBody(*--Current); + return First == Current || !isAsciiIdentifierContinue(*--Current); // Check for a prefix of "u8". if (*Current != '8' || First == Current || *Current-- != 'u') return false; - return First == Current || !isIdentifierBody(*--Current); + return First == Current || !isAsciiIdentifierContinue(*--Current); } static void skipRawString(const char *&First, const char *const End) { @@ -319,7 +319,7 @@ static bool isQuoteCppDigitSeparator(const char *const Start, if (!isPreprocessingNumberBody(Prev)) return false; // The next character should be a valid identifier body character. - return (Cur + 1) < End && isIdentifierBody(*(Cur + 1)); + return (Cur + 1) < End && isAsciiIdentifierContinue(*(Cur + 1)); } static void skipLine(const char *&First, const char *const End) { @@ -484,7 +484,7 @@ void Minimizer::printAdjacentModuleNameParts(const char *&First, const char *Last = First; do ++Last; - while (Last != End && (isIdentifierBody(*Last) || *Last == '.')); + while (Last != End && (isAsciiIdentifierContinue(*Last) || *Last == '.')); append(First, Last); First = Last; } @@ -507,7 +507,7 @@ bool Minimizer::printAtImportBody(const char *&First, const char *const End) { } // Don't handle macro expansions inside @import for now. - if (!isIdentifierBody(*First) && *First != '.') + if (!isAsciiIdentifierContinue(*First) && *First != '.') return true; printAdjacentModuleNameParts(First, End); @@ -524,9 +524,9 @@ void Minimizer::printDirectiveBody(const char *&First, const char *const End) { LLVM_NODISCARD static const char *lexRawIdentifier(const char *First, const char *const End) { - assert(isIdentifierBody(*First) && "invalid identifer"); + assert(isAsciiIdentifierContinue(*First) && "invalid identifer"); const char *Last = First + 1; - while (Last != End && isIdentifierBody(*Last)) + while (Last != End && isAsciiIdentifierContinue(*Last)) ++Last; return Last; } @@ -540,7 +540,7 @@ getIdentifierContinuation(const char *First, const char *const End) { skipNewline(First, End); if (First == End) return nullptr; - return isIdentifierBody(First[0]) ? First : nullptr; + return isAsciiIdentifierContinue(First[0]) ? First : nullptr; } Minimizer::IdInfo Minimizer::lexIdentifier(const char *First, @@ -569,7 +569,7 @@ void Minimizer::printAdjacentMacroArgs(const char *&First, do ++Last; while (Last != End && - (isIdentifierBody(*Last) || *Last == '.' || *Last == ',')); + (isAsciiIdentifierContinue(*Last) || *Last == '.' || *Last == ',')); append(First, Last); First = Last; } @@ -588,7 +588,7 @@ bool Minimizer::printMacroArgs(const char *&First, const char *const End) { } // This is intentionally fairly liberal. - if (!(isIdentifierBody(*First) || *First == '.' || *First == ',')) + if (!(isAsciiIdentifierContinue(*First) || *First == '.' || *First == ',')) return true; printAdjacentMacroArgs(First, End); @@ -602,7 +602,7 @@ bool Minimizer::printMacroArgs(const char *&First, const char *const End) { bool Minimizer::isNextIdentifier(StringRef Id, const char *&First, const char *const End) { skipWhitespace(First, End); - if (First == End || !isIdentifierHead(*First)) + if (First == End || !isAsciiIdentifierStart(*First)) return false; IdInfo FoundId = lexIdentifier(First, End); @@ -639,7 +639,7 @@ bool Minimizer::lexModule(const char *&First, const char *const End) { if (Id.Name == "export") { Export = true; skipWhitespace(First, End); - if (!isIdentifierBody(*First)) { + if (!isAsciiIdentifierContinue(*First)) { skipLine(First, End); return false; } @@ -663,7 +663,7 @@ bool Minimizer::lexModule(const char *&First, const char *const End) { case '"': break; default: - if (!isIdentifierBody(*First)) { + if (!isAsciiIdentifierContinue(*First)) { skipLine(First, End); return false; } @@ -690,7 +690,7 @@ bool Minimizer::lexDefine(const char *&First, const char *const End) { append("#define "); skipWhitespace(First, End); - if (!isIdentifierHead(*First)) + if (!isAsciiIdentifierStart(*First)) return reportError(First, diag::err_pp_macro_not_identifier); IdInfo Id = lexIdentifier(First, End); @@ -722,7 +722,7 @@ bool Minimizer::lexDefine(const char *&First, const char *const End) { bool Minimizer::lexPragma(const char *&First, const char *const End) { // #pragma. skipWhitespace(First, End); - if (First == End || !isIdentifierHead(*First)) + if (First == End || !isAsciiIdentifierStart(*First)) return false; IdInfo FoundId = lexIdentifier(First, End); @@ -734,6 +734,27 @@ bool Minimizer::lexPragma(const char *&First, const char *const End) { append("#pragma once\n"); return false; } + if (FoundId.Name == "push_macro") { + // #pragma push_macro + makeToken(pp_pragma_push_macro); + append("#pragma push_macro"); + printDirectiveBody(First, End); + return false; + } + if (FoundId.Name == "pop_macro") { + // #pragma pop_macro + makeToken(pp_pragma_pop_macro); + append("#pragma pop_macro"); + printDirectiveBody(First, End); + return false; + } + if (FoundId.Name == "include_alias") { + // #pragma include_alias + makeToken(pp_pragma_include_alias); + append("#pragma include_alias"); + printDirectiveBody(First, End); + return false; + } if (FoundId.Name != "clang") { skipLine(First, End); @@ -827,7 +848,7 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { if (First == End) return reportError(First, diag::err_pp_expected_eol); - if (!isIdentifierHead(*First)) { + if (!isAsciiIdentifierStart(*First)) { skipLine(First, End); return false; } @@ -835,6 +856,10 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { // Figure out the token. IdInfo Id = lexIdentifier(First, End); First = Id.Last; + + if (Id.Name == "pragma") + return lexPragma(First, End); + auto Kind = llvm::StringSwitch(Id.Name) .Case("include", pp_include) .Case("__include_macros", pp___include_macros) @@ -850,7 +875,6 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { .Case("elifndef", pp_elifndef) .Case("else", pp_else) .Case("endif", pp_endif) - .Case("pragma", pp_pragma_import) .Default(pp_none); if (Kind == pp_none) { skipDirective(Id.Name, First, End); @@ -863,9 +887,6 @@ bool Minimizer::lexPPLine(const char *&First, const char *const End) { if (Kind == pp_define) return lexDefine(First, End); - if (Kind == pp_pragma_import) - return lexPragma(First, End); - // Everything else. return lexDefault(Kind, Id.Name, First, End); } diff --git a/clang/lib/Lex/HeaderMap.cpp b/clang/lib/Lex/HeaderMap.cpp index ae5e6b22195..0001fc348ed 100644 --- a/clang/lib/Lex/HeaderMap.cpp +++ b/clang/lib/Lex/HeaderMap.cpp @@ -194,19 +194,6 @@ LLVM_DUMP_METHOD void HeaderMapImpl::dump() const { } } -/// LookupFile - Check to see if the specified relative filename is located in -/// this HeaderMap. If so, open it and return its FileEntry. -Optional HeaderMap::LookupFile(StringRef Filename, - FileManager &FM) const { - - SmallString<1024> Path; - StringRef Dest = HeaderMapImpl::lookupFilename(Filename, Path); - if (Dest.empty()) - return None; - - return FM.getOptionalFileRef(Dest); -} - StringRef HeaderMapImpl::lookupFilename(StringRef Filename, SmallVectorImpl &DestPath) const { const HMapHeader &Hdr = getHeader(); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index d5adbcf62cb..a0b60118a1a 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -91,7 +91,7 @@ void HeaderSearch::PrintStats() { << FileInfo.size() << " files tracked.\n"; unsigned NumOnceOnlyFiles = 0, MaxNumIncludes = 0, NumSingleIncludedFiles = 0; for (unsigned i = 0, e = FileInfo.size(); i != e; ++i) { - NumOnceOnlyFiles += FileInfo[i].isImport; + NumOnceOnlyFiles += (FileInfo[i].isPragmaOnce || FileInfo[i].isImport); if (MaxNumIncludes < FileInfo[i].NumIncludes) MaxNumIncludes = FileInfo[i].NumIncludes; NumSingleIncludedFiles += FileInfo[i].NumIncludes == 1; @@ -108,6 +108,20 @@ void HeaderSearch::PrintStats() { << NumSubFrameworkLookups << " subframework lookups.\n"; } +std::vector HeaderSearch::computeUserEntryUsage() const { + std::vector UserEntryUsage(HSOpts->UserEntries.size()); + for (unsigned I = 0, E = SearchDirsUsage.size(); I < E; ++I) { + // Check whether this DirectoryLookup has been successfully used. + if (SearchDirsUsage[I]) { + auto UserEntryIdxIt = SearchDirToHSEntry.find(I); + // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry. + if (UserEntryIdxIt != SearchDirToHSEntry.end()) + UserEntryUsage[UserEntryIdxIt->second] = true; + } + } + return UserEntryUsage; +} + /// CreateHeaderMap - This method returns a HeaderMap for the specified /// FileEntry, uniquing them through the 'HeaderMaps' datastructure. const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE) { @@ -229,7 +243,8 @@ std::string HeaderSearch::getCachedModuleFileNameImpl(StringRef ModuleName, return Result.str().str(); } -Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch, +Module *HeaderSearch::lookupModule(StringRef ModuleName, + SourceLocation ImportLoc, bool AllowSearch, bool AllowExtraModuleMapSearch) { // Look in the module map to determine if there is a module by this name. Module *Module = ModMap.findModule(ModuleName); @@ -237,7 +252,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch, return Module; StringRef SearchName = ModuleName; - Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch); + Module = lookupModule(ModuleName, SearchName, ImportLoc, + AllowExtraModuleMapSearch); // The facility for "private modules" -- adjacent, optional module maps named // module.private.modulemap that are supposed to define private submodules -- @@ -248,19 +264,23 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch, // could force building unwanted dependencies into the parent module and cause // dependency cycles. if (!Module && SearchName.consume_back("_Private")) - Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch); + Module = lookupModule(ModuleName, SearchName, ImportLoc, + AllowExtraModuleMapSearch); if (!Module && SearchName.consume_back("Private")) - Module = lookupModule(ModuleName, SearchName, AllowExtraModuleMapSearch); + Module = lookupModule(ModuleName, SearchName, ImportLoc, + AllowExtraModuleMapSearch); return Module; } Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName, + SourceLocation ImportLoc, bool AllowExtraModuleMapSearch) { Module *Module = nullptr; + unsigned Idx; // Look through the various header search paths to load any available module // maps, searching for a module map that describes this module. - for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) { + for (Idx = 0; Idx != SearchDirs.size(); ++Idx) { if (SearchDirs[Idx].isFramework()) { // Search for or infer a module map for a framework. Here we use // SearchName rather than ModuleName, to permit finding private modules @@ -323,6 +343,9 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, StringRef SearchName, break; } + if (Module) + noteLookupUsage(Idx, ImportLoc); + return Module; } @@ -435,16 +458,19 @@ Optional DirectoryLookup::LookupFile( if (llvm::sys::path::is_relative(Dest)) { MappedName.append(Dest.begin(), Dest.end()); Filename = StringRef(MappedName.begin(), MappedName.size()); - Optional Result = HM->LookupFile(Filename, HS.getFileMgr()); - if (Result) { - FixupSearchPath(); - return *Result; - } - } else if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) { + Dest = HM->lookupFilename(Filename, Path); + } + + if (auto Res = HS.getFileMgr().getOptionalFileRef(Dest)) { FixupSearchPath(); return *Res; } + // Header maps need to be marked as used whenever the filename matches. + // The case where the target file **exists** is handled by callee of this + // function as part of the regular logic that applies to include search paths. + // The case where the target file **does not exist** is handled here: + HS.noteLookupUsage(*HS.searchDirIdx(*this), IncludeLoc); return None; } @@ -649,6 +675,21 @@ Optional DirectoryLookup::DoFrameworkLookup( return None; } +void HeaderSearch::cacheLookupSuccess(LookupFileCacheInfo &CacheLookup, + unsigned HitIdx, SourceLocation Loc) { + CacheLookup.HitIdx = HitIdx; + noteLookupUsage(HitIdx, Loc); +} + +void HeaderSearch::noteLookupUsage(unsigned HitIdx, SourceLocation Loc) { + SearchDirsUsage[HitIdx] = true; + + auto UserEntryIdxIt = SearchDirToHSEntry.find(HitIdx); + if (UserEntryIdxIt != SearchDirToHSEntry.end()) + Diags.Report(Loc, diag::remark_pp_search_path_usage) + << HSOpts->UserEntries[UserEntryIdxIt->second].Path; +} + void HeaderSearch::setTarget(const TargetInfo &Target) { ModMap.setTarget(Target); } @@ -964,13 +1005,13 @@ Optional HeaderSearch::LookupFile( // If this file is found in a header map and uses the framework style of // includes, then this header is part of a framework we're building. - if (CurDir->isIndexHeaderMap()) { + if (CurDir->isHeaderMap() && isAngled) { size_t SlashPos = Filename.find('/'); - if (SlashPos != StringRef::npos) { + if (SlashPos != StringRef::npos) + HFI.Framework = + getUniqueFrameworkName(StringRef(Filename.begin(), SlashPos)); + if (CurDir->isIndexHeaderMap()) HFI.IndexHeaderMapHeader = 1; - HFI.Framework = getUniqueFrameworkName(StringRef(Filename.begin(), - SlashPos)); - } } if (checkMSVCHeaderSearch(Diags, MSFE ? &MSFE->getFileEntry() : nullptr, @@ -987,7 +1028,7 @@ Optional HeaderSearch::LookupFile( &File->getFileEntry(), isAngled, FoundByHeaderMap); // Remember this location for the next lookup we do. - CacheLookup.HitIdx = i; + cacheLookupSuccess(CacheLookup, i, IncludeLoc); return File; } @@ -996,7 +1037,7 @@ Optional HeaderSearch::LookupFile( // resolve "foo.h" any other way, change the include to , where // "Foo" is the name of the framework in which the including header was found. if (!Includers.empty() && Includers.front().first && !isAngled && - Filename.find('/') == StringRef::npos) { + !Filename.contains('/')) { HeaderFileInfo &IncludingHFI = getFileInfo(Includers.front().first); if (IncludingHFI.IndexHeaderMapHeader) { SmallString<128> ScratchFilename; @@ -1017,8 +1058,8 @@ Optional HeaderSearch::LookupFile( return MSFE; } - LookupFileCacheInfo &CacheLookup = LookupFileCache[Filename]; - CacheLookup.HitIdx = LookupFileCache[ScratchFilename].HitIdx; + cacheLookupSuccess(LookupFileCache[Filename], + LookupFileCache[ScratchFilename].HitIdx, IncludeLoc); // FIXME: SuggestedModule. return File; } @@ -1269,9 +1310,12 @@ void HeaderSearch::MarkFileModuleHeader(const FileEntry *FE, bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, const FileEntry *File, bool isImport, - bool ModulesEnabled, Module *M) { + bool ModulesEnabled, Module *M, + bool &IsFirstIncludeOfFile) { ++NumIncluded; // Count # of attempted #includes. + IsFirstIncludeOfFile = false; + // Get information about this file. HeaderFileInfo &FileInfo = getFileInfo(File); @@ -1325,7 +1369,7 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, } else { // Otherwise, if this is a #include of a file that was previously #import'd // or if this is the second #include of a #pragma once file, ignore it. - if (FileInfo.isImport && !TryEnterImported()) + if ((FileInfo.isPragmaOnce || FileInfo.isImport) && !TryEnterImported()) return false; } @@ -1346,6 +1390,8 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, // Increment the number of times this file has been included. ++FileInfo.NumIncludes; + IsFirstIncludeOfFile = FileInfo.NumIncludes == 1; + return true; } @@ -1357,6 +1403,13 @@ size_t HeaderSearch::getTotalMemory() const { + FrameworkMap.getAllocator().getTotalMemory(); } +Optional HeaderSearch::searchDirIdx(const DirectoryLookup &DL) const { + for (unsigned I = 0; I < SearchDirs.size(); ++I) + if (&SearchDirs[I] == &DL) + return I; + return None; +} + StringRef HeaderSearch::getUniqueFrameworkName(StringRef Framework) { return FrameworkNames.insert(Framework).first->first(); } diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 3034af231e0..38467a1835d 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -133,10 +133,10 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, /// assumes that the associated file buffer and Preprocessor objects will /// outlive it, so it doesn't take ownership of either of them. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, - Preprocessor &PP) + Preprocessor &PP, bool IsFirstIncludeOfFile) : PreprocessorLexer(&PP, FID), FileLoc(PP.getSourceManager().getLocForStartOfFile(FID)), - LangOpts(PP.getLangOpts()) { + LangOpts(PP.getLangOpts()), IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(InputFile.getBufferStart(), InputFile.getBufferStart(), InputFile.getBufferEnd()); @@ -147,8 +147,10 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &InputFile, /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, - const char *BufStart, const char *BufPtr, const char *BufEnd) - : FileLoc(fileloc), LangOpts(langOpts) { + const char *BufStart, const char *BufPtr, const char *BufEnd, + bool IsFirstIncludeOfFile) + : FileLoc(fileloc), LangOpts(langOpts), + IsFirstTimeLexingFile(IsFirstIncludeOfFile) { InitLexer(BufStart, BufPtr, BufEnd); // We *are* in raw mode. @@ -159,9 +161,11 @@ Lexer::Lexer(SourceLocation fileloc, const LangOptions &langOpts, /// suitable for calls to 'LexFromRawLexer'. This lexer assumes that the text /// range will outlive it, so it doesn't take ownership of it. Lexer::Lexer(FileID FID, const llvm::MemoryBufferRef &FromFile, - const SourceManager &SM, const LangOptions &langOpts) + const SourceManager &SM, const LangOptions &langOpts, + bool IsFirstIncludeOfFile) : Lexer(SM.getLocForStartOfFile(FID), langOpts, FromFile.getBufferStart(), - FromFile.getBufferStart(), FromFile.getBufferEnd()) {} + FromFile.getBufferStart(), FromFile.getBufferEnd(), + IsFirstIncludeOfFile) {} void Lexer::resetExtendedTokenMode() { assert(PP && "Cannot reset token mode without a preprocessor"); @@ -1062,8 +1066,8 @@ StringRef Lexer::getImmediateMacroNameForDiagnostics( return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength); } -bool Lexer::isIdentifierBodyChar(char c, const LangOptions &LangOpts) { - return isIdentifierBody(c, LangOpts.DollarIdents); +bool Lexer::isAsciiIdentifierContinueChar(char c, const LangOptions &LangOpts) { + return isAsciiIdentifierContinue(c, LangOpts.DollarIdents); } bool Lexer::isNewLineEscaped(const char *BufferStart, const char *Str) { @@ -1446,19 +1450,30 @@ void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) { IsAtPhysicalStartOfLine = StartOfLine; } +static bool isUnicodeWhitespace(uint32_t Codepoint) { + static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars( + UnicodeWhitespaceCharRanges); + return UnicodeWhitespaceChars.contains(Codepoint); +} + static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { if (LangOpts.AsmPreprocessor) { return false; } else if (LangOpts.DollarIdents && '$' == C) { return true; - } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { + } else if (LangOpts.CPlusPlus) { + // A non-leading codepoint must have the XID_Continue property. + // XIDContinueRanges doesn't contains characters also in XIDStartRanges, + // so we need to check both tables. + // '_' doesn't have the XID_Continue property but is allowed in C++. + static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); + static const llvm::sys::UnicodeCharSet XIDContinueChars(XIDContinueRanges); + return C == '_' || XIDStartChars.contains(C) || + XIDContinueChars.contains(C); + } else if (LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11AllowedIDChars( C11AllowedIDCharRanges); return C11AllowedIDChars.contains(C); - } else if (LangOpts.CPlusPlus) { - static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( - CXX03AllowedIDCharRanges); - return CXX03AllowedIDChars.contains(C); } else { static const llvm::sys::UnicodeCharSet C99AllowedIDChars( C99AllowedIDCharRanges); @@ -1467,20 +1482,24 @@ static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { } static bool isAllowedInitiallyIDChar(uint32_t C, const LangOptions &LangOpts) { - assert(isAllowedIDChar(C, LangOpts)); if (LangOpts.AsmPreprocessor) { return false; - } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { + } + if (LangOpts.CPlusPlus) { + static const llvm::sys::UnicodeCharSet XIDStartChars(XIDStartRanges); + // '_' doesn't have the XID_Start property but is allowed in C++. + return C == '_' || XIDStartChars.contains(C); + } + if (!isAllowedIDChar(C, LangOpts)) + return false; + if (LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11DisallowedInitialIDChars( C11DisallowedInitialIDCharRanges); return !C11DisallowedInitialIDChars.contains(C); - } else if (LangOpts.CPlusPlus) { - return true; - } else { - static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( - C99DisallowedInitialIDCharRanges); - return !C99DisallowedInitialIDChars.contains(C); } + static const llvm::sys::UnicodeCharSet C99DisallowedInitialIDChars( + C99DisallowedInitialIDCharRanges); + return !C99DisallowedInitialIDChars.contains(C); } static inline CharSourceRange makeCharRange(Lexer &L, const char *Begin, @@ -1512,16 +1531,6 @@ static void maybeDiagnoseIDCharCompat(DiagnosticsEngine &Diags, uint32_t C, << CannotStartIdentifier; } } - - // Check C++98 compatibility. - if (!Diags.isIgnored(diag::warn_cxx98_compat_unicode_id, Range.getBegin())) { - static const llvm::sys::UnicodeCharSet CXX03AllowedIDChars( - CXX03AllowedIDCharRanges); - if (!CXX03AllowedIDChars.contains(C)) { - Diags.Report(Range.getBegin(), diag::warn_cxx98_compat_unicode_id) - << Range; - } - } } /// After encountering UTF-8 character C and interpreting it as an identifier @@ -1608,14 +1617,56 @@ static void maybeDiagnoseUTF8Homoglyph(DiagnosticsEngine &Diags, uint32_t C, } } +static void diagnoseInvalidUnicodeCodepointInIdentifier( + DiagnosticsEngine &Diags, const LangOptions &LangOpts, uint32_t CodePoint, + CharSourceRange Range, bool IsFirst) { + if (isASCII(CodePoint)) + return; + + bool IsIDStart = isAllowedInitiallyIDChar(CodePoint, LangOpts); + bool IsIDContinue = IsIDStart || isAllowedIDChar(CodePoint, LangOpts); + + if ((IsFirst && IsIDStart) || (!IsFirst && IsIDContinue)) + return; + + bool InvalidOnlyAtStart = IsFirst && !IsIDStart && IsIDContinue; + + llvm::SmallString<5> CharBuf; + llvm::raw_svector_ostream CharOS(CharBuf); + llvm::write_hex(CharOS, CodePoint, llvm::HexPrintStyle::Upper, 4); + + if (!IsFirst || InvalidOnlyAtStart) { + Diags.Report(Range.getBegin(), diag::err_character_not_allowed_identifier) + << Range << CharBuf << int(InvalidOnlyAtStart) + << FixItHint::CreateRemoval(Range); + } else { + Diags.Report(Range.getBegin(), diag::err_character_not_allowed) + << Range << CharBuf << FixItHint::CreateRemoval(Range); + } +} + bool Lexer::tryConsumeIdentifierUCN(const char *&CurPtr, unsigned Size, Token &Result) { const char *UCNPtr = CurPtr + Size; uint32_t CodePoint = tryReadUCN(UCNPtr, CurPtr, /*Token=*/nullptr); - if (CodePoint == 0 || !isAllowedIDChar(CodePoint, LangOpts)) + if (CodePoint == 0) { return false; + } - if (!isLexingRawMode()) + if (!isAllowedIDChar(CodePoint, LangOpts)) { + if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint)) + return false; + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, CodePoint, + makeCharRange(*this, CurPtr, UCNPtr), + /*IsFirst=*/false); + + // We got a unicode codepoint that is neither a space nor a + // a valid identifier part. + // Carry on as if the codepoint was valid for recovery purposes. + } else if (!isLexingRawMode()) maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UCNPtr), /*IsFirst=*/false); @@ -1638,11 +1689,22 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { (const llvm::UTF8 *)BufferEnd, &CodePoint, llvm::strictConversion); - if (Result != llvm::conversionOK || - !isAllowedIDChar(static_cast(CodePoint), LangOpts)) + if (Result != llvm::conversionOK) return false; - if (!isLexingRawMode()) { + if (!isAllowedIDChar(static_cast(CodePoint), LangOpts)) { + if (isASCII(CodePoint) || isUnicodeWhitespace(CodePoint)) + return false; + + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, CodePoint, + makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); + // We got a unicode codepoint that is neither a space nor a + // a valid identifier part. Carry on as if the codepoint was + // valid for recovery purposes. + } else if (!isLexingRawMode()) { maybeDiagnoseIDCharCompat(PP->getDiagnostics(), CodePoint, makeCharRange(*this, CurPtr, UnicodePtr), /*IsFirst=*/false); @@ -1654,103 +1716,128 @@ bool Lexer::tryConsumeIdentifierUTF8Char(const char *&CurPtr) { return true; } -bool Lexer::LexIdentifier(Token &Result, const char *CurPtr) { - // Match [_A-Za-z0-9]*, we have already matched [_A-Za-z$] - unsigned Size; - unsigned char C = *CurPtr++; - while (isIdentifierBody(C)) - C = *CurPtr++; - - --CurPtr; // Back up over the skipped character. - - // Fast path, no $,\,? in identifier found. '\' might be an escaped newline - // or UCN, and ? might be a trigraph for '\', an escaped newline or UCN. - // - // TODO: Could merge these checks into an InfoTable flag to make the - // comparison cheaper - if (isASCII(C) && C != '\\' && C != '?' && - (C != '$' || !LangOpts.DollarIdents)) { -FinishIdentifier: - const char *IdStart = BufferPtr; - FormTokenWithChars(Result, CurPtr, tok::raw_identifier); - Result.setRawIdentifierData(IdStart); - - // If we are in raw mode, return this identifier raw. There is no need to - // look up identifier information or attempt to macro expand it. - if (LexingRawMode) - return true; - - // Fill in Result.IdentifierInfo and update the token kind, - // looking up the identifier in the identifier table. - IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); - // Note that we have to call PP->LookUpIdentifierInfo() even for code - // completion, it writes IdentifierInfo into Result, and callers rely on it. - - // If the completion point is at the end of an identifier, we want to treat - // the identifier as incomplete even if it resolves to a macro or a keyword. - // This allows e.g. 'class^' to complete to 'classifier'. - if (isCodeCompletionPoint(CurPtr)) { - // Return the code-completion token. - Result.setKind(tok::code_completion); - // Skip the code-completion char and all immediate identifier characters. - // This ensures we get consistent behavior when completing at any point in - // an identifier (i.e. at the start, in the middle, at the end). Note that - // only simple cases (i.e. [a-zA-Z0-9_]) are supported to keep the code - // simpler. - assert(*CurPtr == 0 && "Completion character must be 0"); - ++CurPtr; - // Note that code completion token is not added as a separate character - // when the completion point is at the end of the buffer. Therefore, we need - // to check if the buffer has ended. - if (CurPtr < BufferEnd) { - while (isIdentifierBody(*CurPtr)) - ++CurPtr; - } - BufferPtr = CurPtr; - return true; +bool Lexer::LexUnicodeIdentifierStart(Token &Result, uint32_t C, + const char *CurPtr) { + if (isAllowedInitiallyIDChar(C, LangOpts)) { + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput()) { + maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C, + makeCharRange(*this, BufferPtr, CurPtr), + /*IsFirst=*/true); + maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), C, + makeCharRange(*this, BufferPtr, CurPtr)); } - // Finally, now that we know we have an identifier, pass this off to the - // preprocessor, which may macro expand it or something. - if (II->isHandleIdentifierCase()) - return PP->HandleIdentifier(Result); - - return true; + MIOpt.ReadToken(); + return LexIdentifierContinue(Result, CurPtr); } - // Otherwise, $,\,? in identifier found. Enter slower path. + if (!isLexingRawMode() && !ParsingPreprocessorDirective && + !PP->isPreprocessedOutput() && !isASCII(*BufferPtr) && + !isAllowedInitiallyIDChar(C, LangOpts) && !isUnicodeWhitespace(C)) { + // Non-ASCII characters tend to creep into source code unintentionally. + // Instead of letting the parser complain about the unknown token, + // just drop the character. + // Note that we can /only/ do this when the non-ASCII character is actually + // spelled as Unicode, not written as a UCN. The standard requires that + // we not throw away any possible preprocessor tokens, but there's a + // loophole in the mapping of Unicode characters to basic character set + // characters that allows us to map these particular characters to, say, + // whitespace. + diagnoseInvalidUnicodeCodepointInIdentifier( + PP->getDiagnostics(), LangOpts, C, + makeCharRange(*this, BufferPtr, CurPtr), /*IsStart*/ true); + BufferPtr = CurPtr; + return false; + } - C = getCharAndSize(CurPtr, Size); + // Otherwise, we have an explicit UCN or a character that's unlikely to show + // up by accident. + MIOpt.ReadToken(); + FormTokenWithChars(Result, CurPtr, tok::unknown); + return true; +} + +bool Lexer::LexIdentifierContinue(Token &Result, const char *CurPtr) { + // Match [_A-Za-z0-9]*, we have already matched an identifier start. while (true) { + unsigned char C = *CurPtr; + // Fast path. + if (isAsciiIdentifierContinue(C)) { + ++CurPtr; + continue; + } + + unsigned Size; + // Slow path: handle trigraph, unicode codepoints, UCNs. + C = getCharAndSize(CurPtr, Size); + if (isAsciiIdentifierContinue(C)) { + CurPtr = ConsumeChar(CurPtr, Size, Result); + continue; + } if (C == '$') { // If we hit a $ and they are not supported in identifiers, we are done. - if (!LangOpts.DollarIdents) goto FinishIdentifier; - + if (!LangOpts.DollarIdents) + break; // Otherwise, emit a diagnostic and continue. if (!isLexingRawMode()) Diag(CurPtr, diag::ext_dollar_in_identifier); CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); continue; - } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { - C = getCharAndSize(CurPtr, Size); - continue; - } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { - C = getCharAndSize(CurPtr, Size); - continue; - } else if (!isIdentifierBody(C)) { - goto FinishIdentifier; - } - - // Otherwise, this character is good, consume it. - CurPtr = ConsumeChar(CurPtr, Size, Result); - - C = getCharAndSize(CurPtr, Size); - while (isIdentifierBody(C)) { - CurPtr = ConsumeChar(CurPtr, Size, Result); - C = getCharAndSize(CurPtr, Size); } + if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) + continue; + if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) + continue; + // Neither an expected Unicode codepoint nor a UCN. + break; } + + const char *IdStart = BufferPtr; + FormTokenWithChars(Result, CurPtr, tok::raw_identifier); + Result.setRawIdentifierData(IdStart); + + // If we are in raw mode, return this identifier raw. There is no need to + // look up identifier information or attempt to macro expand it. + if (LexingRawMode) + return true; + + // Fill in Result.IdentifierInfo and update the token kind, + // looking up the identifier in the identifier table. + IdentifierInfo *II = PP->LookUpIdentifierInfo(Result); + // Note that we have to call PP->LookUpIdentifierInfo() even for code + // completion, it writes IdentifierInfo into Result, and callers rely on it. + + // If the completion point is at the end of an identifier, we want to treat + // the identifier as incomplete even if it resolves to a macro or a keyword. + // This allows e.g. 'class^' to complete to 'classifier'. + if (isCodeCompletionPoint(CurPtr)) { + // Return the code-completion token. + Result.setKind(tok::code_completion); + // Skip the code-completion char and all immediate identifier characters. + // This ensures we get consistent behavior when completing at any point in + // an identifier (i.e. at the start, in the middle, at the end). Note that + // only simple cases (i.e. [a-zA-Z0-9_]) are supported to keep the code + // simpler. + assert(*CurPtr == 0 && "Completion character must be 0"); + ++CurPtr; + // Note that code completion token is not added as a separate character + // when the completion point is at the end of the buffer. Therefore, we need + // to check if the buffer has ended. + if (CurPtr < BufferEnd) { + while (isAsciiIdentifierContinue(*CurPtr)) + ++CurPtr; + } + BufferPtr = CurPtr; + return true; + } + + // Finally, now that we know we have an identifier, pass this off to the + // preprocessor, which may macro expand it or something. + if (II->isHandleIdentifierCase()) + return PP->HandleIdentifier(Result); + + return true; } /// isHexaLiteral - Return true if Start points to a hex constant. @@ -1806,7 +1893,7 @@ bool Lexer::LexNumericConstant(Token &Result, const char *CurPtr) { if (C == '\'' && (getLangOpts().CPlusPlus14 || getLangOpts().C2x)) { unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Size, NextSize, getLangOpts()); - if (isIdentifierBody(Next)) { + if (isAsciiIdentifierContinue(Next)) { if (!isLexingRawMode()) Diag(CurPtr, getLangOpts().CPlusPlus ? diag::warn_cxx11_compat_digit_separator @@ -1841,7 +1928,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, char C = getCharAndSize(CurPtr, Size); bool Consumed = false; - if (!isIdentifierHead(C)) { + if (!isAsciiIdentifierStart(C)) { if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) Consumed = true; else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) @@ -1880,7 +1967,7 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, unsigned NextSize; char Next = getCharAndSizeNoWarn(CurPtr + Consumed, NextSize, getLangOpts()); - if (!isIdentifierBody(Next)) { + if (!isAsciiIdentifierContinue(Next)) { // End of suffix. Check whether this is on the allowed list. const StringRef CompleteSuffix(Buffer, Chars); IsUDSuffix = StringLiteralParser::isValidUDSuffix(getLangOpts(), @@ -1912,10 +1999,12 @@ const char *Lexer::LexUDSuffix(Token &Result, const char *CurPtr, Result.setFlag(Token::HasUDSuffix); while (true) { C = getCharAndSize(CurPtr, Size); - if (isIdentifierBody(C)) { CurPtr = ConsumeChar(CurPtr, Size, Result); } - else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) {} - else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) {} - else break; + if (isAsciiIdentifierContinue(C)) { + CurPtr = ConsumeChar(CurPtr, Size, Result); + } else if (C == '\\' && tryConsumeIdentifierUCN(CurPtr, Size, Result)) { + } else if (!isASCII(C) && tryConsumeIdentifierUTF8Char(CurPtr)) { + } else + break; } return CurPtr; @@ -2811,11 +2900,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { ConditionalStack.pop_back(); } + SourceLocation EndLoc = getSourceLocation(BufferEnd); // C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue // a pedwarn. if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) { DiagnosticsEngine &Diags = PP->getDiagnostics(); - SourceLocation EndLoc = getSourceLocation(BufferEnd); unsigned DiagID; if (LangOpts.CPlusPlus11) { @@ -2838,7 +2927,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { BufferPtr = CurPtr; // Finally, let the preprocessor handle this. - return PP->HandleEndOfFile(Result, isPragmaLexer()); + return PP->HandleEndOfFile(Result, EndLoc, isPragmaLexer()); } /// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from @@ -3027,6 +3116,10 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, Token *Result) { unsigned CharSize; char Kind = getCharAndSize(StartPtr, CharSize); + bool Delimited = false; + bool FoundEndDelimiter = false; + unsigned Count = 0; + bool Diagnose = Result && !isLexingRawMode(); unsigned NumHexDigits; if (Kind == 'u') @@ -3037,7 +3130,7 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, return 0; if (!LangOpts.CPlusPlus && !LangOpts.C99) { - if (Result && !isLexingRawMode()) + if (Diagnose) Diag(SlashLoc, diag::warn_ucn_not_valid_in_c89); return 0; } @@ -3046,39 +3139,70 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, const char *KindLoc = &CurPtr[-1]; uint32_t CodePoint = 0; - for (unsigned i = 0; i < NumHexDigits; ++i) { + while (Count != NumHexDigits || Delimited) { char C = getCharAndSize(CurPtr, CharSize); + if (!Delimited && C == '{') { + Delimited = true; + CurPtr += CharSize; + continue; + } + + if (Delimited && C == '}') { + CurPtr += CharSize; + FoundEndDelimiter = true; + break; + } unsigned Value = llvm::hexDigitValue(C); if (Value == -1U) { - if (Result && !isLexingRawMode()) { - if (i == 0) { - Diag(BufferPtr, diag::warn_ucn_escape_no_digits) - << StringRef(KindLoc, 1); - } else { - Diag(BufferPtr, diag::warn_ucn_escape_incomplete); - - // If the user wrote \U1234, suggest a fixit to \u. - if (i == 4 && NumHexDigits == 8) { - CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1); - Diag(KindLoc, diag::note_ucn_four_not_eight) - << FixItHint::CreateReplacement(URange, "u"); - } - } - } + if (!Delimited) + break; + if (Diagnose) + Diag(BufferPtr, diag::warn_delimited_ucn_incomplete) + << StringRef(&C, 1); + return 0; + } + if (CodePoint & 0xF000'0000) { + if (Diagnose) + Diag(KindLoc, diag::err_escape_too_large) << 0; return 0; } CodePoint <<= 4; - CodePoint += Value; - + CodePoint |= Value; CurPtr += CharSize; + Count++; + } + + if (Count == 0) { + if (Diagnose) + Diag(StartPtr, FoundEndDelimiter ? diag::warn_delimited_ucn_empty + : diag::warn_ucn_escape_no_digits) + << StringRef(KindLoc, 1); + return 0; + } + + if (!Delimited && Count != NumHexDigits) { + if (Diagnose) { + Diag(BufferPtr, diag::warn_ucn_escape_incomplete); + // If the user wrote \U1234, suggest a fixit to \u. + if (Count == 4 && NumHexDigits == 8) { + CharSourceRange URange = makeCharRange(*this, KindLoc, KindLoc + 1); + Diag(KindLoc, diag::note_ucn_four_not_eight) + << FixItHint::CreateReplacement(URange, "u"); + } + } + return 0; + } + + if (Delimited && PP) { + Diag(BufferPtr, diag::ext_delimited_escape_sequence); } if (Result) { Result->setFlag(Token::HasUCN); - if (CurPtr - StartPtr == (ptrdiff_t)NumHexDigits + 2) + if (CurPtr - StartPtr == (ptrdiff_t)(Count + 2 + (Delimited ? 2 : 0))) StartPtr = CurPtr; else while (StartPtr != CurPtr) @@ -3136,10 +3260,8 @@ uint32_t Lexer::tryReadUCN(const char *&StartPtr, const char *SlashLoc, bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C, const char *CurPtr) { - static const llvm::sys::UnicodeCharSet UnicodeWhitespaceChars( - UnicodeWhitespaceCharRanges); if (!isLexingRawMode() && !PP->isPreprocessedOutput() && - UnicodeWhitespaceChars.contains(C)) { + isUnicodeWhitespace(C)) { Diag(BufferPtr, diag::ext_unicode_whitespace) << makeCharRange(*this, BufferPtr, CurPtr); @@ -3149,47 +3271,6 @@ bool Lexer::CheckUnicodeWhitespace(Token &Result, uint32_t C, return false; } -bool Lexer::LexUnicode(Token &Result, uint32_t C, const char *CurPtr) { - if (isAllowedIDChar(C, LangOpts) && isAllowedInitiallyIDChar(C, LangOpts)) { - if (!isLexingRawMode() && !ParsingPreprocessorDirective && - !PP->isPreprocessedOutput()) { - maybeDiagnoseIDCharCompat(PP->getDiagnostics(), C, - makeCharRange(*this, BufferPtr, CurPtr), - /*IsFirst=*/true); - maybeDiagnoseUTF8Homoglyph(PP->getDiagnostics(), C, - makeCharRange(*this, BufferPtr, CurPtr)); - } - - MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); - } - - if (!isLexingRawMode() && !ParsingPreprocessorDirective && - !PP->isPreprocessedOutput() && - !isASCII(*BufferPtr) && !isAllowedIDChar(C, LangOpts)) { - // Non-ASCII characters tend to creep into source code unintentionally. - // Instead of letting the parser complain about the unknown token, - // just drop the character. - // Note that we can /only/ do this when the non-ASCII character is actually - // spelled as Unicode, not written as a UCN. The standard requires that - // we not throw away any possible preprocessor tokens, but there's a - // loophole in the mapping of Unicode characters to basic character set - // characters that allows us to map these particular characters to, say, - // whitespace. - Diag(BufferPtr, diag::err_non_ascii) - << FixItHint::CreateRemoval(makeCharRange(*this, BufferPtr, CurPtr)); - - BufferPtr = CurPtr; - return false; - } - - // Otherwise, we have an explicit UCN or a character that's unlikely to show - // up by accident. - MIOpt.ReadToken(); - FormTokenWithChars(Result, CurPtr, tok::unknown); - return true; -} - void Lexer::PropagateLineStartLeadingSpaceInfo(Token &Result) { IsAtStartOfLine = Result.isAtStartOfLine(); HasLeadingSpace = Result.hasLeadingSpace(); @@ -3433,7 +3514,7 @@ LexNextToken: } // treat u like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'U': // Identifier (Uber) or C11/C++11 UTF-32 string literal // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3462,7 +3543,7 @@ LexNextToken: } // treat U like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'R': // Identifier or C++0x raw string literal // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3478,7 +3559,7 @@ LexNextToken: } // treat R like the start of an identifier. - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case 'L': // Identifier (Loony) or wide literal (L'x' or L"xyz"). // Notify MIOpt that we read a non-whitespace/non-comment token. @@ -3517,7 +3598,7 @@ LexNextToken: case '_': // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); case '$': // $ in identifiers. if (LangOpts.DollarIdents) { @@ -3525,7 +3606,7 @@ LexNextToken: Diag(CurPtr-1, diag::ext_dollar_in_identifier); // Notify MIOpt that we read a non-whitespace/non-comment token. MIOpt.ReadToken(); - return LexIdentifier(Result, CurPtr); + return LexIdentifierContinue(Result, CurPtr); } Kind = tok::unknown; @@ -3940,7 +4021,7 @@ LexNextToken: goto LexNextToken; } - return LexUnicode(Result, CodePoint, CurPtr); + return LexUnicodeIdentifierStart(Result, CodePoint, CurPtr); } } @@ -3972,7 +4053,7 @@ LexNextToken: // (We manually eliminate the tail call to avoid recursion.) goto LexNextToken; } - return LexUnicode(Result, CodePoint, CurPtr); + return LexUnicodeIdentifierStart(Result, CodePoint, CurPtr); } if (isLexingRawMode() || ParsingPreprocessorDirective || diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index 85d826ce9c6..76c8b324671 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -95,6 +95,8 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin, DiagnosticsEngine *Diags, const LangOptions &Features) { const char *EscapeBegin = ThisTokBuf; + bool Delimited = false; + bool EndDelimiterFound = false; // Skip the '\' char. ++ThisTokBuf; @@ -143,26 +145,47 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin, break; case 'x': { // Hex escape. ResultChar = 0; - if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { + if (ThisTokBuf != ThisTokEnd && *ThisTokBuf == '{') { + Delimited = true; + ThisTokBuf++; + if (*ThisTokBuf == '}') { + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_delimited_escape_empty); + return ResultChar; + } + } else if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { if (Diags) Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, diag::err_hex_escape_no_digits) << "x"; - HadError = true; - break; + return ResultChar; } // Hex escapes are a maximal series of hex digits. bool Overflow = false; for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) { - int CharVal = llvm::hexDigitValue(ThisTokBuf[0]); - if (CharVal == -1) break; + if (Delimited && *ThisTokBuf == '}') { + ThisTokBuf++; + EndDelimiterFound = true; + break; + } + int CharVal = llvm::hexDigitValue(*ThisTokBuf); + if (CharVal == -1) { + // Non delimited hex escape sequences stop at the first non-hex digit. + if (!Delimited) + break; + HadError = true; + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_delimited_escape_invalid) + << StringRef(ThisTokBuf, 1); + continue; + } // About to shift out a digit? if (ResultChar & 0xF0000000) Overflow = true; ResultChar <<= 4; ResultChar |= CharVal; } - // See if any bits will be truncated when evaluated as a character. if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { Overflow = true; @@ -170,9 +193,13 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin, } // Check for overflow. - if (Overflow && Diags) // Too many digits to fit in - Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, - diag::err_escape_too_large) << 0; + if (!HadError && Overflow) { // Too many digits to fit in + HadError = true; + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_escape_too_large) + << 0; + } break; } case '0': case '1': case '2': case '3': @@ -200,7 +227,58 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin, } break; } + case 'o': { + bool Overflow = false; + if (ThisTokBuf == ThisTokEnd || *ThisTokBuf != '{') { + HadError = true; + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_delimited_escape_missing_brace); + break; + } + ResultChar = 0; + Delimited = true; + ++ThisTokBuf; + if (*ThisTokBuf == '}') { + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_delimited_escape_empty); + return ResultChar; + } + + while (ThisTokBuf != ThisTokEnd) { + if (*ThisTokBuf == '}') { + EndDelimiterFound = true; + ThisTokBuf++; + break; + } + if (*ThisTokBuf < '0' || *ThisTokBuf > '7') { + HadError = true; + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_delimited_escape_invalid) + << StringRef(ThisTokBuf, 1); + ThisTokBuf++; + continue; + } + if (ResultChar & 0x020000000) + Overflow = true; + + ResultChar <<= 3; + ResultChar |= *ThisTokBuf++ - '0'; + } + // Check for overflow. Reject '\777', but not L'\777'. + if (!HadError && + (Overflow || (CharWidth != 32 && (ResultChar >> CharWidth) != 0))) { + HadError = true; + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_escape_too_large) + << 1; + ResultChar &= ~0U >> (32 - CharWidth); + } + break; + } // Otherwise, these are not valid escapes. case '(': case '{': case '[': case '%': // GCC accepts these as extensions. We warn about them as such though. @@ -224,6 +302,17 @@ static unsigned ProcessCharEscape(const char *ThisTokBegin, break; } + if (Delimited && Diags) { + if (!EndDelimiterFound) + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_expected) + << tok::r_brace; + else if (!HadError) { + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_delimited_escape_sequence); + } + } + return ResultChar; } @@ -245,18 +334,32 @@ void clang::expandUCNs(SmallVectorImpl &Buf, StringRef Input) { } ++I; - assert(*I == 'u' || *I == 'U'); + char Kind = *I; + ++I; + + assert(Kind == 'u' || Kind == 'U'); + uint32_t CodePoint = 0; + + if (Kind == 'u' && *I == '{') { + for (++I; *I != '}'; ++I) { + unsigned Value = llvm::hexDigitValue(*I); + assert(Value != -1U); + CodePoint <<= 4; + CodePoint += Value; + } + appendCodePoint(CodePoint, Buf); + continue; + } unsigned NumHexDigits; - if (*I == 'u') + if (Kind == 'u') NumHexDigits = 4; else NumHexDigits = 8; assert(I + NumHexDigits <= E); - uint32_t CodePoint = 0; - for (++I; NumHexDigits != 0; ++I, --NumHexDigits) { + for (; NumHexDigits != 0; ++I, --NumHexDigits) { unsigned Value = llvm::hexDigitValue(*I); assert(Value != -1U); @@ -282,28 +385,82 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, // Skip the '\u' char's. ThisTokBuf += 2; - if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { + bool Delimited = false; + bool EndDelimiterFound = false; + bool HasError = false; + + if (UcnBegin[1] == 'u' && in_char_string_literal && + ThisTokBuf != ThisTokEnd && *ThisTokBuf == '{') { + Delimited = true; + ThisTokBuf++; + } else if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { if (Diags) Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, diag::err_hex_escape_no_digits) << StringRef(&ThisTokBuf[-1], 1); return false; } UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8); - unsigned short UcnLenSave = UcnLen; - for (; ThisTokBuf != ThisTokEnd && UcnLenSave; ++ThisTokBuf, UcnLenSave--) { - int CharVal = llvm::hexDigitValue(ThisTokBuf[0]); - if (CharVal == -1) break; + + bool Overflow = false; + unsigned short Count = 0; + for (; ThisTokBuf != ThisTokEnd && (Delimited || Count != UcnLen); + ++ThisTokBuf) { + if (Delimited && *ThisTokBuf == '}') { + ++ThisTokBuf; + EndDelimiterFound = true; + break; + } + int CharVal = llvm::hexDigitValue(*ThisTokBuf); + if (CharVal == -1) { + HasError = true; + if (!Delimited) + break; + if (Diags) { + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::err_delimited_escape_invalid) + << StringRef(ThisTokBuf, 1); + } + Count++; + continue; + } + if (UcnVal & 0xF0000000) { + Overflow = true; + continue; + } UcnVal <<= 4; UcnVal |= CharVal; + Count++; } - // If we didn't consume the proper number of digits, there is a problem. - if (UcnLenSave) { + + if (Overflow) { if (Diags) Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, - diag::err_ucn_escape_incomplete); + diag::err_escape_too_large) + << 0; return false; } + if (Delimited && !EndDelimiterFound) { + if (Diags) { + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::err_expected) + << tok::r_brace; + } + return false; + } + + // If we didn't consume the proper number of digits, there is a problem. + if (Count == 0 || (!Delimited && Count != UcnLen)) { + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + Delimited ? diag::err_delimited_escape_empty + : diag::err_ucn_escape_incomplete); + return false; + } + + if (HasError) + return false; + // Check UCN constraints (C99 6.4.3p2) [C++11 lex.charset p2] if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints UcnVal > 0x10FFFF) { // maximum legal UTF32 value @@ -338,6 +495,10 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, diag::warn_ucn_not_valid_in_c89_literal); + if (Delimited && Diags) + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::ext_delimited_escape_sequence); + return true; } @@ -532,12 +693,6 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, : SM(SM), LangOpts(LangOpts), Diags(Diags), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) { - // This routine assumes that the range begin/end matches the regex for integer - // and FP constants (specifically, the 'pp-number' regex), and assumes that - // the byte at "*end" is both valid and not part of the regex. Because of - // this, it doesn't have to check for 'overscan' in various places. - assert(!isPreprocessingNumberBody(*ThisTokEnd) && "didn't maximally munch?"); - s = DigitsBegin = ThisTokBegin; saw_exponent = false; saw_period = false; @@ -557,6 +712,16 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isAccum = false; hadError = false; + // This routine assumes that the range begin/end matches the regex for integer + // and FP constants (specifically, the 'pp-number' regex), and assumes that + // the byte at "*end" is both valid and not part of the regex. Because of + // this, it doesn't have to check for 'overscan' in various places. + if (isPreprocessingNumberBody(*ThisTokEnd)) { + Diags.Report(TokLoc, diag::err_lexing_numeric); + hadError = true; + return; + } + if (*s == '0') { // parse radix ParseNumberStartingWithZero(TokLoc); if (hadError) @@ -1081,7 +1246,7 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { llvm::SmallString<16> Buffer; StringRef Str(ThisTokBegin, n); - if (Str.find('\'') != StringRef::npos) { + if (Str.contains('\'')) { Buffer.reserve(n); std::remove_copy_if(Str.begin(), Str.end(), std::back_inserter(Buffer), &isDigitSeparator); @@ -1196,7 +1361,7 @@ bool NumericLiteralParser::GetFixedPointValue(llvm::APInt &StoreVal, unsigned Sc Val *= Base; } } else if (BaseShift < 0) { - for (int64_t i = BaseShift; i < 0 && !Val.isNullValue(); ++i) + for (int64_t i = BaseShift; i < 0 && !Val.isZero(); ++i) Val = Val.udiv(Base); } @@ -1271,7 +1436,12 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, ++begin; // Skip over the entry quote. - assert(begin[0] == '\'' && "Invalid token lexed"); + if (begin[0] != '\'') { + PP.Diag(Loc, diag::err_lexing_char); + HadError = true; + return; + } + ++begin; // Remove an optional ud-suffix. @@ -1390,14 +1560,14 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, unsigned NumCharsSoFar = buffer_begin - &codepoint_buffer.front(); if (NumCharsSoFar > 1) { - if (isWide()) - PP.Diag(Loc, diag::warn_extraneous_char_constant); - else if (isAscii() && NumCharsSoFar == 4) + if (isAscii() && NumCharsSoFar == 4) PP.Diag(Loc, diag::warn_four_char_character_literal); else if (isAscii()) PP.Diag(Loc, diag::warn_multichar_character_literal); - else - PP.Diag(Loc, diag::err_multichar_utf_character_literal); + else { + PP.Diag(Loc, diag::err_multichar_character_literal) << (isWide() ? 0 : 1); + HadError = true; + } IsMultiChar = true; } else { IsMultiChar = false; @@ -1493,9 +1663,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, /// StringLiteralParser:: StringLiteralParser(ArrayRef StringToks, - Preprocessor &PP, bool Complain) + Preprocessor &PP) : SM(PP.getSourceManager()), Features(PP.getLangOpts()), - Target(PP.getTargetInfo()), Diags(Complain ? &PP.getDiagnostics() :nullptr), + Target(PP.getTargetInfo()), Diags(&PP.getDiagnostics()), MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown), ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) { init(StringToks); diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index f9af7c2a24f..9fa170410da 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -167,8 +167,8 @@ static void appendSubframeworkPaths(Module *Mod, return; // Add Frameworks/Name.framework for each subframework. - for (unsigned I = Paths.size() - 1; I != 0; --I) - llvm::sys::path::append(Path, "Frameworks", Paths[I-1] + ".framework"); + for (StringRef Framework : llvm::drop_begin(llvm::reverse(Paths))) + llvm::sys::path::append(Path, "Frameworks", Framework + ".framework"); } Optional ModuleMap::findHeader( @@ -338,7 +338,7 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name, if (Name.empty()) return Name; - if (!isValidIdentifier(Name)) { + if (!isValidAsciiIdentifier(Name)) { // If we don't already have something with the form of an identifier, // create a buffer with the sanitized name. Buffer.clear(); @@ -346,7 +346,7 @@ static StringRef sanitizeFilenameAsIdentifier(StringRef Name, Buffer.push_back('_'); Buffer.reserve(Buffer.size() + Name.size()); for (unsigned I = 0, N = Name.size(); I != N; ++I) { - if (isIdentifierBody(Name[I])) + if (isAsciiIdentifierContinue(Name[I])) Buffer.push_back(Name[I]); else Buffer.push_back('_'); @@ -618,18 +618,18 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(const FileEntry *File) { // the actual header is located. bool Explicit = UmbrellaModule->InferExplicitSubmodules; - for (unsigned I = SkippedDirs.size(); I != 0; --I) { + for (const DirectoryEntry *SkippedDir : llvm::reverse(SkippedDirs)) { // Find or create the module that corresponds to this directory name. SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( - llvm::sys::path::stem(SkippedDirs[I-1]->getName()), NameBuf); + llvm::sys::path::stem(SkippedDir->getName()), NameBuf); Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit).first; InferredModuleAllowedBy[Result] = UmbrellaModuleMap; Result->IsInferred = true; // Associate the module and the directory. - UmbrellaDirs[SkippedDirs[I-1]] = Result; + UmbrellaDirs[SkippedDir] = Result; // If inferred submodules export everything they import, add a // wildcard to the set of exports. @@ -745,12 +745,11 @@ ModuleMap::isHeaderUnavailableInModule(const FileEntry *Header, UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - for (unsigned I = SkippedDirs.size(); I != 0; --I) { + for (const DirectoryEntry *SkippedDir : llvm::reverse(SkippedDirs)) { // Find or create the module that corresponds to this directory name. SmallString<32> NameBuf; StringRef Name = sanitizeFilenameAsIdentifier( - llvm::sys::path::stem(SkippedDirs[I-1]->getName()), - NameBuf); + llvm::sys::path::stem(SkippedDir->getName()), NameBuf); Found = lookupModuleQualified(Name, Found); if (!Found) return false; @@ -989,9 +988,8 @@ Module *ModuleMap::inferFrameworkModule(const DirectoryEntry *FrameworkDir, // We're allowed to infer for this directory, but make sure it's okay // to infer this particular module. StringRef Name = llvm::sys::path::stem(FrameworkDirName); - canInfer = std::find(inferred->second.ExcludedModules.begin(), - inferred->second.ExcludedModules.end(), - Name) == inferred->second.ExcludedModules.end(); + canInfer = + !llvm::is_contained(inferred->second.ExcludedModules, Name); Attrs.IsSystem |= inferred->second.Attrs.IsSystem; Attrs.IsExternC |= inferred->second.Attrs.IsExternC; @@ -1218,9 +1216,8 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header, // FIXME: Should we diagnose if a header is listed twice in the // same module definition? auto &HeaderList = Headers[Header.Entry]; - for (auto H : HeaderList) - if (H == KH) - return; + if (llvm::is_contained(HeaderList, KH)) + return; HeaderList.push_back(KH); Mod->Headers[headerRoleToKind(Role)].push_back(Header); @@ -2174,7 +2171,7 @@ void ModuleMapParser::parseExternModuleDecl() { } if (auto File = SourceMgr.getFileManager().getFile(FileNameRef)) Map.parseModuleMapFile( - *File, /*IsSystem=*/false, + *File, IsSystem, Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd ? Directory : (*File)->getDir(), diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 556dd8daf65..ef7a5351953 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -112,7 +112,7 @@ enum PPElifDiag { // the specified module, meaning clang won't build the specified module. This is // useful in a number of situations, for instance, when building a library that // vends a module map, one might want to avoid hitting intermediate build -// products containing the the module map or avoid finding the system installed +// products containimg the module map or avoid finding the system installed // modulemap for that library. static bool isForModuleBuilding(Module *M, StringRef CurrentModule, StringRef ModuleName) { @@ -129,7 +129,7 @@ static bool isForModuleBuilding(Module *M, StringRef CurrentModule, static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) { const LangOptions &Lang = PP.getLangOpts(); - if (II->isReserved(Lang) != ReservedIdentifierStatus::NotReserved) { + if (isReservedInAllContexts(II->isReserved(Lang))) { // list from: // - https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_macros.html // - https://docs.microsoft.com/en-us/cpp/c-runtime-library/security-features-in-the-crt?view=msvc-160 @@ -183,7 +183,7 @@ static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) { static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) { const LangOptions &Lang = PP.getLangOpts(); // Do not warn on keyword undef. It is generally harmless and widely used. - if (II->isReserved(Lang) != ReservedIdentifierStatus::NotReserved) + if (isReservedInAllContexts(II->isReserved(Lang))) return MD_ReservedMacro; return MD_NoWarn; } @@ -617,6 +617,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, // If this is in a skipping block or if we're already handled this #if // block, don't bother parsing the condition. if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) { + // FIXME: We should probably do at least some minimal parsing of the + // condition to verify that it is well-formed. The current state + // allows #elif* directives with completely malformed (or missing) + // conditions. DiscardUntilEndOfDirective(); } else { // Restore the value of LexingRawMode so that identifiers are @@ -656,6 +660,10 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, // If this is in a skipping block or if we're already handled this #if // block, don't bother parsing the condition. if (CondInfo.WasSkipping || CondInfo.FoundNonSkip) { + // FIXME: We should probably do at least some minimal parsing of the + // condition to verify that it is well-formed. The current state + // allows #elif* directives with completely malformed (or missing) + // conditions. DiscardUntilEndOfDirective(); } else { // Restore the value of LexingRawMode so that identifiers are @@ -674,6 +682,8 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, continue; } + emitMacroExpansionWarnings(MacroNameTok); + CheckEndOfDirective(IsElifDef ? "elifdef" : "elifndef"); IdentifierInfo *MII = MacroNameTok.getIdentifierInfo(); @@ -735,7 +745,7 @@ Module *Preprocessor::getModuleForLocation(SourceLocation Loc) { // to the current module, if there is one. return getLangOpts().CurrentModule.empty() ? nullptr - : HeaderInfo.lookupModule(getLangOpts().CurrentModule); + : HeaderInfo.lookupModule(getLangOpts().CurrentModule, Loc); } const FileEntry * @@ -1441,11 +1451,15 @@ void Preprocessor::HandleDigitDirective(Token &DigitTok) { DiscardUntilEndOfDirective(); return; } - FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString()); // If a filename was present, read any flags that are present. if (ReadLineMarkerFlags(IsFileEntry, IsFileExit, FileKind, *this)) return; + + // Exiting to an empty string means pop to the including file, so leave + // FilenameID as -1 in that case. + if (!(IsFileExit && Literal.GetString().empty())) + FilenameID = SourceMgr.getLineTableFilenameID(Literal.GetString()); } // Create a line note with this information. @@ -2002,26 +2016,26 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( SourceLocation FilenameLoc = FilenameTok.getLocation(); StringRef LookupFilename = Filename; -#ifdef _WIN32 - llvm::sys::path::Style BackslashStyle = llvm::sys::path::Style::windows; -#else // Normalize slashes when compiling with -fms-extensions on non-Windows. This // is unnecessary on Windows since the filesystem there handles backslashes. SmallString<128> NormalizedPath; - llvm::sys::path::Style BackslashStyle = llvm::sys::path::Style::posix; - if (LangOpts.MicrosoftExt) { + llvm::sys::path::Style BackslashStyle = llvm::sys::path::Style::native; + if (is_style_posix(BackslashStyle) && LangOpts.MicrosoftExt) { NormalizedPath = Filename.str(); llvm::sys::path::native(NormalizedPath); LookupFilename = NormalizedPath; BackslashStyle = llvm::sys::path::Style::windows; } -#endif Optional File = LookupHeaderIncludeOrImport( CurDir, Filename, FilenameLoc, FilenameRange, FilenameTok, IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile, LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled); + // Record the header's filename for later use. + if (File) + CurLexer->addInclude(OriginalFilename, File->getFileEntry(), FilenameLoc); + if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) { if (File && isPCHThroughHeader(&File->getFileEntry())) SkippingUntilPCHThroughHeader = false; @@ -2129,12 +2143,14 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( IsImportDecl || IncludeTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_import; + bool IsFirstIncludeOfFile = false; + // Ask HeaderInfo if we should enter this #include file. If not, #including // this file will have no effect. if (Action == Enter && File && - !HeaderInfo.ShouldEnterIncludeFile(*this, &File->getFileEntry(), - EnterOnce, getLangOpts().Modules, - SuggestedModule.getModule())) { + !HeaderInfo.ShouldEnterIncludeFile( + *this, &File->getFileEntry(), EnterOnce, getLangOpts().Modules, + SuggestedModule.getModule(), IsFirstIncludeOfFile)) { // Even if we've already preprocessed this header once and know that we // don't need to see its contents again, we still need to import it if it's // modular because we might not have imported it from this submodule before. @@ -2326,7 +2342,8 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( } // If all is good, enter the new file! - if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation())) + if (EnterSourceFile(FID, CurDir, FilenameTok.getLocation(), + IsFirstIncludeOfFile)) return {ImportAction::None}; // Determine if we're switching to building a new submodule, and which one. @@ -2521,7 +2538,7 @@ bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { // If this is already used as a parameter, it is used multiple times (e.g. // #define X(A,A. - if (llvm::find(Parameters, II) != Parameters.end()) { // C99 6.10.3p6 + if (llvm::is_contained(Parameters, II)) { // C99 6.10.3p6 Diag(Tok, diag::err_pp_duplicate_name_in_arg_list) << II; return true; } @@ -2851,6 +2868,12 @@ void Preprocessor::HandleDefineDirective( if (MacroNameTok.is(tok::eod)) return; + IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); + // Issue a final pragma warning if we're defining a macro that was has been + // undefined and is being redefined. + if (!II->hasMacroDefinition() && II->hadMacroDefinition() && II->isFinal()) + emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/false); + // If we are supposed to keep comments in #defines, reenable comment saving // mode. if (CurLexer) CurLexer->SetCommentRetentionState(KeepMacroComments); @@ -2893,6 +2916,12 @@ void Preprocessor::HandleDefineDirective( // Finally, if this identifier already had a macro defined for it, verify that // the macro bodies are identical, and issue diagnostics if they are not. if (const MacroInfo *OtherMI=getMacroInfo(MacroNameTok.getIdentifierInfo())) { + // Final macros are hard-mode: they always warn. Even if the bodies are + // identical. Even if they are in system headers. Even if they are things we + // would silently allow in the past. + if (MacroNameTok.getIdentifierInfo()->isFinal()) + emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/false); + // In Objective-C, ignore attempts to directly redefine the builtin // definitions of the ownership qualifiers. It's still possible to // #undef them. @@ -2922,6 +2951,7 @@ void Preprocessor::HandleDefineDirective( // then don't bother calling MacroInfo::isIdenticalTo. if (!getDiagnostics().getSuppressSystemWarnings() || !SourceMgr.isInSystemHeader(DefineTok.getLocation())) { + if (!OtherMI->isUsed() && OtherMI->isWarnIfUnused()) Diag(OtherMI->getDefinitionLoc(), diag::pp_macro_not_used); @@ -2999,6 +3029,9 @@ void Preprocessor::HandleUndefDirective() { auto MD = getMacroDefinition(II); UndefMacroDirective *Undef = nullptr; + if (II->isFinal()) + emitFinalMacroWarning(MacroNameTok, /*IsUndef=*/true); + // If the macro is not defined, this is a noop undef. if (const MacroInfo *MI = MD.getMacroInfo()) { if (!MI->isUsed() && MI->isWarnIfUnused()) @@ -3048,6 +3081,8 @@ void Preprocessor::HandleIfdefDirective(Token &Result, return; } + emitMacroExpansionWarnings(MacroNameTok); + // Check to see if this is the last token on the #if[n]def line. CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef"); diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp index cab4bab630d..424cccfdb9e 100644 --- a/clang/lib/Lex/PPExpressions.cpp +++ b/clang/lib/Lex/PPExpressions.cpp @@ -133,6 +133,8 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT, Result.Val.setIsUnsigned(false); // Result is signed intmax_t. DT.IncludedUndefinedIds = !Macro; + PP.emitMacroExpansionWarnings(PeekTok); + // If there is a macro, mark it used. if (Result.Val != 0 && ValueLive) PP.markMacroAsUsed(Macro.getMacroInfo()); @@ -660,7 +662,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, case tok::ampamp: // Logical && does not do UACs. break; // No UAC default: - Res.setIsUnsigned(LHS.isUnsigned()|RHS.isUnsigned()); + Res.setIsUnsigned(LHS.isUnsigned() || RHS.isUnsigned()); // If this just promoted something from signed to unsigned, and if the // value was negative, warn about it. if (ValueLive && Res.isUnsigned()) { @@ -820,7 +822,7 @@ static bool EvaluateDirectiveSubExpr(PPValue &LHS, unsigned MinPrec, // Usual arithmetic conversions (C99 6.3.1.8p1): result is unsigned if // either operand is unsigned. - Res.setIsUnsigned(RHS.isUnsigned() | AfterColonVal.isUnsigned()); + Res.setIsUnsigned(RHS.isUnsigned() || AfterColonVal.isUnsigned()); // Figure out the precedence of the token after the : part. PeekPrec = getPrecedence(PeekTok.getKind()); diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index b979b965f46..f8b0a2c5f71 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" @@ -22,6 +23,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" + using namespace clang; //===----------------------------------------------------------------------===// @@ -37,8 +39,8 @@ bool Preprocessor::isInPrimaryFile() const { // If there are any stacked lexers, we're in a #include. assert(IsFileLexer(IncludeMacroStack[0]) && "Top level include stack isn't our primary lexer?"); - return std::none_of( - IncludeMacroStack.begin() + 1, IncludeMacroStack.end(), + return llvm::none_of( + llvm::drop_begin(IncludeMacroStack), [&](const IncludeStackInfo &ISI) -> bool { return IsFileLexer(ISI); }); } @@ -65,7 +67,8 @@ PreprocessorLexer *Preprocessor::getCurrentFileLexer() const { /// EnterSourceFile - Add a source file to the top of the include stack and /// start lexing tokens from it instead of the current buffer. bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, - SourceLocation Loc) { + SourceLocation Loc, + bool IsFirstIncludeOfFile) { assert(!CurTokenLexer && "Cannot #include a file inside a macro!"); ++NumEnteredSourceFiles; @@ -89,7 +92,8 @@ bool Preprocessor::EnterSourceFile(FileID FID, const DirectoryLookup *CurDir, CodeCompletionFileLoc.getLocWithOffset(CodeCompletionOffset); } - EnterSourceFileWithLexer(new Lexer(FID, *InputFile, *this), CurDir); + EnterSourceFileWithLexer( + new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile), CurDir); return false; } @@ -299,10 +303,46 @@ void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) { } } +void Preprocessor::ResolvePragmaIncludeInstead( + const SourceLocation Location) const { + assert(Location.isValid()); + if (CurLexer == nullptr) + return; + + if (SourceMgr.isInSystemHeader(Location)) + return; + + for (const auto &Include : CurLexer->getIncludeHistory()) { + StringRef Filename = Include.getKey(); + const PreprocessorLexer::IncludeInfo &Info = Include.getValue(); + ArrayRef> Aliases = + HeaderInfo.getFileInfo(Info.File).Aliases.getArrayRef(); + + if (Aliases.empty()) + continue; + + switch (Aliases.size()) { + case 1: + Diag(Info.Location, diag::err_pragma_include_instead_system_reserved) + << Filename << 0 << Aliases[0]; + continue; + case 2: + Diag(Info.Location, diag::err_pragma_include_instead_system_reserved) + << Filename << 1 << Aliases[0] << Aliases[1]; + continue; + default: { + Diag(Info.Location, diag::err_pragma_include_instead_system_reserved) + << Filename << 2 << ("{'" + llvm::join(Aliases, "', '") + "'}"); + } + } + } +} + /// HandleEndOfFile - This callback is invoked when the lexer hits the end of /// the current file. This either returns the EOF token or pops a level off /// the include stack and keeps going. -bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { +bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc, + bool isEndOfMacro) { assert(!CurTokenLexer && "Ending a file when currently in a macro!"); @@ -339,7 +379,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { CurPPLexer->MIOpt.GetDefinedMacro()) { if (!isMacroDefined(ControllingMacro) && DefinedMacro != ControllingMacro && - HeaderInfo.FirstTimeLexingFile(FE)) { + CurLexer->isFirstTimeLexingFile()) { // If the edit distance between the two macros is more than 50%, // DefinedMacro may not be header guard, or can be header guard of @@ -372,6 +412,9 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { } } + if (EndLoc.isValid()) + ResolvePragmaIncludeInstead(EndLoc); + // Complain about reaching a true EOF within arc_cf_code_audited. // We don't want to complain about reaching the end of a macro // instantiation or a _Pragma. @@ -560,7 +603,7 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) { TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer); // Handle this like a #include file being popped off the stack. - return HandleEndOfFile(Result, true); + return HandleEndOfFile(Result, {}, true); } /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 8728ac9e216..cfee7a3c251 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -155,11 +155,8 @@ ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, // If we were the first overrider for any macro, it's no longer a leaf. auto &LeafMacros = LeafModuleMacros[II]; if (HidAny) { - LeafMacros.erase(std::remove_if(LeafMacros.begin(), LeafMacros.end(), - [](ModuleMacro *MM) { - return MM->NumOverriddenBy != 0; - }), - LeafMacros.end()); + llvm::erase_if(LeafMacros, + [](ModuleMacro *MM) { return MM->NumOverriddenBy != 0; }); } // The new macro is always a leaf macro. @@ -426,7 +423,7 @@ static bool isTrivialSingleTokenExpansion(const MacroInfo *MI, // If this is a function-like macro invocation, it's safe to trivially expand // as long as the identifier is not a macro argument. - return std::find(MI->param_begin(), MI->param_end(), II) == MI->param_end(); + return !llvm::is_contained(MI->params(), II); } /// isNextPPTokenLParen - Determine whether the next preprocessor token to be @@ -471,6 +468,8 @@ bool Preprocessor::isNextPPTokenLParen() { /// expanded as a macro, handle it and return the next token as 'Identifier'. bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, const MacroDefinition &M) { + emitMacroExpansionWarnings(Identifier); + MacroInfo *MI = M.getMacroInfo(); // If this is a macro expansion in the "#if !defined(x)" line for the file, @@ -986,7 +985,11 @@ MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName, // If the macro contains the comma pasting extension, the diagnostic // is suppressed; we know we'll get another diagnostic later. if (!MI->hasCommaPasting()) { - Diag(Tok, diag::ext_missing_varargs_arg); + // C++20 allows this construct, but standards before C++20 and all C + // standards do not allow the construct (we allow it as an extension). + Diag(Tok, getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_missing_varargs_arg + : diag::ext_missing_varargs_arg); Diag(MI->getDefinitionLoc(), diag::note_macro_here) << MacroName.getIdentifierInfo(); } @@ -1287,7 +1290,7 @@ static bool EvaluateHasIncludeNext(Token &Tok, /// integer values. static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS, Token &Tok, IdentifierInfo *II, - Preprocessor &PP, + Preprocessor &PP, bool ExpandArgs, llvm::function_ref< int(Token &Tok, bool &HasLexedNextTok)> Op) { @@ -1313,7 +1316,10 @@ static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS, bool SuppressDiagnostic = false; while (true) { // Parse next token. - PP.LexUnexpandedToken(Tok); + if (ExpandArgs) + PP.Lex(Tok); + else + PP.LexUnexpandedToken(Tok); already_lexed: switch (Tok.getKind()) { @@ -1453,15 +1459,6 @@ static bool isTargetEnvironment(const TargetInfo &TI, return TI.getTriple().getEnvironment() == Env.getEnvironment(); } -static void remapMacroPath( - SmallString<256> &Path, - const std::map> - &MacroPrefixMap) { - for (const auto &Entry : MacroPrefixMap) - if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) - break; -} - /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1543,7 +1540,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } else { FN += PLoc.getFilename(); } - remapMacroPath(FN, PPOpts->MacroPrefixMap); + getLangOpts().remapPathPrefix(FN); Lexer::Stringify(FN); OS << '"' << FN << '"'; } @@ -1612,21 +1609,21 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); return II && HasFeature(*this, II->getName()); }); } else if (II == Ident__has_extension) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); return II && HasExtension(*this, II->getName()); }); } else if (II == Ident__has_builtin) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); @@ -1678,12 +1675,12 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } }); } else if (II == Ident__is_identifier) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [](Token &Tok, bool &HasLexedNextToken) -> int { return Tok.is(tok::identifier); }); } else if (II == Ident__has_attribute) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); @@ -1691,7 +1688,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { getTargetInfo(), getLangOpts()) : 0; }); } else if (II == Ident__has_declspec) { - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); @@ -1707,8 +1704,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } else if (II == Ident__has_cpp_attribute || II == Ident__has_c_attribute) { bool IsCXX = II == Ident__has_cpp_attribute; - EvaluateFeatureLikeBuiltinMacro( - OS, Tok, II, *this, [&](Token &Tok, bool &HasLexedNextToken) -> int { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, + [&](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *ScopeII = nullptr; IdentifierInfo *II = ExpectFeatureIdentifierInfo( Tok, *this, diag::err_feature_check_malformed); @@ -1722,7 +1719,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { HasLexedNextToken = true; else { ScopeII = II; - LexUnexpandedToken(Tok); + // Lex an expanded token for the attribute name. + Lex(Tok); II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_feature_check_malformed); } @@ -1749,7 +1747,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_warning) { // The argument should be a parenthesized string literal. - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [this](Token &Tok, bool &HasLexedNextToken) -> int { std::string WarningName; SourceLocation StrStartLoc = Tok.getLocation(); @@ -1780,7 +1778,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // The argument to this builtin should be an identifier. The // builtin evaluates to 1 when that identifier names the module we are // currently building. - EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, diag::err_expected_id_building_module); @@ -1840,28 +1838,32 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { return; } else if (II == Ident__is_target_arch) { EvaluateFeatureLikeBuiltinMacro( - OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo( Tok, *this, diag::err_feature_check_malformed); return II && isTargetArch(getTargetInfo(), II); }); } else if (II == Ident__is_target_vendor) { EvaluateFeatureLikeBuiltinMacro( - OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo( Tok, *this, diag::err_feature_check_malformed); return II && isTargetVendor(getTargetInfo(), II); }); } else if (II == Ident__is_target_os) { EvaluateFeatureLikeBuiltinMacro( - OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo( Tok, *this, diag::err_feature_check_malformed); return II && isTargetOS(getTargetInfo(), II); }); } else if (II == Ident__is_target_environment) { EvaluateFeatureLikeBuiltinMacro( - OS, Tok, II, *this, [this](Token &Tok, bool &HasLexedNextToken) -> int { + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { IdentifierInfo *II = ExpectFeatureIdentifierInfo( Tok, *this, diag::err_feature_check_malformed); return II && isTargetEnvironment(getTargetInfo(), II); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index c89061ba6d0..67daa584198 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Pragma.h" +#include "clang/Basic/CLWarnings.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticLex.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" @@ -35,11 +37,12 @@ #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Timer.h" @@ -495,43 +498,88 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { SrcMgr::C_System); } -/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. -void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { +static llvm::Optional LexHeader(Preprocessor &PP, + Optional &File, + bool SuppressIncludeNotFoundError) { Token FilenameTok; - if (LexHeaderName(FilenameTok, /*AllowConcatenation*/false)) - return; + if (PP.LexHeaderName(FilenameTok, /*AllowConcatenation*/ false)) + return llvm::None; // If the next token wasn't a header-name, diagnose the error. if (FilenameTok.isNot(tok::header_name)) { - Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); - return; + PP.Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); + return llvm::None; } // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; bool Invalid = false; - StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid); + StringRef Filename = PP.getSpelling(FilenameTok, FilenameBuffer, &Invalid); if (Invalid) - return; + return llvm::None; bool isAngled = - GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); + PP.GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); // If GetIncludeFilenameSpelling set the start ptr to null, there was an // error. if (Filename.empty()) - return; + return llvm::None; // Search include directories for this file. const DirectoryLookup *CurDir; - Optional File = - LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, - nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr); + File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr, + nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, + nullptr); if (!File) { if (!SuppressIncludeNotFoundError) - Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; + PP.Diag(FilenameTok, diag::err_pp_file_not_found) << Filename; + return llvm::None; + } + + return FilenameTok; +} + +/// HandlePragmaIncludeInstead - Handle \#pragma clang include_instead(header). +void Preprocessor::HandlePragmaIncludeInstead(Token &Tok) { + // Get the current file lexer we're looking at. Ignore _Pragma 'files' etc. + PreprocessorLexer *TheLexer = getCurrentFileLexer(); + + if (!SourceMgr.isInSystemHeader(Tok.getLocation())) { + Diag(Tok, diag::err_pragma_include_instead_not_sysheader); return; } + Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + Diag(Tok, diag::err_expected) << "("; + return; + } + + Optional File; + llvm::Optional FilenameTok = + LexHeader(*this, File, SuppressIncludeNotFoundError); + if (!FilenameTok) + return; + + Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + Diag(Tok, diag::err_expected) << ")"; + return; + } + + SmallString<128> FilenameBuffer; + StringRef Filename = getSpelling(*FilenameTok, FilenameBuffer); + HeaderInfo.AddFileAlias(TheLexer->getFileEntry(), Filename); +} + +/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. +void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { + Optional File; + llvm::Optional FilenameTok = + LexHeader(*this, File, SuppressIncludeNotFoundError); + if (!FilenameTok) + return; + const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry(); // If this file is older than the file it depends on, emit a diagnostic. @@ -547,7 +595,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { // Remove the trailing ' ' if present. if (!Message.empty()) Message.erase(Message.end()-1); - Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message; + Diag(*FilenameTok, diag::pp_out_of_date_dependency) << Message; } } @@ -1022,6 +1070,18 @@ struct PragmaSystemHeaderHandler : public PragmaHandler { } }; +/// PragmaIncludeInsteadHandler - "\#pragma clang include_instead(header)" marks +/// the current file as non-includable if the including header is not a system +/// header. +struct PragmaIncludeInsteadHandler : public PragmaHandler { + PragmaIncludeInsteadHandler() : PragmaHandler("include_instead") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &IIToken) override { + PP.HandlePragmaIncludeInstead(IIToken); + } +}; + struct PragmaDependencyHandler : public PragmaHandler { PragmaDependencyHandler() : PragmaHandler("dependency") {} @@ -1354,12 +1414,15 @@ struct PragmaWarningHandler : public PragmaHandler { return; } } + PP.getDiagnostics().pushMappings(DiagLoc); if (Callbacks) Callbacks->PragmaWarningPush(DiagLoc, Level); } else if (II && II->isStr("pop")) { // #pragma warning( pop ) PP.Lex(Tok); - if (Callbacks) + if (!PP.getDiagnostics().popMappings(DiagLoc)) + PP.Diag(Tok, diag::warn_pragma_diagnostic_cannot_pop); + else if (Callbacks) Callbacks->PragmaWarningPop(DiagLoc); } else { // #pragma warning( warning-specifier : warning-number-list @@ -1373,14 +1436,19 @@ struct PragmaWarningHandler : public PragmaHandler { // Figure out which warning specifier this is. bool SpecifierValid; - StringRef Specifier; - llvm::SmallString<1> SpecifierBuf; + PPCallbacks::PragmaWarningSpecifier Specifier; if (II) { - Specifier = II->getName(); - SpecifierValid = llvm::StringSwitch(Specifier) - .Cases("default", "disable", "error", "once", - "suppress", true) - .Default(false); + int SpecifierInt = llvm::StringSwitch(II->getName()) + .Case("default", PPCallbacks::PWS_Default) + .Case("disable", PPCallbacks::PWS_Disable) + .Case("error", PPCallbacks::PWS_Error) + .Case("once", PPCallbacks::PWS_Once) + .Case("suppress", PPCallbacks::PWS_Suppress) + .Default(-1); + if ((SpecifierValid = SpecifierInt != -1)) + Specifier = + static_cast(SpecifierInt); + // If we read a correct specifier, snatch next token (that should be // ":", checked later). if (SpecifierValid) @@ -1388,9 +1456,10 @@ struct PragmaWarningHandler : public PragmaHandler { } else { // Token is a numeric constant. It should be either 1, 2, 3 or 4. uint64_t Value; - Specifier = PP.getSpelling(Tok, SpecifierBuf); if (PP.parseSimpleIntegerLiteral(Tok, Value)) { - SpecifierValid = (Value >= 1) && (Value <= 4); + if ((SpecifierValid = (Value >= 1) && (Value <= 4))) + Specifier = static_cast( + PPCallbacks::PWS_Level1 + Value - 1); } else SpecifierValid = false; // Next token already snatched by parseSimpleIntegerLiteral. @@ -1417,6 +1486,22 @@ struct PragmaWarningHandler : public PragmaHandler { } Ids.push_back(int(Value)); } + + // Only act on disable for now. + diag::Severity SV = diag::Severity(); + if (Specifier == PPCallbacks::PWS_Disable) + SV = diag::Severity::Ignored; + if (SV != diag::Severity()) + for (int Id : Ids) { + if (auto Group = diagGroupFromCLWarningID(Id)) { + bool unknownDiag = PP.getDiagnostics().setSeverityForGroup( + diag::Flavor::WarningOrError, *Group, SV, DiagLoc); + assert(!unknownDiag && + "wd table should only contain known diags"); + (void)unknownDiag; + } + } + if (Callbacks) Callbacks->PragmaWarning(DiagLoc, Specifier, Ids); @@ -1667,7 +1752,7 @@ struct PragmaModuleBeginHandler : public PragmaHandler { // Find the module we're entering. We require that a module map for it // be loaded or implicitly loadable. auto &HSI = PP.getHeaderSearchInfo(); - Module *M = HSI.lookupModule(Current); + Module *M = HSI.lookupModule(Current, ModuleName.front().second); if (!M) { PP.Diag(ModuleName.front().second, diag::err_pp_module_begin_no_module_map) << Current; @@ -1911,6 +1996,130 @@ struct PragmaRegionHandler : public PragmaHandler { } }; +/// This handles parsing pragmas that take a macro name and optional message +static IdentifierInfo *HandleMacroAnnotationPragma(Preprocessor &PP, Token &Tok, + const char *Pragma, + std::string &MessageString) { + std::string Macro; + + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok, diag::err_expected) << "("; + return nullptr; + } + + PP.LexUnexpandedToken(Tok); + if (!Tok.is(tok::identifier)) { + PP.Diag(Tok, diag::err_expected) << tok::identifier; + return nullptr; + } + IdentifierInfo *II = Tok.getIdentifierInfo(); + + if (!II->hasMacroDefinition()) { + PP.Diag(Tok, diag::err_pp_visibility_non_macro) << II; + return nullptr; + } + + PP.Lex(Tok); + if (Tok.is(tok::comma)) { + PP.Lex(Tok); + if (!PP.FinishLexStringLiteral(Tok, MessageString, Pragma, + /*AllowMacroExpansion=*/true)) + return nullptr; + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok, diag::err_expected) << ")"; + return nullptr; + } + return II; +} + +/// "\#pragma clang deprecated(...)" +/// +/// The syntax is +/// \code +/// #pragma clang deprecate(MACRO_NAME [, Message]) +/// \endcode +struct PragmaDeprecatedHandler : public PragmaHandler { + PragmaDeprecatedHandler() : PragmaHandler("deprecated") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override { + std::string MessageString; + + if (IdentifierInfo *II = HandleMacroAnnotationPragma( + PP, Tok, "#pragma clang deprecated", MessageString)) { + II->setIsDeprecatedMacro(true); + PP.addMacroDeprecationMsg(II, std::move(MessageString), + Tok.getLocation()); + } + } +}; + +/// "\#pragma clang restrict_expansion(...)" +/// +/// The syntax is +/// \code +/// #pragma clang restrict_expansion(MACRO_NAME [, Message]) +/// \endcode +struct PragmaRestrictExpansionHandler : public PragmaHandler { + PragmaRestrictExpansionHandler() : PragmaHandler("restrict_expansion") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override { + std::string MessageString; + + if (IdentifierInfo *II = HandleMacroAnnotationPragma( + PP, Tok, "#pragma clang restrict_expansion", MessageString)) { + II->setIsRestrictExpansion(true); + PP.addRestrictExpansionMsg(II, std::move(MessageString), + Tok.getLocation()); + } + } +}; + +/// "\#pragma clang final(...)" +/// +/// The syntax is +/// \code +/// #pragma clang final(MACRO_NAME) +/// \endcode +struct PragmaFinalHandler : public PragmaHandler { + PragmaFinalHandler() : PragmaHandler("final") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &Tok) override { + std::string Macro; + + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok, diag::err_expected) << "("; + return; + } + + PP.LexUnexpandedToken(Tok); + if (!Tok.is(tok::identifier)) { + PP.Diag(Tok, diag::err_expected) << tok::identifier; + return; + } + IdentifierInfo *II = Tok.getIdentifierInfo(); + + if (!II->hasMacroDefinition()) { + PP.Diag(Tok, diag::err_pp_visibility_non_macro) << II; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok, diag::err_expected) << ")"; + return; + } + II->setIsFinal(true); + PP.addFinalLoc(II, Tok.getLocation()); + } +}; + } // namespace /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: @@ -1934,11 +2143,15 @@ void Preprocessor::RegisterBuiltinPragmas() { // #pragma clang ... AddPragmaHandler("clang", new PragmaPoisonHandler()); AddPragmaHandler("clang", new PragmaSystemHeaderHandler()); + AddPragmaHandler("clang", new PragmaIncludeInsteadHandler()); AddPragmaHandler("clang", new PragmaDebugHandler()); AddPragmaHandler("clang", new PragmaDependencyHandler()); AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang")); AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler()); AddPragmaHandler("clang", new PragmaAssumeNonNullHandler()); + AddPragmaHandler("clang", new PragmaDeprecatedHandler()); + AddPragmaHandler("clang", new PragmaRestrictExpansionHandler()); + AddPragmaHandler("clang", new PragmaFinalHandler()); // #pragma clang module ... auto *ModuleHandler = new PragmaNamespace("module"); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 32ea8791d29..b026ae36fc0 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -723,11 +723,7 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const { // is cleaned to tok::identifier "B". After cleaning the token's length is // still 3 and the SourceLocation refers to the location of the backslash. Identifier.setIdentifierInfo(II); - if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() && - getSourceManager().isInSystemHeader(Identifier.getLocation())) - Identifier.setKind(tok::identifier); - else - Identifier.setKind(II->getTokenID()); + Identifier.setKind(II->getTokenID()); return II; } @@ -1387,7 +1383,7 @@ bool Preprocessor::parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value) { void Preprocessor::addCommentHandler(CommentHandler *Handler) { assert(Handler && "NULL comment handler"); - assert(llvm::find(CommentHandlers, Handler) == CommentHandlers.end() && + assert(!llvm::is_contained(CommentHandlers, Handler) && "Comment handler already registered"); CommentHandlers.push_back(Handler); } @@ -1413,6 +1409,48 @@ bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { return true; } +void Preprocessor::emitMacroDeprecationWarning(const Token &Identifier) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.DeprecationInfo && + "Macro deprecation warning without recorded annotation!"); + const MacroAnnotationInfo &Info = *A.DeprecationInfo; + if (Info.Message.empty()) + Diag(Identifier, diag::warn_pragma_deprecated_macro_use) + << Identifier.getIdentifierInfo() << 0; + else + Diag(Identifier, diag::warn_pragma_deprecated_macro_use) + << Identifier.getIdentifierInfo() << 1 << Info.Message; + Diag(Info.Location, diag::note_pp_macro_annotation) << 0; +} + +void Preprocessor::emitRestrictExpansionWarning(const Token &Identifier) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.RestrictExpansionInfo && + "Macro restricted expansion warning without recorded annotation!"); + const MacroAnnotationInfo &Info = *A.RestrictExpansionInfo; + if (Info.Message.empty()) + Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use) + << Identifier.getIdentifierInfo() << 0; + else + Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use) + << Identifier.getIdentifierInfo() << 1 << Info.Message; + Diag(Info.Location, diag::note_pp_macro_annotation) << 1; +} + +void Preprocessor::emitFinalMacroWarning(const Token &Identifier, + bool IsUndef) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.FinalAnnotationLoc && + "Final macro warning without recorded annotation!"); + + Diag(Identifier, diag::warn_pragma_final_macro) + << Identifier.getIdentifierInfo() << (IsUndef ? 0 : 1); + Diag(*A.FinalAnnotationLoc, diag::note_pp_macro_annotation) << 2; +} + ModuleLoader::~ModuleLoader() = default; CommentHandler::~CommentHandler() = default; diff --git a/clang/lib/Lex/UnicodeCharSets.h b/clang/lib/Lex/UnicodeCharSets.h index 74dd57fdf11..e79a85bc72b 100644 --- a/clang/lib/Lex/UnicodeCharSets.h +++ b/clang/lib/Lex/UnicodeCharSets.h @@ -10,6 +10,355 @@ #include "llvm/Support/UnicodeCharRanges.h" +// Unicode 14 XID_Start +static const llvm::sys::UnicodeCharRange XIDStartRanges[] = { + {0x0041, 0x005A}, {0x0061, 0x007A}, {0x00AA, 0x00AA}, + {0x00B5, 0x00B5}, {0x00BA, 0x00BA}, {0x00C0, 0x00D6}, + {0x00D8, 0x00F6}, {0x00F8, 0x02C1}, {0x02C6, 0x02D1}, + {0x02E0, 0x02E4}, {0x02EC, 0x02EC}, {0x02EE, 0x02EE}, + {0x0370, 0x0374}, {0x0376, 0x0377}, {0x037B, 0x037D}, + {0x037F, 0x037F}, {0x0386, 0x0386}, {0x0388, 0x038A}, + {0x038C, 0x038C}, {0x038E, 0x03A1}, {0x03A3, 0x03F5}, + {0x03F7, 0x0481}, {0x048A, 0x052F}, {0x0531, 0x0556}, + {0x0559, 0x0559}, {0x0560, 0x0588}, {0x05D0, 0x05EA}, + {0x05EF, 0x05F2}, {0x0620, 0x064A}, {0x066E, 0x066F}, + {0x0671, 0x06D3}, {0x06D5, 0x06D5}, {0x06E5, 0x06E6}, + {0x06EE, 0x06EF}, {0x06FA, 0x06FC}, {0x06FF, 0x06FF}, + {0x0710, 0x0710}, {0x0712, 0x072F}, {0x074D, 0x07A5}, + {0x07B1, 0x07B1}, {0x07CA, 0x07EA}, {0x07F4, 0x07F5}, + {0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x081A, 0x081A}, + {0x0824, 0x0824}, {0x0828, 0x0828}, {0x0840, 0x0858}, + {0x0860, 0x086A}, {0x0870, 0x0887}, {0x0889, 0x088E}, + {0x08A0, 0x08C9}, {0x0904, 0x0939}, {0x093D, 0x093D}, + {0x0950, 0x0950}, {0x0958, 0x0961}, {0x0971, 0x0980}, + {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, + {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, + {0x09BD, 0x09BD}, {0x09CE, 0x09CE}, {0x09DC, 0x09DD}, + {0x09DF, 0x09E1}, {0x09F0, 0x09F1}, {0x09FC, 0x09FC}, + {0x0A05, 0x0A0A}, {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, + {0x0A2A, 0x0A30}, {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, + {0x0A38, 0x0A39}, {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, + {0x0A72, 0x0A74}, {0x0A85, 0x0A8D}, {0x0A8F, 0x0A91}, + {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, {0x0AB2, 0x0AB3}, + {0x0AB5, 0x0AB9}, {0x0ABD, 0x0ABD}, {0x0AD0, 0x0AD0}, + {0x0AE0, 0x0AE1}, {0x0AF9, 0x0AF9}, {0x0B05, 0x0B0C}, + {0x0B0F, 0x0B10}, {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, + {0x0B32, 0x0B33}, {0x0B35, 0x0B39}, {0x0B3D, 0x0B3D}, + {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B71, 0x0B71}, + {0x0B83, 0x0B83}, {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, + {0x0B92, 0x0B95}, {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, + {0x0B9E, 0x0B9F}, {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, + {0x0BAE, 0x0BB9}, {0x0BD0, 0x0BD0}, {0x0C05, 0x0C0C}, + {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, {0x0C2A, 0x0C39}, + {0x0C3D, 0x0C3D}, {0x0C58, 0x0C5A}, {0x0C5D, 0x0C5D}, + {0x0C60, 0x0C61}, {0x0C80, 0x0C80}, {0x0C85, 0x0C8C}, + {0x0C8E, 0x0C90}, {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, + {0x0CB5, 0x0CB9}, {0x0CBD, 0x0CBD}, {0x0CDD, 0x0CDE}, + {0x0CE0, 0x0CE1}, {0x0CF1, 0x0CF2}, {0x0D04, 0x0D0C}, + {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D}, + {0x0D4E, 0x0D4E}, {0x0D54, 0x0D56}, {0x0D5F, 0x0D61}, + {0x0D7A, 0x0D7F}, {0x0D85, 0x0D96}, {0x0D9A, 0x0DB1}, + {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, {0x0DC0, 0x0DC6}, + {0x0E01, 0x0E30}, {0x0E32, 0x0E32}, {0x0E40, 0x0E46}, + {0x0E81, 0x0E82}, {0x0E84, 0x0E84}, {0x0E86, 0x0E8A}, + {0x0E8C, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EB0}, + {0x0EB2, 0x0EB2}, {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, + {0x0EC6, 0x0EC6}, {0x0EDC, 0x0EDF}, {0x0F00, 0x0F00}, + {0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F88, 0x0F8C}, + {0x1000, 0x102A}, {0x103F, 0x103F}, {0x1050, 0x1055}, + {0x105A, 0x105D}, {0x1061, 0x1061}, {0x1065, 0x1066}, + {0x106E, 0x1070}, {0x1075, 0x1081}, {0x108E, 0x108E}, + {0x10A0, 0x10C5}, {0x10C7, 0x10C7}, {0x10CD, 0x10CD}, + {0x10D0, 0x10FA}, {0x10FC, 0x1248}, {0x124A, 0x124D}, + {0x1250, 0x1256}, {0x1258, 0x1258}, {0x125A, 0x125D}, + {0x1260, 0x1288}, {0x128A, 0x128D}, {0x1290, 0x12B0}, + {0x12B2, 0x12B5}, {0x12B8, 0x12BE}, {0x12C0, 0x12C0}, + {0x12C2, 0x12C5}, {0x12C8, 0x12D6}, {0x12D8, 0x1310}, + {0x1312, 0x1315}, {0x1318, 0x135A}, {0x1380, 0x138F}, + {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1401, 0x166C}, + {0x166F, 0x167F}, {0x1681, 0x169A}, {0x16A0, 0x16EA}, + {0x16EE, 0x16F8}, {0x1700, 0x1711}, {0x171F, 0x1731}, + {0x1740, 0x1751}, {0x1760, 0x176C}, {0x176E, 0x1770}, + {0x1780, 0x17B3}, {0x17D7, 0x17D7}, {0x17DC, 0x17DC}, + {0x1820, 0x1878}, {0x1880, 0x18A8}, {0x18AA, 0x18AA}, + {0x18B0, 0x18F5}, {0x1900, 0x191E}, {0x1950, 0x196D}, + {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, + {0x1A00, 0x1A16}, {0x1A20, 0x1A54}, {0x1AA7, 0x1AA7}, + {0x1B05, 0x1B33}, {0x1B45, 0x1B4C}, {0x1B83, 0x1BA0}, + {0x1BAE, 0x1BAF}, {0x1BBA, 0x1BE5}, {0x1C00, 0x1C23}, + {0x1C4D, 0x1C4F}, {0x1C5A, 0x1C7D}, {0x1C80, 0x1C88}, + {0x1C90, 0x1CBA}, {0x1CBD, 0x1CBF}, {0x1CE9, 0x1CEC}, + {0x1CEE, 0x1CF3}, {0x1CF5, 0x1CF6}, {0x1CFA, 0x1CFA}, + {0x1D00, 0x1DBF}, {0x1E00, 0x1F15}, {0x1F18, 0x1F1D}, + {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, {0x1F50, 0x1F57}, + {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, {0x1F5D, 0x1F5D}, + {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, {0x1FB6, 0x1FBC}, + {0x1FBE, 0x1FBE}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, + {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB}, {0x1FE0, 0x1FEC}, + {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x2071, 0x2071}, + {0x207F, 0x207F}, {0x2090, 0x209C}, {0x2102, 0x2102}, + {0x2107, 0x2107}, {0x210A, 0x2113}, {0x2115, 0x2115}, + {0x2118, 0x211D}, {0x2124, 0x2124}, {0x2126, 0x2126}, + {0x2128, 0x2128}, {0x212A, 0x2139}, {0x213C, 0x213F}, + {0x2145, 0x2149}, {0x214E, 0x214E}, {0x2160, 0x2188}, + {0x2C00, 0x2CE4}, {0x2CEB, 0x2CEE}, {0x2CF2, 0x2CF3}, + {0x2D00, 0x2D25}, {0x2D27, 0x2D27}, {0x2D2D, 0x2D2D}, + {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F}, {0x2D80, 0x2D96}, + {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, + {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, + {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x3005, 0x3007}, + {0x3021, 0x3029}, {0x3031, 0x3035}, {0x3038, 0x303C}, + {0x3041, 0x3096}, {0x309D, 0x309F}, {0x30A1, 0x30FA}, + {0x30FC, 0x30FF}, {0x3105, 0x312F}, {0x3131, 0x318E}, + {0x31A0, 0x31BF}, {0x31F0, 0x31FF}, {0x3400, 0x4DBF}, + {0x4E00, 0xA48C}, {0xA4D0, 0xA4FD}, {0xA500, 0xA60C}, + {0xA610, 0xA61F}, {0xA62A, 0xA62B}, {0xA640, 0xA66E}, + {0xA67F, 0xA69D}, {0xA6A0, 0xA6EF}, {0xA717, 0xA71F}, + {0xA722, 0xA788}, {0xA78B, 0xA7CA}, {0xA7D0, 0xA7D1}, + {0xA7D3, 0xA7D3}, {0xA7D5, 0xA7D9}, {0xA7F2, 0xA801}, + {0xA803, 0xA805}, {0xA807, 0xA80A}, {0xA80C, 0xA822}, + {0xA840, 0xA873}, {0xA882, 0xA8B3}, {0xA8F2, 0xA8F7}, + {0xA8FB, 0xA8FB}, {0xA8FD, 0xA8FE}, {0xA90A, 0xA925}, + {0xA930, 0xA946}, {0xA960, 0xA97C}, {0xA984, 0xA9B2}, + {0xA9CF, 0xA9CF}, {0xA9E0, 0xA9E4}, {0xA9E6, 0xA9EF}, + {0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA40, 0xAA42}, + {0xAA44, 0xAA4B}, {0xAA60, 0xAA76}, {0xAA7A, 0xAA7A}, + {0xAA7E, 0xAAAF}, {0xAAB1, 0xAAB1}, {0xAAB5, 0xAAB6}, + {0xAAB9, 0xAABD}, {0xAAC0, 0xAAC0}, {0xAAC2, 0xAAC2}, + {0xAADB, 0xAADD}, {0xAAE0, 0xAAEA}, {0xAAF2, 0xAAF4}, + {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, {0xAB11, 0xAB16}, + {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, {0xAB30, 0xAB5A}, + {0xAB5C, 0xAB69}, {0xAB70, 0xABE2}, {0xAC00, 0xD7A3}, + {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xF900, 0xFA6D}, + {0xFA70, 0xFAD9}, {0xFB00, 0xFB06}, {0xFB13, 0xFB17}, + {0xFB1D, 0xFB1D}, {0xFB1F, 0xFB28}, {0xFB2A, 0xFB36}, + {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41}, + {0xFB43, 0xFB44}, {0xFB46, 0xFBB1}, {0xFBD3, 0xFC5D}, + {0xFC64, 0xFD3D}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, + {0xFDF0, 0xFDF9}, {0xFE71, 0xFE71}, {0xFE73, 0xFE73}, + {0xFE77, 0xFE77}, {0xFE79, 0xFE79}, {0xFE7B, 0xFE7B}, + {0xFE7D, 0xFE7D}, {0xFE7F, 0xFEFC}, {0xFF21, 0xFF3A}, + {0xFF41, 0xFF5A}, {0xFF66, 0xFF9D}, {0xFFA0, 0xFFBE}, + {0xFFC2, 0xFFC7}, {0xFFCA, 0xFFCF}, {0xFFD2, 0xFFD7}, + {0xFFDA, 0xFFDC}, {0x10000, 0x1000B}, {0x1000D, 0x10026}, + {0x10028, 0x1003A}, {0x1003C, 0x1003D}, {0x1003F, 0x1004D}, + {0x10050, 0x1005D}, {0x10080, 0x100FA}, {0x10140, 0x10174}, + {0x10280, 0x1029C}, {0x102A0, 0x102D0}, {0x10300, 0x1031F}, + {0x1032D, 0x1034A}, {0x10350, 0x10375}, {0x10380, 0x1039D}, + {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D1, 0x103D5}, + {0x10400, 0x1049D}, {0x104B0, 0x104D3}, {0x104D8, 0x104FB}, + {0x10500, 0x10527}, {0x10530, 0x10563}, {0x10570, 0x1057A}, + {0x1057C, 0x1058A}, {0x1058C, 0x10592}, {0x10594, 0x10595}, + {0x10597, 0x105A1}, {0x105A3, 0x105B1}, {0x105B3, 0x105B9}, + {0x105BB, 0x105BC}, {0x10600, 0x10736}, {0x10740, 0x10755}, + {0x10760, 0x10767}, {0x10780, 0x10785}, {0x10787, 0x107B0}, + {0x107B2, 0x107BA}, {0x10800, 0x10805}, {0x10808, 0x10808}, + {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C}, + {0x1083F, 0x10855}, {0x10860, 0x10876}, {0x10880, 0x1089E}, + {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x10900, 0x10915}, + {0x10920, 0x10939}, {0x10980, 0x109B7}, {0x109BE, 0x109BF}, + {0x10A00, 0x10A00}, {0x10A10, 0x10A13}, {0x10A15, 0x10A17}, + {0x10A19, 0x10A35}, {0x10A60, 0x10A7C}, {0x10A80, 0x10A9C}, + {0x10AC0, 0x10AC7}, {0x10AC9, 0x10AE4}, {0x10B00, 0x10B35}, + {0x10B40, 0x10B55}, {0x10B60, 0x10B72}, {0x10B80, 0x10B91}, + {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, + {0x10D00, 0x10D23}, {0x10E80, 0x10EA9}, {0x10EB0, 0x10EB1}, + {0x10F00, 0x10F1C}, {0x10F27, 0x10F27}, {0x10F30, 0x10F45}, + {0x10F70, 0x10F81}, {0x10FB0, 0x10FC4}, {0x10FE0, 0x10FF6}, + {0x11003, 0x11037}, {0x11071, 0x11072}, {0x11075, 0x11075}, + {0x11083, 0x110AF}, {0x110D0, 0x110E8}, {0x11103, 0x11126}, + {0x11144, 0x11144}, {0x11147, 0x11147}, {0x11150, 0x11172}, + {0x11176, 0x11176}, {0x11183, 0x111B2}, {0x111C1, 0x111C4}, + {0x111DA, 0x111DA}, {0x111DC, 0x111DC}, {0x11200, 0x11211}, + {0x11213, 0x1122B}, {0x11280, 0x11286}, {0x11288, 0x11288}, + {0x1128A, 0x1128D}, {0x1128F, 0x1129D}, {0x1129F, 0x112A8}, + {0x112B0, 0x112DE}, {0x11305, 0x1130C}, {0x1130F, 0x11310}, + {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333}, + {0x11335, 0x11339}, {0x1133D, 0x1133D}, {0x11350, 0x11350}, + {0x1135D, 0x11361}, {0x11400, 0x11434}, {0x11447, 0x1144A}, + {0x1145F, 0x11461}, {0x11480, 0x114AF}, {0x114C4, 0x114C5}, + {0x114C7, 0x114C7}, {0x11580, 0x115AE}, {0x115D8, 0x115DB}, + {0x11600, 0x1162F}, {0x11644, 0x11644}, {0x11680, 0x116AA}, + {0x116B8, 0x116B8}, {0x11700, 0x1171A}, {0x11740, 0x11746}, + {0x11800, 0x1182B}, {0x118A0, 0x118DF}, {0x118FF, 0x11906}, + {0x11909, 0x11909}, {0x1190C, 0x11913}, {0x11915, 0x11916}, + {0x11918, 0x1192F}, {0x1193F, 0x1193F}, {0x11941, 0x11941}, + {0x119A0, 0x119A7}, {0x119AA, 0x119D0}, {0x119E1, 0x119E1}, + {0x119E3, 0x119E3}, {0x11A00, 0x11A00}, {0x11A0B, 0x11A32}, + {0x11A3A, 0x11A3A}, {0x11A50, 0x11A50}, {0x11A5C, 0x11A89}, + {0x11A9D, 0x11A9D}, {0x11AB0, 0x11AF8}, {0x11C00, 0x11C08}, + {0x11C0A, 0x11C2E}, {0x11C40, 0x11C40}, {0x11C72, 0x11C8F}, + {0x11D00, 0x11D06}, {0x11D08, 0x11D09}, {0x11D0B, 0x11D30}, + {0x11D46, 0x11D46}, {0x11D60, 0x11D65}, {0x11D67, 0x11D68}, + {0x11D6A, 0x11D89}, {0x11D98, 0x11D98}, {0x11EE0, 0x11EF2}, + {0x11FB0, 0x11FB0}, {0x12000, 0x12399}, {0x12400, 0x1246E}, + {0x12480, 0x12543}, {0x12F90, 0x12FF0}, {0x13000, 0x1342E}, + {0x14400, 0x14646}, {0x16800, 0x16A38}, {0x16A40, 0x16A5E}, + {0x16A70, 0x16ABE}, {0x16AD0, 0x16AED}, {0x16B00, 0x16B2F}, + {0x16B40, 0x16B43}, {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, + {0x16E40, 0x16E7F}, {0x16F00, 0x16F4A}, {0x16F50, 0x16F50}, + {0x16F93, 0x16F9F}, {0x16FE0, 0x16FE1}, {0x16FE3, 0x16FE3}, + {0x17000, 0x187F7}, {0x18800, 0x18CD5}, {0x18D00, 0x18D08}, + {0x1AFF0, 0x1AFF3}, {0x1AFF5, 0x1AFFB}, {0x1AFFD, 0x1AFFE}, + {0x1B000, 0x1B122}, {0x1B150, 0x1B152}, {0x1B164, 0x1B167}, + {0x1B170, 0x1B2FB}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, + {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1D400, 0x1D454}, + {0x1D456, 0x1D49C}, {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2}, + {0x1D4A5, 0x1D4A6}, {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, + {0x1D4BB, 0x1D4BB}, {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, + {0x1D507, 0x1D50A}, {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, + {0x1D51E, 0x1D539}, {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, + {0x1D546, 0x1D546}, {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, + {0x1D6A8, 0x1D6C0}, {0x1D6C2, 0x1D6DA}, {0x1D6DC, 0x1D6FA}, + {0x1D6FC, 0x1D714}, {0x1D716, 0x1D734}, {0x1D736, 0x1D74E}, + {0x1D750, 0x1D76E}, {0x1D770, 0x1D788}, {0x1D78A, 0x1D7A8}, + {0x1D7AA, 0x1D7C2}, {0x1D7C4, 0x1D7CB}, {0x1DF00, 0x1DF1E}, + {0x1E100, 0x1E12C}, {0x1E137, 0x1E13D}, {0x1E14E, 0x1E14E}, + {0x1E290, 0x1E2AD}, {0x1E2C0, 0x1E2EB}, {0x1E7E0, 0x1E7E6}, + {0x1E7E8, 0x1E7EB}, {0x1E7ED, 0x1E7EE}, {0x1E7F0, 0x1E7FE}, + {0x1E800, 0x1E8C4}, {0x1E900, 0x1E943}, {0x1E94B, 0x1E94B}, + {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, + {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, + {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, + {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, + {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, + {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, + {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, + {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, + {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, + {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, + {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, + {0x20000, 0x2A6DF}, {0x2A700, 0x2B738}, {0x2B740, 0x2B81D}, + {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, {0x2F800, 0x2FA1D}, + {0x30000, 0x3134A}}; + +// Unicode 14 XID_Continue, excluding XID_Start +// The Unicode Property XID_Continue is a super set of XID_Start. +// To save Space, the table below only contains the codepoints +// that are not also in XID_Start. +static const llvm::sys::UnicodeCharRange XIDContinueRanges[] = { + {0x0030, 0x0039}, {0x005F, 0x005F}, {0x00B7, 0x00B7}, + {0x0300, 0x036F}, {0x0387, 0x0387}, {0x0483, 0x0487}, + {0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, + {0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0610, 0x061A}, + {0x064B, 0x0669}, {0x0670, 0x0670}, {0x06D6, 0x06DC}, + {0x06DF, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, + {0x06F0, 0x06F9}, {0x0711, 0x0711}, {0x0730, 0x074A}, + {0x07A6, 0x07B0}, {0x07C0, 0x07C9}, {0x07EB, 0x07F3}, + {0x07FD, 0x07FD}, {0x0816, 0x0819}, {0x081B, 0x0823}, + {0x0825, 0x0827}, {0x0829, 0x082D}, {0x0859, 0x085B}, + {0x0898, 0x089F}, {0x08CA, 0x08E1}, {0x08E3, 0x0903}, + {0x093A, 0x093C}, {0x093E, 0x094F}, {0x0951, 0x0957}, + {0x0962, 0x0963}, {0x0966, 0x096F}, {0x0981, 0x0983}, + {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8}, + {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3}, + {0x09E6, 0x09EF}, {0x09FE, 0x09FE}, {0x0A01, 0x0A03}, + {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, {0x0A47, 0x0A48}, + {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, {0x0A66, 0x0A71}, + {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, {0x0ABC, 0x0ABC}, + {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, {0x0ACB, 0x0ACD}, + {0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AFA, 0x0AFF}, + {0x0B01, 0x0B03}, {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, + {0x0B47, 0x0B48}, {0x0B4B, 0x0B4D}, {0x0B55, 0x0B57}, + {0x0B62, 0x0B63}, {0x0B66, 0x0B6F}, {0x0B82, 0x0B82}, + {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCD}, + {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF}, {0x0C00, 0x0C04}, + {0x0C3C, 0x0C3C}, {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, + {0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, + {0x0C66, 0x0C6F}, {0x0C81, 0x0C83}, {0x0CBC, 0x0CBC}, + {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, {0x0CCA, 0x0CCD}, + {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, + {0x0D00, 0x0D03}, {0x0D3B, 0x0D3C}, {0x0D3E, 0x0D44}, + {0x0D46, 0x0D48}, {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, + {0x0D62, 0x0D63}, {0x0D66, 0x0D6F}, {0x0D81, 0x0D83}, + {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, {0x0DD6, 0x0DD6}, + {0x0DD8, 0x0DDF}, {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, + {0x0E31, 0x0E31}, {0x0E33, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0E50, 0x0E59}, {0x0EB1, 0x0EB1}, {0x0EB3, 0x0EBC}, + {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0F18, 0x0F19}, + {0x0F20, 0x0F29}, {0x0F35, 0x0F35}, {0x0F37, 0x0F37}, + {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, {0x0F71, 0x0F84}, + {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, {0x0F99, 0x0FBC}, + {0x0FC6, 0x0FC6}, {0x102B, 0x103E}, {0x1040, 0x1049}, + {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064}, + {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D}, + {0x108F, 0x109D}, {0x135D, 0x135F}, {0x1369, 0x1371}, + {0x1712, 0x1715}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD}, + {0x17E0, 0x17E9}, {0x180B, 0x180D}, {0x180F, 0x1819}, + {0x18A9, 0x18A9}, {0x1920, 0x192B}, {0x1930, 0x193B}, + {0x1946, 0x194F}, {0x19D0, 0x19DA}, {0x1A17, 0x1A1B}, + {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A89}, + {0x1A90, 0x1A99}, {0x1AB0, 0x1ABD}, {0x1ABF, 0x1ACE}, + {0x1B00, 0x1B04}, {0x1B34, 0x1B44}, {0x1B50, 0x1B59}, + {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD}, + {0x1BB0, 0x1BB9}, {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, + {0x1C40, 0x1C49}, {0x1C50, 0x1C59}, {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF4, 0x1CF4}, + {0x1CF7, 0x1CF9}, {0x1DC0, 0x1DFF}, {0x203F, 0x2040}, + {0x2054, 0x2054}, {0x20D0, 0x20DC}, {0x20E1, 0x20E1}, + {0x20E5, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A}, + {0xA620, 0xA629}, {0xA66F, 0xA66F}, {0xA674, 0xA67D}, + {0xA69E, 0xA69F}, {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, + {0xA806, 0xA806}, {0xA80B, 0xA80B}, {0xA823, 0xA827}, + {0xA82C, 0xA82C}, {0xA880, 0xA881}, {0xA8B4, 0xA8C5}, + {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8FF, 0xA909}, + {0xA926, 0xA92D}, {0xA947, 0xA953}, {0xA980, 0xA983}, + {0xA9B3, 0xA9C0}, {0xA9D0, 0xA9D9}, {0xA9E5, 0xA9E5}, + {0xA9F0, 0xA9F9}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4D}, {0xAA50, 0xAA59}, {0xAA7B, 0xAA7D}, + {0xAAB0, 0xAAB0}, {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, + {0xAABE, 0xAABF}, {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, + {0xAAF5, 0xAAF6}, {0xABE3, 0xABEA}, {0xABEC, 0xABED}, + {0xABF0, 0xABF9}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F}, + {0xFE20, 0xFE2F}, {0xFE33, 0xFE34}, {0xFE4D, 0xFE4F}, + {0xFF10, 0xFF19}, {0xFF3F, 0xFF3F}, {0xFF9E, 0xFF9F}, + {0x101FD, 0x101FD}, {0x102E0, 0x102E0}, {0x10376, 0x1037A}, + {0x104A0, 0x104A9}, {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, + {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, + {0x10AE5, 0x10AE6}, {0x10D24, 0x10D27}, {0x10D30, 0x10D39}, + {0x10EAB, 0x10EAC}, {0x10F46, 0x10F50}, {0x10F82, 0x10F85}, + {0x11000, 0x11002}, {0x11038, 0x11046}, {0x11066, 0x11070}, + {0x11073, 0x11074}, {0x1107F, 0x11082}, {0x110B0, 0x110BA}, + {0x110C2, 0x110C2}, {0x110F0, 0x110F9}, {0x11100, 0x11102}, + {0x11127, 0x11134}, {0x11136, 0x1113F}, {0x11145, 0x11146}, + {0x11173, 0x11173}, {0x11180, 0x11182}, {0x111B3, 0x111C0}, + {0x111C9, 0x111CC}, {0x111CE, 0x111D9}, {0x1122C, 0x11237}, + {0x1123E, 0x1123E}, {0x112DF, 0x112EA}, {0x112F0, 0x112F9}, + {0x11300, 0x11303}, {0x1133B, 0x1133C}, {0x1133E, 0x11344}, + {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357}, + {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, + {0x11435, 0x11446}, {0x11450, 0x11459}, {0x1145E, 0x1145E}, + {0x114B0, 0x114C3}, {0x114D0, 0x114D9}, {0x115AF, 0x115B5}, + {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640}, + {0x11650, 0x11659}, {0x116AB, 0x116B7}, {0x116C0, 0x116C9}, + {0x1171D, 0x1172B}, {0x11730, 0x11739}, {0x1182C, 0x1183A}, + {0x118E0, 0x118E9}, {0x11930, 0x11935}, {0x11937, 0x11938}, + {0x1193B, 0x1193E}, {0x11940, 0x11940}, {0x11942, 0x11943}, + {0x11950, 0x11959}, {0x119D1, 0x119D7}, {0x119DA, 0x119E0}, + {0x119E4, 0x119E4}, {0x11A01, 0x11A0A}, {0x11A33, 0x11A39}, + {0x11A3B, 0x11A3E}, {0x11A47, 0x11A47}, {0x11A51, 0x11A5B}, + {0x11A8A, 0x11A99}, {0x11C2F, 0x11C36}, {0x11C38, 0x11C3F}, + {0x11C50, 0x11C59}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, + {0x11D31, 0x11D36}, {0x11D3A, 0x11D3A}, {0x11D3C, 0x11D3D}, + {0x11D3F, 0x11D45}, {0x11D47, 0x11D47}, {0x11D50, 0x11D59}, + {0x11D8A, 0x11D8E}, {0x11D90, 0x11D91}, {0x11D93, 0x11D97}, + {0x11DA0, 0x11DA9}, {0x11EF3, 0x11EF6}, {0x16A60, 0x16A69}, + {0x16AC0, 0x16AC9}, {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, + {0x16B50, 0x16B59}, {0x16F4F, 0x16F4F}, {0x16F51, 0x16F87}, + {0x16F8F, 0x16F92}, {0x16FE4, 0x16FE4}, {0x16FF0, 0x16FF1}, + {0x1BC9D, 0x1BC9E}, {0x1CF00, 0x1CF2D}, {0x1CF30, 0x1CF46}, + {0x1D165, 0x1D169}, {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, + {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, + {0x1D7CE, 0x1D7FF}, {0x1DA00, 0x1DA36}, {0x1DA3B, 0x1DA6C}, + {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, {0x1DA9B, 0x1DA9F}, + {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, + {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, + {0x1E130, 0x1E136}, {0x1E140, 0x1E149}, {0x1E2AE, 0x1E2AE}, + {0x1E2EC, 0x1E2F9}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A}, + {0x1E950, 0x1E959}, {0x1FBF0, 0x1FBF9}, {0xE0100, 0xE01EF}}; + // C11 D.1, C++11 [charname.allowed] static const llvm::sys::UnicodeCharRange C11AllowedIDCharRanges[] = { // 1 @@ -40,127 +389,6 @@ static const llvm::sys::UnicodeCharRange C11AllowedIDCharRanges[] = { { 0xD0000, 0xDFFFD }, { 0xE0000, 0xEFFFD } }; -// C++03 [extendid] -// Note that this is not the same as C++98, but we don't distinguish C++98 -// and C++03 in Clang. -static const llvm::sys::UnicodeCharRange CXX03AllowedIDCharRanges[] = { - // Latin - { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, { 0x0250, 0x02A8 }, - - // Greek - { 0x0384, 0x0384 }, { 0x0388, 0x038A }, { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE }, { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, - - // Cyrillic - { 0x0401, 0x040D }, { 0x040F, 0x044F }, { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - - // Armenian - { 0x0531, 0x0556 }, { 0x0561, 0x0587 }, - - // Hebrew - { 0x05D0, 0x05EA }, { 0x05F0, 0x05F4 }, - - // Arabic - { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06E5, 0x06E7 }, - - // Devanagari - { 0x0905, 0x0939 }, { 0x0958, 0x0962 }, - - // Bengali - { 0x0985, 0x098C }, { 0x098F, 0x0990 }, { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 }, - { 0x09DC, 0x09DD }, { 0x09DF, 0x09E1 }, { 0x09F0, 0x09F1 }, - - // Gurmukhi - { 0x0A05, 0x0A0A }, { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 }, { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, - - // Gujarti - { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D }, { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, { 0x0AE0, 0x0AE0 }, - - // Oriya - { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, - { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, - - // Tamil - { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - - // Telugu - { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, { 0x0C35, 0x0C39 }, { 0x0C60, 0x0C61 }, - - // Kannada - { 0x0C85, 0x0C8C }, { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 }, { 0x0CE0, 0x0CE1 }, - - // Malayam - { 0x0D05, 0x0D0C }, { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, { 0x0D60, 0x0D61 }, - - // Thai - { 0x0E01, 0x0E30 }, { 0x0E32, 0x0E33 }, { 0x0E40, 0x0E46 }, - { 0x0E4F, 0x0E5B }, - - // Lao - { 0x0E81, 0x0E82 }, { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E87 }, - { 0x0E88, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAA }, - { 0x0EAB, 0x0EAB }, { 0x0EAD, 0x0EB0 }, { 0x0EB2, 0x0EB2 }, - { 0x0EB3, 0x0EB3 }, { 0x0EBD, 0x0EBD }, { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - - // Georgian - { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, - - // Hangul - { 0x1100, 0x1159 }, { 0x1161, 0x11A2 }, { 0x11A8, 0x11F9 }, - - // Latin (2) - { 0x1E00, 0x1E9A }, { 0x1EA0, 0x1EF9 }, - - // Greek (2) - { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC }, { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 }, { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC }, - - // Hiragana - { 0x3041, 0x3094 }, { 0x309B, 0x309E }, - - // Katakana - { 0x30A1, 0x30FE }, - - // Bopmofo [sic] - { 0x3105, 0x312C }, - - // CJK Unified Ideographs - { 0x4E00, 0x9FA5 }, { 0xF900, 0xFA2D }, { 0xFB1F, 0xFB36 }, - { 0xFB38, 0xFB3C }, { 0xFB3E, 0xFB3E }, { 0xFB40, 0xFB41 }, - { 0xFB42, 0xFB44 }, { 0xFB46, 0xFBB1 }, { 0xFBD3, 0xFD3F }, - { 0xFD50, 0xFD8F }, { 0xFD92, 0xFDC7 }, { 0xFDF0, 0xFDFB }, - { 0xFE70, 0xFE72 }, { 0xFE74, 0xFE74 }, { 0xFE76, 0xFEFC }, - { 0xFF21, 0xFF3A }, { 0xFF41, 0xFF5A }, { 0xFF66, 0xFFBE }, - { 0xFFC2, 0xFFC7 }, { 0xFFCA, 0xFFCF }, { 0xFFD2, 0xFFD7 }, - { 0xFFDA, 0xFFDC } -}; - // C99 Annex D static const llvm::sys::UnicodeCharRange C99AllowedIDCharRanges[] = { // Latin (1) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f4f5f461e3b..a0871062395 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -195,6 +195,11 @@ void Parser::ParseGNUAttributes(ParsedAttributesWithRange &Attrs, // Expect an identifier or declaration specifier (const, int, etc.) if (Tok.isAnnotation()) break; + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU); + break; + } IdentifierInfo *AttrName = Tok.getIdentifierInfo(); if (!AttrName) break; @@ -714,6 +719,12 @@ void Parser::ParseMicrosoftDeclSpecs(ParsedAttributes &Attrs, if (TryConsumeToken(tok::comma)) continue; + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + Actions.CodeCompleteAttribute(AttributeCommonInfo::AS_Declspec); + return; + } + // We expect either a well-known identifier or a generic string. Anything // else is a malformed declspec. bool IsString = Tok.getKind() == tok::string_literal; @@ -2010,6 +2021,18 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, Actions.CodeCompleteAfterFunctionEquals(D); return nullptr; } + // We're at the point where the parsing of function declarator is finished. + // + // A common error is that users accidently add a virtual specifier + // (e.g. override) in an out-line method definition. + // We attempt to recover by stripping all these specifiers coming after + // the declarator. + while (auto Specifier = isCXX11VirtSpecifier()) { + Diag(Tok, diag::err_virt_specifier_outside_class) + << VirtSpecifiers::getSpecifierName(Specifier) + << FixItHint::CreateRemoval(Tok.getLocation()); + ConsumeToken(); + } // Look at the next token to make sure that this isn't a function // declaration. We have to check this because __attribute__ might be the // start of a function definition in GCC-extended K&R C. @@ -3091,6 +3114,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, return true; }; + // Turn off usual access checking for template specializations and + // instantiations. + bool IsTemplateSpecOrInst = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + switch (Tok.getKind()) { default: DoneWithDeclSpec: @@ -3261,6 +3290,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isConstructorDeclarator(/*Unqualified*/ false)) goto DoneWithDeclSpec; + // C++20 [temp.spec] 13.9/6. + // This disables the access checking rules for function template explicit + // instantiation and explicit specialization: + // - `return type`. + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + ParsedType TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), getCurScope(), &SS, false, false, nullptr, @@ -3268,6 +3303,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, /*WantNontrivialTypeSourceInfo=*/true, isClassTemplateDeductionContext(DSContext)); + if (IsTemplateSpecOrInst) + SAC.done(); + // If the referenced identifier is not a type, then this declspec is // erroneous: We already checked about that it has no type specifier, and // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the @@ -3377,10 +3415,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { - if (TryAnnotateCXXScopeToken(EnteringContext)) { + // C++20 [temp.spec] 13.9/6. + // This disables the access checking rules for function template + // explicit instantiation and explicit specialization: + // - `return type`. + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + + const bool Success = TryAnnotateCXXScopeToken(EnteringContext); + + if (IsTemplateSpecOrInst) + SAC.done(); + + if (Success) { + if (IsTemplateSpecOrInst) + SAC.redelay(); DS.SetTypeSpecError(); goto DoneWithDeclSpec; } + if (!Tok.is(tok::identifier)) continue; } @@ -3889,6 +3941,10 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___ibm128: + isInvalid = DS.SetTypeSpecType(DeclSpec::TST_ibm128, Loc, PrevSpec, + DiagID, Policy); + break; case tok::kw_wchar_t: isInvalid = DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); @@ -3945,15 +4001,19 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeAltiVecBool(true, Loc, PrevSpec, DiagID, Policy); break; case tok::kw_pipe: - if (!getLangOpts().OpenCL || (getLangOpts().OpenCLVersion < 200 && - !getLangOpts().OpenCLCPlusPlus)) { + if (!getLangOpts().OpenCL || + getLangOpts().getOpenCLCompatibleVersion() < 200) { // OpenCL 2.0 and later define this keyword. OpenCL 1.2 and earlier // should support the "pipe" word as identifier. Tok.getIdentifierInfo()->revertTokenIDToIdentifier(); Tok.setKind(tok::identifier); goto DoneWithDeclSpec; - } - isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy); + } else if (!getLangOpts().OpenCLPipes) { + DiagID = diag::err_opencl_unknown_type_specifier; + PrevSpec = Tok.getIdentifierInfo()->getNameStart(); + isInvalid = true; + } else + isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy); break; // We only need to enumerate each image type once. #define IMAGE_READ_WRITE_TYPE(Type, Id, Ext) @@ -4138,9 +4198,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, << FixItHint::CreateRemoval( SourceRange(Loc, DS.getEndLoc())); else if (DiagID == diag::err_opencl_unknown_type_specifier) { - Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus - << getLangOpts().getOpenCLVersionTuple().getAsString() - << PrevSpec << isStorageClass; + Diag(Loc, DiagID) << getLangOpts().getOpenCLVersionString() << PrevSpec + << isStorageClass; } else Diag(Loc, DiagID) << PrevSpec; } @@ -4964,6 +5023,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { case tok::kw__Fract: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -5045,6 +5105,7 @@ bool Parser::isTypeSpecifierQualifier() { case tok::kw__Fract: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -5126,8 +5187,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { switch (Tok.getKind()) { default: return false; + // OpenCL 2.0 and later define this keyword. case tok::kw_pipe: - return getLangOpts().OpenCLPipe; + return getLangOpts().OpenCL && + getLangOpts().getOpenCLCompatibleVersion() >= 200; case tok::identifier: // foo::bar // Unfortunate hack to support "Class.factoryMethod" notation. @@ -5213,6 +5276,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw__Fract: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_bool: case tok::kw__Bool: case tok::kw__Decimal32: @@ -5656,7 +5720,9 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang, if (Kind == tok::star || Kind == tok::caret) return true; - if (Kind == tok::kw_pipe && Lang.OpenCLPipe) + // OpenCL 2.0 and later define this keyword. + if (Kind == tok::kw_pipe && Lang.OpenCL && + Lang.getOpenCLCompatibleVersion() >= 200) return true; if (!Lang.CPlusPlus) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index ca5c013a51f..f5a6ffcff9e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -678,7 +678,10 @@ Parser::ParseUsingDeclaration( SourceLocation UsingLoc, SourceLocation &DeclEnd, ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) { SourceLocation UELoc; - if (TryConsumeToken(tok::kw_enum, UELoc)) { + bool InInitStatement = Context == DeclaratorContext::SelectionInit || + Context == DeclaratorContext::ForInit; + + if (TryConsumeToken(tok::kw_enum, UELoc) && !InInitStatement) { // C++20 using-enum Diag(UELoc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_using_enum_declaration @@ -714,6 +717,9 @@ Parser::ParseUsingDeclaration( ParsedAttributesWithRange MisplacedAttrs(AttrFactory); MaybeParseCXX11Attributes(MisplacedAttrs); + if (InInitStatement && Tok.isNot(tok::identifier)) + return nullptr; + UsingDeclarator D; bool InvalidDeclarator = ParseUsingDeclarator(Context, D); @@ -732,7 +738,7 @@ Parser::ParseUsingDeclaration( } // Maybe this is an alias-declaration. - if (Tok.is(tok::equal)) { + if (Tok.is(tok::equal) || InInitStatement) { if (InvalidDeclarator) { SkipUntil(tok::semi); return nullptr; @@ -1474,19 +1480,15 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, return; } - // C++03 [temp.explicit] 14.7.2/8: - // The usual access checking rules do not apply to names used to specify - // explicit instantiations. - // - // As an extension we do not perform access checking on the names used to - // specify explicit specializations either. This is important to allow - // specializing traits classes for private types. - // - // Note that we don't suppress if this turns out to be an elaborated - // type specifier. - bool shouldDelayDiagsInTag = - (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || - TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + // C++20 [temp.class.spec] 13.7.5/10 + // The usual access checking rules do not apply to non-dependent names + // used to specify template arguments of the simple-template-id of the + // partial specialization. + // C++20 [temp.spec] 13.9/6: + // The usual access checking rules do not apply to names in a declaration + // of an explicit instantiation or explicit specialization... + const bool shouldDelayDiagsInTag = + (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate); SuppressAccessChecks diagsFromTag(*this, shouldDelayDiagsInTag); ParsedAttributesWithRange attrs(AttrFactory); @@ -1834,14 +1836,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } - // If this is an elaborated type specifier, and we delayed - // diagnostics before, just merge them into the current pool. - if (shouldDelayDiagsInTag) { - diagsFromTag.done(); - if (TUK == Sema::TUK_Reference) - diagsFromTag.redelay(); - } - if (!Name && !TemplateId && (DS.getTypeSpecType() == DeclSpec::TST_error || TUK != Sema::TUK_Definition)) { if (DS.getTypeSpecType() != DeclSpec::TST_error) { @@ -2018,6 +2012,16 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } + // If this is an elaborated type specifier in function template, + // and we delayed diagnostics before, + // just merge them into the current pool. + if (shouldDelayDiagsInTag) { + diagsFromTag.done(); + if (TUK == Sema::TUK_Reference && + TemplateInfo.Kind == ParsedTemplateInfo::Template) + diagsFromTag.redelay(); + } + // If there is a body, parse it and inform the actions module. if (TUK == Sema::TUK_Definition) { assert(Tok.is(tok::l_brace) || @@ -2713,9 +2717,22 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (MalformedTypeSpec) DS.SetTypeSpecError(); + // Turn off usual access checking for templates explicit specialization + // and instantiation. + // C++20 [temp.spec] 13.9/6. + // This disables the access checking rules for member function template + // explicit instantiation and explicit specialization. + bool IsTemplateSpecOrInst = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks diagsFromTag(*this, IsTemplateSpecOrInst); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_class, &CommonLateParsedAttrs); + if (IsTemplateSpecOrInst) + diagsFromTag.done(); + // Turn off colon protection that was set for declspec. X.restore(); @@ -2784,6 +2801,11 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ExprResult TrailingRequiresClause; bool ExpectSemi = true; + // C++20 [temp.spec] 13.9/6. + // This disables the access checking rules for member function template + // explicit instantiation and explicit specialization. + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + // Parse the first declarator. if (ParseCXXMemberDeclaratorBeforeInitializer( DeclaratorInfo, VS, BitfieldSize, LateParsedAttrs)) { @@ -2791,6 +2813,9 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return nullptr; } + if (IsTemplateSpecOrInst) + SAC.done(); + // Check for a member function definition. if (BitfieldSize.isUnset()) { // MSVC permits pure specifier on inline functions defined at class scope. @@ -2989,9 +3014,11 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ExprResult Init = ParseCXXMemberInitializer( ThisDecl, DeclaratorInfo.isDeclarationOfFunction(), EqualLoc); - if (Init.isInvalid()) + if (Init.isInvalid()) { + if (ThisDecl) + Actions.ActOnUninitializedDecl(ThisDecl); SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); - else if (ThisDecl) + } else if (ThisDecl) Actions.AddInitializerToDecl(ThisDecl, Init.get(), EqualLoc.isInvalid()); } else if (ThisDecl && DS.getStorageClassSpec() == DeclSpec::SCS_static) // No initializer. @@ -3835,7 +3862,7 @@ Parser::tryParseExceptionSpecification(bool Delayed, NoexceptExpr = ParseConstantExpression(); T.consumeClose(); if (!NoexceptExpr.isInvalid()) { - NoexceptExpr = Actions.ActOnNoexceptSpec(KeywordLoc, NoexceptExpr.get(), + NoexceptExpr = Actions.ActOnNoexceptSpec(NoexceptExpr.get(), NoexceptType); NoexceptRange = SourceRange(KeywordLoc, T.getCloseLocation()); } else { @@ -4084,7 +4111,10 @@ void Parser::PopParsingClass(Sema::ParsingClassState state) { /// If a keyword or an alternative token that satisfies the syntactic /// requirements of an identifier is contained in an attribute-token, /// it is considered an identifier. -IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { +IdentifierInfo * +Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc, + Sema::AttributeCompletion Completion, + const IdentifierInfo *Scope) { switch (Tok.getKind()) { default: // Identifiers and keywords have identifier info attached. @@ -4096,6 +4126,13 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { } return nullptr; + case tok::code_completion: + cutOffParsing(); + Actions.CodeCompleteAttribute(getLangOpts().CPlusPlus ? ParsedAttr::AS_CXX11 + : ParsedAttr::AS_C2x, + Completion, Scope); + return nullptr; + case tok::numeric_constant: { // If we got a numeric constant, check to see if it comes from a macro that // corresponds to the predefined __clang__ macro. If it does, warn the user @@ -4371,7 +4408,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, : diag::ext_using_attribute_ns); ConsumeToken(); - CommonScopeName = TryParseCXX11AttributeIdentifier(CommonScopeLoc); + CommonScopeName = TryParseCXX11AttributeIdentifier( + CommonScopeLoc, Sema::AttributeCompletion::Scope); if (!CommonScopeName) { Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; SkipUntil(tok::r_square, tok::colon, StopBeforeMatch); @@ -4383,7 +4421,7 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, llvm::SmallDenseMap SeenAttrs; bool AttrParsed = false; - while (!Tok.isOneOf(tok::r_square, tok::semi)) { + while (!Tok.isOneOf(tok::r_square, tok::semi, tok::eof)) { if (AttrParsed) { // If we parsed an attribute, a comma is required before parsing any // additional attributes. @@ -4401,7 +4439,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, SourceLocation ScopeLoc, AttrLoc; IdentifierInfo *ScopeName = nullptr, *AttrName = nullptr; - AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + AttrName = TryParseCXX11AttributeIdentifier( + AttrLoc, Sema::AttributeCompletion::Attribute, CommonScopeName); if (!AttrName) // Break out to the "expected ']'" diagnostic. break; @@ -4411,7 +4450,8 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, ScopeName = AttrName; ScopeLoc = AttrLoc; - AttrName = TryParseCXX11AttributeIdentifier(AttrLoc); + AttrName = TryParseCXX11AttributeIdentifier( + AttrLoc, Sema::AttributeCompletion::Attribute, ScopeName); if (!AttrName) { Diag(Tok.getLocation(), diag::err_expected) << tok::identifier; SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch); @@ -4626,7 +4666,15 @@ void Parser::ParseMicrosoftAttributes(ParsedAttributes &attrs, // Skip most ms attributes except for a specific list. while (true) { - SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch); + SkipUntil(tok::r_square, tok::identifier, + StopAtSemi | StopBeforeMatch | StopAtCodeCompletion); + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + Actions.CodeCompleteAttribute(AttributeCommonInfo::AS_Microsoft, + Sema::AttributeCompletion::Attribute, + /*Scope=*/nullptr); + break; + } if (Tok.isNot(tok::identifier)) // ']', but also eof break; if (Tok.getIdentifierInfo()->getName() == "uuid") diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 22f3b7624c4..2c8b4f9f441 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1521,6 +1521,7 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, case tok::kw___bf16: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_void: case tok::kw_typename: case tok::kw_typeof: @@ -2331,7 +2332,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, /// a parameter. ExprResult Parser::ParseSYCLUniqueStableNameExpression() { assert(Tok.is(tok::kw___builtin_sycl_unique_stable_name) && - "Not __bulitin_sycl_unique_stable_name"); + "Not __builtin_sycl_unique_stable_name"); SourceLocation OpLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index f3d10b4a088..4e5c0ac6c1c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1068,8 +1068,8 @@ bool Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro, // Ensure that any ellipsis was in the right place. SourceLocation EllipsisLoc; - if (std::any_of(std::begin(EllipsisLocs), std::end(EllipsisLocs), - [](SourceLocation Loc) { return Loc.isValid(); })) { + if (llvm::any_of(EllipsisLocs, + [](SourceLocation Loc) { return Loc.isValid(); })) { // The '...' should appear before the identifier in an init-capture, and // after the identifier otherwise. bool InitCapture = InitKind != LambdaCaptureInitKind::NoInit; @@ -1910,6 +1910,28 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { } } +Parser::DeclGroupPtrTy +Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context, + ParsedAttributesWithRange &Attrs) { + assert(Tok.is(tok::kw_using) && "Expected using"); + assert((Context == DeclaratorContext::ForInit || + Context == DeclaratorContext::SelectionInit) && + "Unexpected Declarator Context"); + DeclGroupPtrTy DG; + SourceLocation DeclStart = ConsumeToken(), DeclEnd; + + DG = ParseUsingDeclaration(Context, {}, DeclStart, DeclEnd, Attrs, AS_none); + if (!DG) + return DG; + + Diag(DeclStart, !getLangOpts().CPlusPlus2b + ? diag::ext_alias_in_init_statement + : diag::warn_cxx20_alias_in_init_statement) + << SourceRange(DeclStart, DeclEnd); + + return DG; +} + /// ParseCXXCondition - if/switch/while condition expression. /// /// condition: @@ -2017,9 +2039,14 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, case ConditionOrInitStatement::InitStmtDecl: { WarnOnInit(); + DeclGroupPtrTy DG; SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration( - DeclaratorContext::SelectionInit, DeclEnd, attrs, /*RequireSemi=*/true); + if (Tok.is(tok::kw_using)) + DG = ParseAliasDeclarationInInitStatement( + DeclaratorContext::SelectionInit, attrs); + else + DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd, + attrs, /*RequireSemi=*/true); *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); return ParseCXXCondition(nullptr, Loc, CK); } @@ -2226,6 +2253,9 @@ void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { case tok::kw___float128: DS.SetTypeSpecType(DeclSpec::TST_float128, Loc, PrevSpec, DiagID, Policy); break; + case tok::kw___ibm128: + DS.SetTypeSpecType(DeclSpec::TST_ibm128, Loc, PrevSpec, DiagID, Policy); + break; case tok::kw_wchar_t: DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec, DiagID, Policy); break; @@ -3602,7 +3632,7 @@ ExprResult Parser::ParseRequiresExpression() { break; } if (!Expression.isInvalid() && PossibleRequiresExprInSimpleRequirement) - Diag(StartLoc, diag::warn_requires_expr_in_simple_requirement) + Diag(StartLoc, diag::err_requires_expr_in_simple_requirement) << FixItHint::CreateInsertion(StartLoc, "requires"); if (auto *Req = Actions.ActOnSimpleRequirement(Expression.get())) Requirements.push_back(Req); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 18e43c3734a..613ad742c93 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -828,7 +828,7 @@ static StringRef stringLiteralParser(Parser &P) { static StringRef getNameFromIdOrString(Parser &P, Token &Tok, OMPContextLvl Lvl) { - if (Tok.is(tok::identifier)) { + if (Tok.is(tok::identifier) || Tok.is(tok::kw_for)) { llvm::SmallString<16> Buffer; StringRef Name = P.getPreprocessor().getSpelling(Tok, Buffer); (void)P.ConsumeToken(); @@ -1402,26 +1402,178 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, OMPTraitInfo *ParentTI = Actions.getOMPTraitInfoForSurroundingScope(); ASTContext &ASTCtx = Actions.getASTContext(); OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); - if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) - return; + SmallVector AdjustNothing; + SmallVector AdjustNeedDevicePtr; + SmallVector AppendArgs; + SourceLocation AdjustArgsLoc, AppendArgsLoc; + + // At least one clause is required. + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << (getLangOpts().OpenMP < 51 ? 0 : 1); + } + + bool IsError = false; + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (!isAllowedClauseForDirective(OMPD_declare_variant, CKind, + getLangOpts().OpenMP)) { + Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << (getLangOpts().OpenMP < 51 ? 0 : 1); + IsError = true; + } + if (!IsError) { + switch (CKind) { + case OMPC_match: + IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI); + break; + case OMPC_adjust_args: { + AdjustArgsLoc = Tok.getLocation(); + ConsumeToken(); + Parser::OpenMPVarListDataTy Data; + SmallVector Vars; + IsError = ParseOpenMPVarList(OMPD_declare_variant, OMPC_adjust_args, + Vars, Data); + if (!IsError) + llvm::append_range(Data.ExtraModifier == OMPC_ADJUST_ARGS_nothing + ? AdjustNothing + : AdjustNeedDevicePtr, + Vars); + break; + } + case OMPC_append_args: + if (!AppendArgs.empty()) { + Diag(AppendArgsLoc, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(OMPD_declare_variant) + << getOpenMPClauseName(CKind) << 0; + IsError = true; + } + if (!IsError) { + AppendArgsLoc = Tok.getLocation(); + ConsumeToken(); + IsError = parseOpenMPAppendArgs(AppendArgs); + } + break; + default: + llvm_unreachable("Unexpected clause for declare variant."); + } + } + if (IsError) { + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); + return; + } + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } Optional> DeclVarData = Actions.checkOpenMPDeclareVariantFunction( - Ptr, AssociatedFunction.get(), TI, + Ptr, AssociatedFunction.get(), TI, AppendArgs.size(), SourceRange(Loc, Tok.getLocation())); - // Skip last tokens. - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); if (DeclVarData && !TI.Sets.empty()) Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData->first, DeclVarData->second, TI, + DeclVarData->first, DeclVarData->second, TI, AdjustNothing, + AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc, SourceRange(Loc, Tok.getLocation())); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); } +/// Parse a list of interop-types. These are 'target' and 'targetsync'. Both +/// are allowed but duplication of either is not meaningful. +static Optional +parseInteropTypeList(Parser &P) { + const Token &Tok = P.getCurToken(); + bool HasError = false; + bool IsTarget = false; + bool IsTargetSync = false; + + while (Tok.is(tok::identifier)) { + if (Tok.getIdentifierInfo()->isStr("target")) { + // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] + // Each interop-type may be specified on an action-clause at most + // once. + if (IsTarget) + P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; + IsTarget = true; + } else if (Tok.getIdentifierInfo()->isStr("targetsync")) { + if (IsTargetSync) + P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; + IsTargetSync = true; + } else { + HasError = true; + P.Diag(Tok, diag::err_omp_expected_interop_type); + } + P.ConsumeToken(); + + if (!Tok.is(tok::comma)) + break; + P.ConsumeToken(); + } + if (HasError) + return None; + + if (!IsTarget && !IsTargetSync) { + P.Diag(Tok, diag::err_omp_expected_interop_type); + return None; + } + + // As of OpenMP 5.1,there are two interop-types, "target" and + // "targetsync". Either or both are allowed for a single interop. + if (IsTarget && IsTargetSync) + return OMPDeclareVariantAttr::Target_TargetSync; + if (IsTarget) + return OMPDeclareVariantAttr::Target; + return OMPDeclareVariantAttr::TargetSync; +} + +bool Parser::parseOpenMPAppendArgs( + SmallVectorImpl &InterOpTypes) { + bool HasError = false; + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(OMPC_append_args).data())) + return true; + + // Parse the list of append-ops, each is; + // interop(interop-type[,interop-type]...) + while (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("interop")) { + ConsumeToken(); + BalancedDelimiterTracker IT(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop")) + return true; + + // Parse the interop-types. + if (Optional IType = + parseInteropTypeList(*this)) + InterOpTypes.push_back(IType.getValue()); + else + HasError = true; + + IT.consumeClose(); + if (Tok.is(tok::comma)) + ConsumeToken(); + } + if (!HasError && InterOpTypes.empty()) { + HasError = true; + Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op); + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + HasError = T.consumeClose() || HasError; + return HasError; +} + bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI, OMPTraitInfo *ParentTI) { @@ -1431,24 +1583,15 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, : getOpenMPClauseKind(PP.getSpelling(Tok)); if (CKind != OMPC_match) { Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) - << getOpenMPClauseName(OMPC_match); - while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) - ; - // Skip the last annot_pragma_openmp_end. - (void)ConsumeAnnotationToken(); + << (getLangOpts().OpenMP < 51 ? 0 : 1); return true; } (void)ConsumeToken(); // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPClauseName(OMPC_match).data())) { - while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) - ; - // Skip the last annot_pragma_openmp_end. - (void)ConsumeAnnotationToken(); + getOpenMPClauseName(OMPC_match).data())) return true; - } // Parse inner context selectors. parseOMPContextSelectors(Loc, TI); @@ -1532,7 +1675,7 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, /// void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, SourceLocation Loc) { - SmallVector Assumptions; + SmallVector Assumptions; bool SkippedClauses = false; auto SkipBraces = [&](llvm::StringRef Spelling, bool IssueNote) { @@ -1599,9 +1742,11 @@ void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, } assert(II && "Expected an identifier clause!"); - StringRef Assumption = II->getName(); + std::string Assumption = II->getName().str(); if (ACMI.StartsWith) - Assumption = Assumption.substr(ACMI.Identifier.size()); + Assumption = "ompx_" + Assumption.substr(ACMI.Identifier.size()); + else + Assumption = "omp_" + Assumption; Assumptions.push_back(Assumption); } @@ -1651,7 +1796,7 @@ parseOpenMPSimpleClause(Parser &P, OpenMPClauseKind Kind) { unsigned Type = getOpenMPSimpleClauseType( Kind, Tok.isAnnotation() ? "" : P.getPreprocessor().getSpelling(Tok), - P.getLangOpts().OpenMP); + P.getLangOpts()); SourceLocation TypeLoc = Tok.getLocation(); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -2027,8 +2172,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( OMPTraitInfo *ParentTI = Actions.getOMPTraitInfoForSurroundingScope(); ASTContext &ASTCtx = Actions.getASTContext(); OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo(); - if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) + if (parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI)) { + while (!SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); break; + } // Skip last tokens. skipUntilPragmaOpenMPEnd(OMPD_begin_declare_variant); @@ -2044,8 +2194,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( // improve the diagnostic location. Diag(Loc, diag::warn_unknown_begin_declare_variant_isa_trait) << ISATrait; }; - TargetOMPContext OMPCtx(ASTCtx, std::move(DiagUnknownTrait), - /* CurrentFunctionDecl */ nullptr); + TargetOMPContext OMPCtx( + ASTCtx, std::move(DiagUnknownTrait), + /* CurrentFunctionDecl */ nullptr, + /* ConstructTraits */ ArrayRef()); if (isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ true)) { Actions.ActOnOpenMPBeginDeclareVariant(Loc, TI); @@ -2222,6 +2374,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_target_teams_distribute_simd: case OMPD_dispatch: case OMPD_masked: + case OMPD_metadirective: + case OMPD_loop: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); break; @@ -2276,8 +2430,10 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { - assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && - "Not an OpenMP directive!"); + static bool ReadDirectiveWithinMetadirective = false; + if (!ReadDirectiveWithinMetadirective) + assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) && + "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector Clauses; @@ -2286,8 +2442,15 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { FirstClauses(llvm::omp::Clause_enumSize + 1); unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; - SourceLocation Loc = ConsumeAnnotationToken(), EndLoc; + SourceLocation Loc = ReadDirectiveWithinMetadirective + ? Tok.getLocation() + : ConsumeAnnotationToken(), + EndLoc; OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); + if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) { + Diag(Tok, diag::err_omp_unknown_directive); + return StmtError(); + } OpenMPDirectiveKind CancelRegion = OMPD_unknown; // Name of critical directive. DeclarationNameInfo DirName; @@ -2295,6 +2458,141 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { bool HasAssociatedStatement = true; switch (DKind) { + case OMPD_metadirective: { + ConsumeToken(); + SmallVector VMIs; + + // First iteration of parsing all clauses of metadirective. + // This iteration only parses and collects all context selector ignoring the + // associated directives. + TentativeParsingAction TPA(*this); + ASTContext &ASTContext = Actions.getASTContext(); + + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + SourceLocation Loc = ConsumeToken(); + + // Parse '('. + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(CKind).data())) + return Directive; + + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); + if (CKind == OMPC_when) { + // parse and get OMPTraitInfo to pass to the When clause + parseOMPContextSelectors(Loc, TI); + if (TI.Sets.size() == 0) { + Diag(Tok, diag::err_omp_expected_context_selector) << "when clause"; + TPA.Commit(); + return Directive; + } + + // Parse ':' + if (Tok.is(tok::colon)) + ConsumeAnyToken(); + else { + Diag(Tok, diag::err_omp_expected_colon) << "when clause"; + TPA.Commit(); + return Directive; + } + } + // Skip Directive for now. We will parse directive in the second iteration + int paren = 0; + while (Tok.isNot(tok::r_paren) || paren != 0) { + if (Tok.is(tok::l_paren)) + paren++; + if (Tok.is(tok::r_paren)) + paren--; + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::err_omp_expected_punc) + << getOpenMPClauseName(CKind) << 0; + TPA.Commit(); + return Directive; + } + ConsumeAnyToken(); + } + // Parse ')' + if (Tok.is(tok::r_paren)) + T.consumeClose(); + + VariantMatchInfo VMI; + TI.getAsVariantMatchInfo(ASTContext, VMI); + + VMIs.push_back(VMI); + } + + TPA.Revert(); + // End of the first iteration. Parser is reset to the start of metadirective + + TargetOMPContext OMPCtx(ASTContext, /* DiagUnknownTrait */ nullptr, + /* CurrentFunctionDecl */ nullptr, + ArrayRef()); + + // A single match is returned for OpenMP 5.0 + int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx); + + int Idx = 0; + // In OpenMP 5.0 metadirective is either replaced by another directive or + // ignored. + // TODO: In OpenMP 5.1 generate multiple directives based upon the matches + // found by getBestWhenMatchForContext. + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + // OpenMP 5.0 implementation - Skip to the best index found. + if (Idx++ != BestIdx) { + ConsumeToken(); // Consume clause name + T.consumeOpen(); // Consume '(' + int paren = 0; + // Skip everything inside the clause + while (Tok.isNot(tok::r_paren) || paren != 0) { + if (Tok.is(tok::l_paren)) + paren++; + if (Tok.is(tok::r_paren)) + paren--; + ConsumeAnyToken(); + } + // Parse ')' + if (Tok.is(tok::r_paren)) + T.consumeClose(); + continue; + } + + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + SourceLocation Loc = ConsumeToken(); + + // Parse '('. + T.consumeOpen(); + + // Skip ContextSelectors for when clause + if (CKind == OMPC_when) { + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); + // parse and skip the ContextSelectors + parseOMPContextSelectors(Loc, TI); + + // Parse ':' + ConsumeAnyToken(); + } + + // If no directive is passed, skip in OpenMP 5.0. + // TODO: Generate nothing directive from OpenMP 5.1. + if (Tok.is(tok::r_paren)) { + SkipUntil(tok::annot_pragma_openmp_end); + break; + } + + // Parse Directive + ReadDirectiveWithinMetadirective = true; + Directive = ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); + ReadDirectiveWithinMetadirective = false; + break; + } + break; + } case OMPD_threadprivate: { // FIXME: Should this be permitted in C++? if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == @@ -2427,6 +2725,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_target_data: case OMPD_target_parallel: case OMPD_target_parallel_for: + case OMPD_loop: case OMPD_taskloop: case OMPD_taskloop_simd: case OMPD_master_taskloop: @@ -2486,6 +2785,13 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); while (Tok.isNot(tok::annot_pragma_openmp_end)) { + // If we are parsing for a directive within a metadirective, the directive + // ends with a ')'. + if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + break; + } bool HasImplicitClause = false; if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { HasImplicitClause = true; @@ -2562,8 +2868,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && getLangOpts().OpenMPIRBuilder) - AssociatedStmt = - Actions.ActOnOpenMPCanonicalLoop(AssociatedStmt.get()); + AssociatedStmt = Actions.ActOnOpenMPLoopnest(AssociatedStmt.get()); } AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || @@ -2751,7 +3056,7 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { /// clause: /// if-clause | final-clause | num_threads-clause | safelen-clause | /// default-clause | private-clause | firstprivate-clause | shared-clause -/// | linear-clause | aligned-clause | collapse-clause | +/// | linear-clause | aligned-clause | collapse-clause | bind-clause | /// lastprivate-clause | reduction-clause | proc_bind-clause | /// schedule-clause | copyin-clause | copyprivate-clause | untied-clause | /// mergeable-clause | flush-clause | read-clause | write-clause | @@ -2800,6 +3105,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_nocontext: case OMPC_filter: case OMPC_partial: + case OMPC_align: // OpenMP [2.5, Restrictions] // At most one num_threads clause can appear on the directive. // OpenMP [2.8.1, simd construct, Restrictions] @@ -2841,6 +3147,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_proc_bind: case OMPC_atomic_default_mem_order: case OMPC_order: + case OMPC_bind: // OpenMP [2.14.3.1, Restrictions] // Only a single default clause may be specified on a parallel, task or // teams directive. @@ -2849,6 +3156,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, // OpenMP [5.0, Requires directive, Restrictions] // At most one atomic_default_mem_order clause can appear // on the directive + // OpenMP 5.1, 2.11.7 loop Construct, Restrictions. + // At most one bind clause can appear on a loop directive. if (!FirstClause && CKind != OMPC_order) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; @@ -3054,6 +3363,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, /// detach-clause: /// 'detach' '(' event-handler-expression ')' /// +/// align-clause +/// 'align' '(' positive-integer-constant ')' +/// OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind, bool ParseOnly) { SourceLocation Loc = ConsumeToken(); @@ -3143,36 +3455,15 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, } // Parse the interop-types. - bool HasError = false; - while (Tok.is(tok::identifier)) { - if (PP.getSpelling(Tok) == "target") { - // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] - // Each interop-type may be specified on an action-clause at most - // once. - if (IsTarget) - Diag(Tok, diag::warn_omp_more_one_interop_type) << "target"; - IsTarget = true; - } else if (PP.getSpelling(Tok) == "targetsync") { - if (IsTargetSync) - Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync"; - IsTargetSync = true; - } else { - HasError = true; - Diag(Tok, diag::err_omp_expected_interop_type); - } - ConsumeToken(); - - if (!Tok.is(tok::comma)) - break; - ConsumeToken(); + if (Optional IType = + parseInteropTypeList(*this)) { + IsTarget = IType != OMPDeclareVariantAttr::TargetSync; + IsTargetSync = IType != OMPDeclareVariantAttr::Target; + if (Tok.isNot(tok::colon)) + Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; } - if (!HasError && !IsTarget && !IsTargetSync) - Diag(Tok, diag::err_omp_expected_interop_type); - if (Tok.is(tok::colon)) ConsumeToken(); - else if (IsTarget || IsTargetSync) - Diag(Tok, diag::warn_pragma_expected_colon) << "interop types"; } // Parse the variable. @@ -3216,6 +3507,9 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind, /// proc_bind-clause: /// 'proc_bind' '(' 'master' | 'close' | 'spread' ')' /// +/// bind-clause: +/// 'bind' '(' 'teams' | 'parallel' | 'thread' ')' +/// /// update-clause: /// 'update' '(' 'in' | 'out' | 'inout' | 'mutexinoutset' ')' /// @@ -3310,8 +3604,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Arg[Modifier2] = OMPC_SCHEDULE_MODIFIER_unknown; Arg[ScheduleKind] = OMPC_SCHEDULE_unknown; unsigned KindModifier = getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); if (KindModifier > OMPC_SCHEDULE_unknown) { // Parse 'modifier' Arg[Modifier1] = KindModifier; @@ -3323,8 +3616,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, // Parse ',' 'modifier' ConsumeAnyToken(); KindModifier = getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); Arg[Modifier2] = KindModifier > OMPC_SCHEDULE_unknown ? KindModifier : (unsigned)OMPC_SCHEDULE_unknown; @@ -3339,8 +3631,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, else Diag(Tok, diag::warn_pragma_expected_colon) << "schedule modifier"; KindModifier = getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); } Arg[ScheduleKind] = KindModifier; KLoc[ScheduleKind] = Tok.getLocation(); @@ -3354,8 +3645,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, DelimLoc = ConsumeAnyToken(); } else if (Kind == OMPC_dist_schedule) { Arg.push_back(getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP)); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); KLoc.push_back(Tok.getLocation()); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -3365,8 +3655,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, } else if (Kind == OMPC_defaultmap) { // Get a defaultmap modifier unsigned Modifier = getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); // Set defaultmap modifier to unknown if it is either scalar, aggregate, or // pointer if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown) @@ -3384,8 +3673,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, Diag(Tok, diag::warn_pragma_expected_colon) << "defaultmap modifier"; // Get a defaultmap kind Arg.push_back(getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP)); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); KLoc.push_back(Tok.getLocation()); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -3400,8 +3688,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, NextToken().is(tok::colon)) { // Parse optional ':' Arg.push_back(getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), - getLangOpts().OpenMP)); + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts())); KLoc.push_back(Tok.getLocation()); ConsumeAnyToken(); // Parse ':' @@ -3512,7 +3799,7 @@ static OpenMPMapModifierKind isMapModifier(Parser &P) { Preprocessor &PP = P.getPreprocessor(); OpenMPMapModifierKind TypeModifier = static_cast(getOpenMPSimpleClauseType( - OMPC_map, PP.getSpelling(Tok), P.getLangOpts().OpenMP)); + OMPC_map, PP.getSpelling(Tok), P.getLangOpts())); return TypeModifier; } @@ -3554,7 +3841,8 @@ bool Parser::parseMapTypeModifiers(OpenMPVarListDataTy &Data) { OpenMPMapModifierKind TypeModifier = isMapModifier(*this); if (TypeModifier == OMPC_MAP_MODIFIER_always || TypeModifier == OMPC_MAP_MODIFIER_close || - TypeModifier == OMPC_MAP_MODIFIER_present) { + TypeModifier == OMPC_MAP_MODIFIER_present || + TypeModifier == OMPC_MAP_MODIFIER_ompx_hold) { Data.MapTypeModifiers.push_back(TypeModifier); Data.MapTypeModifiersLoc.push_back(Tok.getLocation()); ConsumeToken(); @@ -3577,7 +3865,8 @@ bool Parser::parseMapTypeModifiers(OpenMPVarListDataTy &Data) { if (PP.LookAhead(0).is(tok::colon)) return false; Diag(Tok, diag::err_omp_unknown_map_type_modifier) - << (getLangOpts().OpenMP >= 51 ? 1 : 0); + << (getLangOpts().OpenMP >= 51 ? 1 : 0) + << getLangOpts().OpenMPExtensions; ConsumeToken(); } if (getCurToken().is(tok::comma)) @@ -3596,7 +3885,7 @@ static OpenMPMapClauseKind isMapType(Parser &P) { Preprocessor &PP = P.getPreprocessor(); OpenMPMapClauseKind MapType = static_cast(getOpenMPSimpleClauseType( - OMPC_map, PP.getSpelling(Tok), P.getLangOpts().OpenMP)); + OMPC_map, PP.getSpelling(Tok), P.getLangOpts())); return MapType; } @@ -3749,8 +4038,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, (Tok.is(tok::identifier) || Tok.is(tok::kw_default)) && NextToken().is(tok::comma)) { // Parse optional reduction modifier. - Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), - getLangOpts().OpenMP); + Data.ExtraModifier = + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); ConsumeToken(); assert(Tok.is(tok::comma) && "Expected comma."); @@ -3796,7 +4085,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ColonProtectionRAIIObject ColonRAII(*this); Data.ExtraModifier = getOpenMPSimpleClauseType( Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", - getLangOpts().OpenMP); + getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); if (Data.ExtraModifier == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, @@ -3821,8 +4110,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // Try to parse modifier if any. Data.ExtraModifier = OMPC_LINEAR_val; if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { - Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), - getLangOpts().OpenMP); + Data.ExtraModifier = + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); Data.ExtraModifierLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; @@ -3835,8 +4124,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) && !isOpenMPTaskLoopDirective(DKind)) && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { - Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), - getLangOpts().OpenMP); + Data.ExtraModifier = + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts()); Data.ExtraModifierLoc = Tok.getLocation(); ConsumeToken(); assert(Tok.is(tok::colon) && "Expected colon."); @@ -3879,9 +4168,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ColonLoc = ConsumeToken(); } else if (Kind == OMPC_to || Kind == OMPC_from) { while (Tok.is(tok::identifier)) { - auto Modifier = - static_cast(getOpenMPSimpleClauseType( - Kind, PP.getSpelling(Tok), getLangOpts().OpenMP)); + auto Modifier = static_cast( + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts())); if (Modifier == OMPC_MOTION_MODIFIER_unknown) break; Data.MotionModifiers.push_back(Modifier); @@ -3951,6 +4239,23 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } + } else if (Kind == OMPC_adjust_args) { + // Handle adjust-op for adjust_args clause. + ColonProtectionRAIIObject ColonRAII(*this); + Data.ExtraModifier = getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "", + getLangOpts()); + Data.ExtraModifierLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_ADJUST_ARGS_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + if (Tok.is(tok::colon)) + Data.ColonLoc = Tok.getLocation(); + ExpectAndConsume(tok::colon, diag::warn_pragma_expected_colon, + "adjust-op"); + } } bool IsComma = @@ -3958,7 +4263,9 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || (Kind == OMPC_reduction && !InvalidReductionId) || (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || - (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown); + (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown) || + (Kind == OMPC_adjust_args && + Data.ExtraModifier != OMPC_ADJUST_ARGS_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 42072fe63fc..27e85012786 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -261,6 +261,68 @@ struct PragmaMSOptimizeHandler : public PragmaHandler { Token &FirstToken) override; }; +// "\#pragma fenv_access (on)". +struct PragmaMSFenvAccessHandler : public PragmaHandler { + PragmaMSFenvAccessHandler() : PragmaHandler("fenv_access") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, + Token &FirstToken) override { + StringRef PragmaName = FirstToken.getIdentifierInfo()->getName(); + if (!PP.getTargetInfo().hasStrictFP() && !PP.getLangOpts().ExpStrictFP) { + PP.Diag(FirstToken.getLocation(), diag::warn_pragma_fp_ignored) + << PragmaName; + return; + } + + Token Tok; + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << PragmaName; + return; + } + PP.Lex(Tok); // Consume the l_paren. + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); + return; + } + const IdentifierInfo *II = Tok.getIdentifierInfo(); + tok::OnOffSwitch OOS; + if (II->isStr("on")) { + OOS = tok::OOS_ON; + PP.Lex(Tok); + } else if (II->isStr("off")) { + OOS = tok::OOS_OFF; + PP.Lex(Tok); + } else { + PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_fenv_access); + return; + } + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << PragmaName; + return; + } + PP.Lex(Tok); // Consume the r_paren. + + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << PragmaName; + return; + } + + MutableArrayRef Toks( + PP.getPreprocessorAllocator().Allocate(1), 1); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_fenv_access_ms); + Toks[0].setLocation(FirstToken.getLocation()); + Toks[0].setAnnotationEndLoc(Tok.getLocation()); + Toks[0].setAnnotationValue( + reinterpret_cast(static_cast(OOS))); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject=*/false); + } +}; + struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { PragmaForceCUDAHostDeviceHandler(Sema &Actions) : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} @@ -389,6 +451,8 @@ void Parser::initializePragmaHandlers() { PP.AddPragmaHandler(MSIntrinsic.get()); MSOptimize = std::make_unique(); PP.AddPragmaHandler(MSOptimize.get()); + MSFenvAccess = std::make_unique(); + PP.AddPragmaHandler(MSFenvAccess.get()); } if (getLangOpts().CUDA) { @@ -496,6 +560,8 @@ void Parser::resetPragmaHandlers() { MSIntrinsic.reset(); PP.RemovePragmaHandler(MSOptimize.get()); MSOptimize.reset(); + PP.RemovePragmaHandler(MSFenvAccess.get()); + MSFenvAccess.reset(); } if (getLangOpts().CUDA) { @@ -701,7 +767,8 @@ void Parser::HandlePragmaFloatControl() { } void Parser::HandlePragmaFEnvAccess() { - assert(Tok.is(tok::annot_pragma_fenv_access)); + assert(Tok.is(tok::annot_pragma_fenv_access) || + Tok.is(tok::annot_pragma_fenv_access_ms)); tok::OnOffSwitch OOS = static_cast( reinterpret_cast(Tok.getAnnotationValue())); @@ -1592,6 +1659,15 @@ void Parser::HandlePragmaAttribute() { if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) return SkipToEnd(); + // FIXME: The practical usefulness of completion here is limited because + // we only get here if the line has balanced parens. + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + // FIXME: suppress completion of unsupported attributes? + Actions.CodeCompleteAttribute(AttributeCommonInfo::Syntax::AS_GNU); + return SkipToEnd(); + } + if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_pragma_attribute_expected_attribute_name); SkipToEnd(); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index ebfe048513b..bb8718671bb 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -374,8 +374,11 @@ Retry: return StmtError(); case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: ProhibitAttributes(Attrs); - Diag(Tok, diag::err_pragma_stdc_fenv_access_scope); + Diag(Tok, diag::err_pragma_file_or_compound_scope) + << (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS" + : "fenv_access"); ConsumeAnnotationToken(); return StmtEmpty(); @@ -955,6 +958,7 @@ void Parser::ParseCompoundStatementLeadingPragmas() { HandlePragmaFP(); break; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); break; case tok::annot_pragma_fenv_round: @@ -1338,20 +1342,36 @@ struct MisleadingIndentationChecker { /// 'if' '(' expression ')' statement 'else' statement /// [C++] 'if' '(' condition ')' statement /// [C++] 'if' '(' condition ')' statement 'else' statement +/// [C++23] 'if' '!' [opt] consteval compound-statement +/// [C++23] 'if' '!' [opt] consteval compound-statement 'else' statement /// StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { assert(Tok.is(tok::kw_if) && "Not an if stmt!"); SourceLocation IfLoc = ConsumeToken(); // eat the 'if'. bool IsConstexpr = false; + bool IsConsteval = false; + SourceLocation NotLocation; + SourceLocation ConstevalLoc; + if (Tok.is(tok::kw_constexpr)) { Diag(Tok, getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_constexpr_if : diag::ext_constexpr_if); IsConstexpr = true; ConsumeToken(); - } + } else { + if (Tok.is(tok::exclaim)) { + NotLocation = ConsumeToken(); + } - if (Tok.isNot(tok::l_paren)) { + if (Tok.is(tok::kw_consteval)) { + Diag(Tok, getLangOpts().CPlusPlus2b ? diag::warn_cxx20_compat_consteval_if + : diag::ext_consteval_if); + IsConsteval = true; + ConstevalLoc = ConsumeToken(); + } + } + if (!IsConsteval && (NotLocation.isValid() || Tok.isNot(tok::l_paren))) { Diag(Tok, diag::err_expected_lparen_after) << "if"; SkipUntil(tok::semi); return StmtError(); @@ -1378,15 +1398,18 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { Sema::ConditionResult Cond; SourceLocation LParen; SourceLocation RParen; - if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, - IsConstexpr ? Sema::ConditionKind::ConstexprIf - : Sema::ConditionKind::Boolean, - &LParen, &RParen)) - return StmtError(); - llvm::Optional ConstexprCondition; - if (IsConstexpr) - ConstexprCondition = Cond.getKnownValue(); + if (!IsConsteval) { + + if (ParseParenExprOrCondition(&InitStmt, Cond, IfLoc, + IsConstexpr ? Sema::ConditionKind::ConstexprIf + : Sema::ConditionKind::Boolean, + &LParen, &RParen)) + return StmtError(); + + if (IsConstexpr) + ConstexprCondition = Cond.getKnownValue(); + } bool IsBracedThen = Tok.is(tok::l_brace); @@ -1418,10 +1441,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { SourceLocation InnerStatementTrailingElseLoc; StmtResult ThenStmt; { + bool ShouldEnter = ConstexprCondition && !*ConstexprCondition; + Sema::ExpressionEvaluationContext Context = + Sema::ExpressionEvaluationContext::DiscardedStatement; + if (NotLocation.isInvalid() && IsConsteval) { + Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; + ShouldEnter = true; + } + EnterExpressionEvaluationContext PotentiallyDiscarded( - Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - Sema::ExpressionEvaluationContextRecord::EK_Other, - /*ShouldEnter=*/ConstexprCondition && !*ConstexprCondition); + Actions, Context, nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } @@ -1456,11 +1486,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { Tok.is(tok::l_brace)); MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc); + bool ShouldEnter = ConstexprCondition && *ConstexprCondition; + Sema::ExpressionEvaluationContext Context = + Sema::ExpressionEvaluationContext::DiscardedStatement; + if (NotLocation.isValid() && IsConsteval) { + Context = Sema::ExpressionEvaluationContext::ImmediateFunctionContext; + ShouldEnter = true; + } EnterExpressionEvaluationContext PotentiallyDiscarded( - Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, - Sema::ExpressionEvaluationContextRecord::EK_Other, - /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); + Actions, Context, nullptr, + Sema::ExpressionEvaluationContextRecord::EK_Other, ShouldEnter); ElseStmt = ParseStatement(); if (ElseStmt.isUsable()) @@ -1488,14 +1524,40 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { return StmtError(); } + if (IsConsteval) { + auto IsCompoundStatement = [](const Stmt *S) { + if (const auto *Outer = dyn_cast_or_null(S)) + S = Outer->getSubStmt(); + return isa_and_nonnull(S); + }; + + if (!IsCompoundStatement(ThenStmt.get())) { + Diag(ConstevalLoc, diag::err_expected_after) << "consteval" + << "{"; + return StmtError(); + } + if (!ElseStmt.isUnset() && !IsCompoundStatement(ElseStmt.get())) { + Diag(ElseLoc, diag::err_expected_after) << "else" + << "{"; + return StmtError(); + } + } + // Now if either are invalid, replace with a ';'. if (ThenStmt.isInvalid()) ThenStmt = Actions.ActOnNullStmt(ThenStmtLoc); if (ElseStmt.isInvalid()) ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc); - return Actions.ActOnIfStmt(IfLoc, IsConstexpr, LParen, InitStmt.get(), Cond, - RParen, ThenStmt.get(), ElseLoc, ElseStmt.get()); + IfStatementKind Kind = IfStatementKind::Ordinary; + if (IsConstexpr) + Kind = IfStatementKind::Constexpr; + else if (IsConsteval) + Kind = NotLocation.isValid() ? IfStatementKind::ConstevalNegated + : IfStatementKind::ConstevalNonNegated; + + return Actions.ActOnIfStmt(IfLoc, Kind, LParen, InitStmt.get(), Cond, RParen, + ThenStmt.get(), ElseLoc, ElseStmt.get()); } /// ParseSwitchStatement @@ -1767,6 +1829,7 @@ bool Parser::isForRangeIdentifier() { /// [C++] for-init-statement: /// [C++] expression-statement /// [C++] simple-declaration +/// [C++2b] alias-declaration /// /// [C++0x] for-range-declaration: /// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator @@ -1872,36 +1935,42 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { Diag(Tok, diag::ext_c99_variable_decl_in_for_loop); Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop); } - - // In C++0x, "for (T NS:a" might not be a typo for :: - bool MightBeForRangeStmt = getLangOpts().CPlusPlus; - ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); - - SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration( - DeclaratorContext::ForInit, DeclEnd, attrs, false, - MightBeForRangeStmt ? &ForRangeInfo : nullptr); - FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); - if (ForRangeInfo.ParsedForRangeDecl()) { - Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_for_range : diag::ext_for_range); - ForRangeInfo.LoopVar = FirstPart; - FirstPart = StmtResult(); - } else if (Tok.is(tok::semi)) { // for (int x = 4; - ConsumeToken(); - } else if ((ForEach = isTokIdentifier_in())) { - Actions.ActOnForEachDeclStmt(DG); - // ObjC: for (id x in expr) - ConsumeToken(); // consume 'in' - - if (Tok.is(tok::code_completion)) { - cutOffParsing(); - Actions.CodeCompleteObjCForCollection(getCurScope(), DG); - return StmtError(); - } - Collection = ParseExpression(); + DeclGroupPtrTy DG; + if (Tok.is(tok::kw_using)) { + DG = ParseAliasDeclarationInInitStatement(DeclaratorContext::ForInit, + attrs); } else { - Diag(Tok, diag::err_expected_semi_for); + // In C++0x, "for (T NS:a" might not be a typo for :: + bool MightBeForRangeStmt = getLangOpts().CPlusPlus; + ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); + + SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + DG = ParseSimpleDeclaration( + DeclaratorContext::ForInit, DeclEnd, attrs, false, + MightBeForRangeStmt ? &ForRangeInfo : nullptr); + FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); + if (ForRangeInfo.ParsedForRangeDecl()) { + Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_for_range + : diag::ext_for_range); + ForRangeInfo.LoopVar = FirstPart; + FirstPart = StmtResult(); + } else if (Tok.is(tok::semi)) { // for (int x = 4; + ConsumeToken(); + } else if ((ForEach = isTokIdentifier_in())) { + Actions.ActOnForEachDeclStmt(DG); + // ObjC: for (id x in expr) + ConsumeToken(); // consume 'in' + + if (Tok.is(tok::code_completion)) { + cutOffParsing(); + Actions.CodeCompleteObjCForCollection(getCurScope(), DG); + return StmtError(); + } + Collection = ParseExpression(); + } else { + Diag(Tok, diag::err_expected_semi_for); + } } } else { ProhibitAttributes(attrs); diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index e520151dcad..3e9ce8fd668 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -28,8 +28,8 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" using namespace clang; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 828b9b2277f..45af61a3926 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -248,7 +248,27 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); if (TemplateInfo.TemplateParams) DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); + + // Turn off usual access checking for template specializations and + // instantiations. + // C++20 [temp.spec] 13.9/6. + // This disables the access checking rules for function template explicit + // instantiation and explicit specialization: + // - parameter-list; + // - template-argument-list; + // - noexcept-specifier; + // - dynamic-exception-specifications (deprecated in C++11, removed since + // C++17). + bool IsTemplateSpecOrInst = + (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation || + TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization); + SuppressAccessChecks SAC(*this, IsTemplateSpecOrInst); + ParseDeclarator(DeclaratorInfo); + + if (IsTemplateSpecOrInst) + SAC.done(); + // Error parsing the declarator? if (!DeclaratorInfo.hasName()) { // If so, skip until the semi-colon or a }. @@ -886,10 +906,13 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { } else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater, tok::greatergreater, tok::ellipsis)) { Diag(Tok.getLocation(), diag::err_class_on_template_template_param) - << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") - : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); + << getLangOpts().CPlusPlus17 + << (Replace + ? FixItHint::CreateReplacement(Tok.getLocation(), "class") + : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); } else - Diag(Tok.getLocation(), diag::err_class_on_template_template_param); + Diag(Tok.getLocation(), diag::err_class_on_template_template_param) + << getLangOpts().CPlusPlus17; if (Replace) ConsumeToken(); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index c0bfbbde40a..be3823ecda0 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -483,6 +483,8 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement, ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement, CanBeForRangeDecl); + if (CanBeInitStatement && Tok.is(tok::kw_using)) + return ConditionOrInitStatement::InitStmtDecl; if (State.update(isCXXDeclarationSpecifier())) return State.result(); @@ -1101,9 +1103,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, } bool Parser::isTentativelyDeclared(IdentifierInfo *II) { - return std::find(TentativelyDeclaredIdentifiers.begin(), - TentativelyDeclaredIdentifiers.end(), II) - != TentativelyDeclaredIdentifiers.end(); + return llvm::is_contained(TentativelyDeclaredIdentifiers, II); } namespace { @@ -1637,6 +1637,7 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, case tok::kw___bf16: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_void: case tok::annot_decltype: #define GENERIC_IMAGE_TYPE(ImgType, Id) case tok::kw_##ImgType##_t: @@ -1751,6 +1752,7 @@ bool Parser::isCXXDeclarationSpecifierAType() { case tok::kw___bf16: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_void: case tok::kw___unknown_anytype: case tok::kw___auto_type: diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index c81dd03ffaa..11113fa1a06 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -785,6 +785,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, HandlePragmaFPContract(); return nullptr; case tok::annot_pragma_fenv_access: + case tok::annot_pragma_fenv_access_ms: HandlePragmaFEnvAccess(); return nullptr; case tok::annot_pragma_fenv_round: diff --git a/clang/lib/Rewrite/HTMLRewrite.cpp b/clang/lib/Rewrite/HTMLRewrite.cpp index 2f5f2734aa4..371557a624c 100644 --- a/clang/lib/Rewrite/HTMLRewrite.cpp +++ b/clang/lib/Rewrite/HTMLRewrite.cpp @@ -371,6 +371,7 @@ h1 { font-size:14pt } .msg { border-radius:5px } .msg { font-family:Helvetica, sans-serif; font-size:8pt } .msg { float:left } +.msg { position:relative } .msg { padding:0.25em 1ex 0.25em 1ex } .msg { margin-top:10px; margin-bottom:10px } .msg { font-weight:bold } @@ -391,7 +392,7 @@ h1 { font-size:14pt } .CodeInsertionHint { font-weight: bold; background-color: #10dd10 } .CodeRemovalHint { background-color:#de1010 } .CodeRemovalHint { border-bottom:1px solid #6F9DBE } -.selected{ background-color:orange !important; } +.msg.selected{ background-color:orange !important; } table.simpletable { padding: 5px; diff --git a/clang/lib/Rewrite/Rewriter.cpp b/clang/lib/Rewrite/Rewriter.cpp index 040e1c28425..3b06afc76e1 100644 --- a/clang/lib/Rewrite/Rewriter.cpp +++ b/clang/lib/Rewrite/Rewriter.cpp @@ -259,7 +259,7 @@ bool Rewriter::InsertText(SourceLocation Loc, StringRef Str, unsigned StartOffs = getLocationOffsetAndFileID(Loc, FID); SmallString<128> indentedStr; - if (indentNewLines && Str.find('\n') != StringRef::npos) { + if (indentNewLines && Str.contains('\n')) { StringRef MB = SourceMgr->getBufferData(FID); unsigned lineNo = SourceMgr->getLineNumber(FID, StartOffs) - 1; diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index aa2602c8d92..8544a4fccf4 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -497,8 +497,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { HasAbnormalEdge = true; continue; } - if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) - == B.succ_end()) { + if (!llvm::is_contained(B.succs(), &cfg->getExit())) { HasAbnormalEdge = true; continue; } @@ -1080,11 +1079,9 @@ namespace { while (!BlockQueue.empty()) { const CFGBlock *P = BlockQueue.front(); BlockQueue.pop_front(); - for (CFGBlock::const_succ_iterator I = P->succ_begin(), - E = P->succ_end(); - I != E; ++I) { - if (*I && ReachableBlocks.insert(*I).second) - BlockQueue.push_back(*I); + for (const CFGBlock *B : P->succs()) { + if (B && ReachableBlocks.insert(B).second) + BlockQueue.push_back(B); } } } @@ -1115,17 +1112,15 @@ namespace { continue; // Case label is preceded with a normal label, good. if (!ReachableBlocks.count(P)) { - for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(), - ElemEnd = P->rend(); - ElemIt != ElemEnd; ++ElemIt) { - if (Optional CS = ElemIt->getAs()) { + for (const CFGElement &Elem : llvm::reverse(*P)) { + if (Optional CS = Elem.getAs()) { if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { // Don't issue a warning for an unreachable fallthrough // attribute in template instantiations as it may not be // unreachable in all instantiations of the template. if (!IsTemplateInstantiation) S.Diag(AS->getBeginLoc(), - diag::warn_fallthrough_attr_unreachable); + diag::warn_unreachable_fallthrough_attr); markFallthroughVisited(AS); ++AnnotatedCnt; break; @@ -1202,12 +1197,9 @@ namespace { static const Stmt *getLastStmt(const CFGBlock &B) { if (const Stmt *Term = B.getTerminatorStmt()) return Term; - for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), - ElemEnd = B.rend(); - ElemIt != ElemEnd; ++ElemIt) { - if (Optional CS = ElemIt->getAs()) + for (const CFGElement &Elem : llvm::reverse(B)) + if (Optional CS = Elem.getAs()) return CS->getStmt(); - } // Workaround to detect a statement thrown out by CFGBuilder: // case X: {} case Y: // case X: ; case Y: @@ -1637,7 +1629,7 @@ public: private: static bool hasAlwaysUninitializedUse(const UsesVec* vec) { - return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) { + return llvm::any_of(*vec, [](const UninitUse &U) { return U.getKind() == UninitUse::Always || U.getKind() == UninitUse::AfterCall || U.getKind() == UninitUse::AfterDecl; @@ -2275,8 +2267,7 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( .setAlwaysAdd(Stmt::CStyleCastExprClass) .setAlwaysAdd(Stmt::DeclRefExprClass) .setAlwaysAdd(Stmt::ImplicitCastExprClass) - .setAlwaysAdd(Stmt::UnaryOperatorClass) - .setAlwaysAdd(Stmt::AttributedStmtClass); + .setAlwaysAdd(Stmt::UnaryOperatorClass); } // Install the logical handler. diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 3ab2a18f5e8..6c47cedfccf 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -82,6 +82,7 @@ bool CodeCompletionContext::wantConstructorResults() const { case CCC_ObjCInterfaceName: case CCC_ObjCCategoryName: case CCC_IncludedFile: + case CCC_Attribute: return false; } @@ -161,6 +162,8 @@ StringRef clang::getCompletionKindString(CodeCompletionContext::Kind Kind) { return "ObjCCategoryName"; case CCKind::CCC_IncludedFile: return "IncludedFile"; + case CCKind::CCC_Attribute: + return "Attribute"; case CCKind::CCC_Recovery: return "Recovery"; } @@ -384,14 +387,13 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { SmallString<128> S; llvm::raw_svector_ostream OS(S); bool First = true; - for (unsigned I = Contexts.size(); I != 0; --I) { + for (const DeclContext *CurDC : llvm::reverse(Contexts)) { if (First) First = false; else { OS << "::"; } - const DeclContext *CurDC = Contexts[I - 1]; if (const auto *CatImpl = dyn_cast(CurDC)) CurDC = CatImpl->getCategoryDecl(); diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 72d9ea6dd3b..4405f29f3d9 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -358,6 +358,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_Fract: case TST_Float16: case TST_float128: + case TST_ibm128: case TST_enum: case TST_error: case TST_float: @@ -558,6 +559,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_fract: return "_Fract"; case DeclSpec::TST_float16: return "_Float16"; case DeclSpec::TST_float128: return "__float128"; + case DeclSpec::TST_ibm128: return "__ibm128"; case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool"; case DeclSpec::TST_decimal32: return "_Decimal32"; case DeclSpec::TST_decimal64: return "_Decimal64"; @@ -631,8 +633,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, case SCS_extern: case SCS_private_extern: case SCS_static: - if (S.getLangOpts().OpenCLVersion < 120 && - !S.getLangOpts().OpenCLCPlusPlus) { + if (S.getLangOpts().getOpenCLCompatibleVersion() < 120) { DiagID = diag::err_opencl_unknown_type_specifier; PrevSpec = getSpecifierName(SC); return true; @@ -1155,6 +1156,17 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { + // No vector long long without VSX (or ZVector). + if ((getTypeSpecWidth() == TypeSpecifierWidth::LongLong) && + !S.Context.getTargetInfo().hasFeature("vsx") && + !S.getLangOpts().ZVector) + S.Diag(TSWRange.getBegin(), diag::err_invalid_vector_long_long_decl_spec); + + // No vector __int128 prior to Power8. + if ((TypeSpecType == TST_int128) && + !S.Context.getTargetInfo().hasFeature("power8-vector")) + S.Diag(TSTLoc, diag::err_invalid_vector_int128_decl_spec); + if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (getTypeSpecSign() != TypeSpecifierSign::Unspecified) { @@ -1183,13 +1195,6 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { S.Diag(TSWRange.getBegin(), diag::err_invalid_vector_bool_decl_spec) << getSpecifierName(getTypeSpecWidth()); - // vector bool long long requires VSX support or ZVector. - if ((getTypeSpecWidth() == TypeSpecifierWidth::LongLong) && - (!S.Context.getTargetInfo().hasFeature("vsx")) && - (!S.Context.getTargetInfo().hasFeature("power8-vector")) && - !S.getLangOpts().ZVector) - S.Diag(TSTLoc, diag::err_invalid_vector_long_long_decl_spec); - // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecType == TST_int128) || @@ -1212,13 +1217,15 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { !S.Context.getTargetInfo().hasFeature("arch12")) S.Diag(TSTLoc, diag::err_invalid_vector_float_decl_spec); } else if (getTypeSpecWidth() == TypeSpecifierWidth::Long) { - // vector long is unsupported for ZVector and deprecated for AltiVec. + // Vector long is unsupported for ZVector, or without VSX, and deprecated + // for AltiVec. // It has also been historically deprecated on AIX (as an alias for // "vector int" in both 32-bit and 64-bit modes). It was then made // unsupported in the Clang-based XL compiler since the deprecated type // has a number of conflicting semantics and continuing to support it // is a disservice to users. if (S.getLangOpts().ZVector || + !S.Context.getTargetInfo().hasFeature("vsx") || S.Context.getTargetInfo().getTriple().isOSAIX()) S.Diag(TSWRange.getBegin(), diag::err_invalid_vector_long_decl_spec); else @@ -1300,8 +1307,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (!S.getLangOpts().CPlusPlus) S.Diag(TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double && - TypeSpecType != TST_float128) { - // FIXME: _Float16, __fp16? + TypeSpecType != TST_float128 && TypeSpecType != TST_float16 && + TypeSpecType != TST_ibm128) { + // FIXME: __fp16? S.Diag(TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecComplex = TSC_unspecified; diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 999c2a48145..94f39e1eea6 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -377,11 +377,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, case Stmt::IfStmtClass: { IfStmt *IS = cast(S); - if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck())) + if (!(IS->isConstexpr() || IS->isConsteval() || + IS->isObjCAvailabilityCheck())) break; - unsigned Diag = IS->isConstexpr() ? diag::note_protected_by_constexpr_if - : diag::note_protected_by_if_available; + unsigned Diag = diag::note_protected_by_if_available; + if (IS->isConstexpr()) + Diag = diag::note_protected_by_constexpr_if; + else if (IS->isConsteval()) + Diag = diag::note_protected_by_consteval_if; if (VarDecl *Var = IS->getConditionVariable()) BuildScopeInformation(Var, ParentScope); @@ -389,7 +393,9 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // Cannot jump into the middle of the condition. unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getBeginLoc())); - BuildScopeInformation(IS->getCond(), NewParentScope); + + if (!IS->isConsteval()) + BuildScopeInformation(IS->getCond(), NewParentScope); // Jumps into either arm of an 'if constexpr' are not allowed. NewParentScope = Scopes.size(); @@ -487,8 +493,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, } // Jump from the catch to the finally or try is not valid. - for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *AC = AT->getCatchStmt(I); + for (ObjCAtCatchStmt *AC : AT->catch_stmts()) { unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index cd704fe395a..8cf7ec58eff 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -83,6 +83,30 @@ def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_imag def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">; def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">; +def FuncExtOpenCLCPipes : FunctionExtension<"__opencl_c_pipes">; +def FuncExtOpenCLCWGCollectiveFunctions : FunctionExtension<"__opencl_c_work_group_collective_functions">; +def FuncExtFloatAtomicsFp16GlobalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store">; +def FuncExtFloatAtomicsFp16LocalLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_load_store">; +def FuncExtFloatAtomicsFp16GenericLoadStore : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_load_store __opencl_c_ext_fp16_local_atomic_load_store">; +def FuncExtFloatAtomicsFp16GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_add">; +def FuncExtFloatAtomicsFp32GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_add">; +def FuncExtFloatAtomicsFp64GlobalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_add">; +def FuncExtFloatAtomicsFp16LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add">; +def FuncExtFloatAtomicsFp32LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add">; +def FuncExtFloatAtomicsFp64LocalAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add">; +def FuncExtFloatAtomicsFp16GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_add __opencl_c_ext_fp16_global_atomic_add">; +def FuncExtFloatAtomicsFp32GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_add __opencl_c_ext_fp32_global_atomic_add">; +def FuncExtFloatAtomicsFp64GenericAdd : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_add __opencl_c_ext_fp64_global_atomic_add">; +def FuncExtFloatAtomicsFp16GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_global_atomic_min_max">; +def FuncExtFloatAtomicsFp32GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_global_atomic_min_max">; +def FuncExtFloatAtomicsFp64GlobalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_global_atomic_min_max">; +def FuncExtFloatAtomicsFp16LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max">; +def FuncExtFloatAtomicsFp32LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max">; +def FuncExtFloatAtomicsFp64LocalMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max">; +def FuncExtFloatAtomicsFp16GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp16_local_atomic_min_max __opencl_c_ext_fp16_global_atomic_min_max">; +def FuncExtFloatAtomicsFp32GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp32_local_atomic_min_max __opencl_c_ext_fp32_global_atomic_min_max">; +def FuncExtFloatAtomicsFp64GenericMinMax : FunctionExtension<"cl_ext_float_atomics __opencl_c_ext_fp64_local_atomic_min_max __opencl_c_ext_fp64_global_atomic_min_max">; + // Not a real extension, but a workaround to add C++ for OpenCL specific builtins. def FuncExtOpenCLCxx : FunctionExtension<"__cplusplus">; @@ -347,6 +371,7 @@ def AtomicLong : Type<"atomic_long", QualType<"Context.getAtomicType( def AtomicULong : Type<"atomic_ulong", QualType<"Context.getAtomicType(Context.UnsignedLongTy)">>; def AtomicFloat : Type<"atomic_float", QualType<"Context.getAtomicType(Context.FloatTy)">>; def AtomicDouble : Type<"atomic_double", QualType<"Context.getAtomicType(Context.DoubleTy)">>; +def AtomicHalf : Type<"atomic_half", QualType<"Context.getAtomicType(Context.HalfTy)">>; def AtomicIntPtr : Type<"atomic_intptr_t", QualType<"Context.getAtomicType(Context.getIntPtrType())">>; def AtomicUIntPtr : Type<"atomic_uintptr_t", QualType<"Context.getAtomicType(Context.getUIntPtrType())">>; def AtomicSize : Type<"atomic_size_t", QualType<"Context.getAtomicType(Context.getSizeType())">>; @@ -543,9 +568,10 @@ foreach name = ["fma", "mad"] in { def : Builtin; } -// --- Version dependent --- -let MaxVersion = CL20 in { - foreach AS = [GlobalAS, LocalAS, PrivateAS] in { +// The following math builtins take pointer arguments. Which overloads are +// available depends on whether the generic address space feature is enabled. +multiclass MathWithPointer addrspaces> { + foreach AS = addrspaces in { foreach name = ["fract", "modf", "sincos"] in { def : Builtin]>; } @@ -561,19 +587,12 @@ let MaxVersion = CL20 in { } } } + +let MaxVersion = CL20 in { + defm : MathWithPointer<[GlobalAS, LocalAS, PrivateAS]>; +} let MinVersion = CL20 in { - foreach name = ["fract", "modf", "sincos"] in { - def : Builtin]>; - } - foreach name = ["frexp", "lgamma_r"] in { - foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { - def : Builtin]>; - } } - foreach name = ["remquo"] in { - foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { - def : Builtin]>; - } - } + defm : MathWithPointer<[GenericAS]>; } // --- Table 9 --- @@ -783,10 +802,8 @@ foreach name = ["select"] in { // OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions // OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s5.1.6 and s6.1.6 - Vector Data Load and Store Functions // --- Table 15 --- -// Variants for OpenCL versions below 2.0, using pointers to the global, local -// and private address spaces. -let MaxVersion = CL20 in { - foreach AS = [GlobalAS, LocalAS, PrivateAS] in { +multiclass VloadVstore addrspaces, bit defStores> { + foreach AS = addrspaces in { foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vload" # VSize] in { def : Builtin, Size, PointerType, AS>]>; @@ -801,148 +818,68 @@ let MaxVersion = CL20 in { def : Builtin, Size, PointerType, AS>]>; def : Builtin, Size, PointerType, AS>]>; } - foreach name = ["vstore" # VSize] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - } - foreach name = ["vloada_half" # VSize] in { - def : Builtin, Size, PointerType, AS>]>; - } - foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - foreach name = ["vstorea_half" # VSize # rnd] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - } - } - } - } -} -// Variants for OpenCL versions above 2.0, using pointers to the generic -// address space. -let MinVersion = CL20 in { - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vload" # VSize] in { - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - def : Builtin, Size, PointerType, GenericAS>]>; - } - foreach name = ["vstore" # VSize] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - } - foreach name = ["vloada_half" # VSize] in { - def : Builtin, Size, PointerType, GenericAS>]>; - } - foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - foreach name = ["vstorea_half" # VSize # rnd] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - } - } - } -} -// Variants using pointers to the constant address space. -foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vload" # VSize] in { - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - def : Builtin, Size, PointerType, ConstantAS>]>; - } - foreach name = ["vloada_half" # VSize] in { - def : Builtin, Size, PointerType, ConstantAS>]>; - } -} -let MaxVersion = CL20 in { - foreach AS = [GlobalAS, LocalAS, PrivateAS] in { - def : Builtin<"vload_half", [Float, Size, PointerType, AS>]>; - def : Builtin<"vloada_half", [Float, Size, PointerType, AS>]>; - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vload_half" # VSize] in { - def : Builtin, Size, PointerType, AS>]>; - } - } - foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in { - def : Builtin]>; - def : Builtin]>; - } - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vstore_half" # VSize # rnd] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; - } - } - } - } -} -let MinVersion = CL20 in { - foreach AS = [GenericAS] in { - def : Builtin<"vload_half", [Float, Size, PointerType, AS>]>; - def : Builtin<"vloada_half", [Float, Size, PointerType, AS>]>; - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vload_half" # VSize] in { - def : Builtin, Size, PointerType, AS>]>; - } - } - foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in { - def : Builtin]>; - def : Builtin]>; - } - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vstore_half" # VSize # rnd] in { - def : Builtin, Size, PointerType]>; - def : Builtin, Size, PointerType]>; + if defStores then { + foreach name = ["vstore" # VSize] in { + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; } } } } } -foreach AS = [ConstantAS] in { - def : Builtin<"vload_half", [Float, Size, PointerType, AS>]>; - def : Builtin<"vloada_half", [Float, Size, PointerType, AS>]>; - foreach VSize = [2, 3, 4, 8, 16] in { - foreach name = ["vload_half" # VSize] in { - def : Builtin, Size, PointerType, AS>]>; +let MaxVersion = CL20 in { + defm : VloadVstore<[GlobalAS, LocalAS, PrivateAS], 1>; +} +let MinVersion = CL20 in { + defm : VloadVstore<[GenericAS], 1>; +} +// vload with constant address space is available regardless of version. +defm : VloadVstore<[ConstantAS], 0>; + +multiclass VloadVstoreHalf addrspaces, bit defStores> { + foreach AS = addrspaces in { + def : Builtin<"vload_half", [Float, Size, PointerType, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload_half" # VSize, "vloada_half" # VSize] in { + def : Builtin, Size, PointerType, AS>]>; + } + } + if defStores then { + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + foreach name = ["vstore_half" # rnd] in { + def : Builtin]>; + def : Builtin]>; + } + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vstore_half" # VSize # rnd, "vstorea_half" # VSize # rnd] in { + def : Builtin, Size, PointerType]>; + def : Builtin, Size, PointerType]>; + } + } + } } } } +let MaxVersion = CL20 in { + defm : VloadVstoreHalf<[GlobalAS, LocalAS, PrivateAS], 1>; +} +let MinVersion = CL20 in { + defm : VloadVstoreHalf<[GenericAS], 1>; +} +// vload with constant address space is available regardless of version. +defm : VloadVstoreHalf<[ConstantAS], 0>; + // OpenCL v3.0 s6.15.8 - Synchronization Functions. def : Builtin<"barrier", [Void, MemFenceFlags], Attr.Convergent>; let MinVersion = CL20 in { @@ -1177,6 +1114,218 @@ let MinVersion = CL20 in { [Bool, PointerType, GenericAS>, MemoryOrder, MemoryScope]>; } +// The functionality added by cl_ext_float_atomics extension +let MinVersion = CL20 in { + let Extension = FuncExtFloatAtomicsFp16GlobalLoadStore in { + def : Builtin<"atomic_store", + [Void, PointerType, GlobalAS>, AtomicHalf]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, GlobalAS>, AtomicHalf, MemoryOrder]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, GlobalAS>, AtomicHalf, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_load", + [Half, PointerType, GlobalAS>]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, GlobalAS>, MemoryOrder]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, GlobalAS>, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_exchange", + [Half, PointerType, GlobalAS>, Half]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16LocalLoadStore in { + def : Builtin<"atomic_store", + [Void, PointerType, LocalAS>, AtomicHalf]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, LocalAS>, AtomicHalf, MemoryOrder]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, LocalAS>, AtomicHalf, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_load", + [Half, PointerType, LocalAS>]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, LocalAS>, MemoryOrder]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, LocalAS>, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_exchange", + [Half, PointerType, LocalAS>, Half]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16GenericLoadStore in { + def : Builtin<"atomic_store", + [Void, PointerType, GenericAS>, AtomicHalf]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, GenericAS>, AtomicHalf, MemoryOrder]>; + def : Builtin<"atomic_store_explicit", + [Void, PointerType, GenericAS>, AtomicHalf, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_load", + [Half, PointerType, GenericAS>]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, GenericAS>, MemoryOrder]>; + def : Builtin<"atomic_load_explicit", + [Half, PointerType, GenericAS>, MemoryOrder, MemoryScope]>; + def : Builtin<"atomic_exchange", + [Half, PointerType, GenericAS>, Half]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_exchange_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder, MemoryScope]>; + } + foreach ModOp = ["add", "sub"] in { + let Extension = FuncExtFloatAtomicsFp16GlobalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, GlobalAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32GlobalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, GlobalAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GlobalAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GlobalAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64GlobalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, GlobalAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GlobalAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GlobalAS>, Double, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16LocalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, LocalAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32LocalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, LocalAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, LocalAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, LocalAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64LocalAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, LocalAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, LocalAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, LocalAS>, Double, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16GenericAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, GenericAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32GenericAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, GenericAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GenericAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GenericAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64GenericAdd in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, GenericAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GenericAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GenericAS>, Double, MemoryOrder, MemoryScope]>; + } + } + foreach ModOp = ["min", "max"] in { + let Extension = FuncExtFloatAtomicsFp16GlobalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, GlobalAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GlobalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32GlobalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, GlobalAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GlobalAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GlobalAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64GlobalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, GlobalAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GlobalAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GlobalAS>, Double, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16LocalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, LocalAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, LocalAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32LocalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, LocalAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, LocalAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, LocalAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64LocalMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, LocalAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, LocalAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, LocalAS>, Double, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp16GenericMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Half, PointerType, GenericAS>, Half]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Half, PointerType, GenericAS>, Half, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp32GenericMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Float, PointerType, GenericAS>, Float]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GenericAS>, Float, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Float, PointerType, GenericAS>, Float, MemoryOrder, MemoryScope]>; + } + let Extension = FuncExtFloatAtomicsFp64GenericMinMax in { + def : Builtin<"atomic_fetch_" # ModOp, + [Double, PointerType, GenericAS>, Double]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GenericAS>, Double, MemoryOrder]>; + def : Builtin<"atomic_fetch_" # ModOp # "_explicit", + [Double, PointerType, GenericAS>, Double, MemoryOrder, MemoryScope]>; + } + } +} + //-------------------------------------------------------------------- // OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions // --- Table 19 --- @@ -1370,7 +1519,7 @@ foreach aQual = ["WO", "RW"] in { //-------------------------------------------------------------------- // OpenCL v2.0 s6.13.15 - Work-group Functions // --- Table 26 --- -let MinVersion = CL20 in { +let Extension = FuncExtOpenCLCWGCollectiveFunctions in { foreach name = ["work_group_all", "work_group_any"] in { def : Builtin; } @@ -1395,7 +1544,9 @@ let MinVersion = CL20 in { // --- Table 28 --- // Builtins taking pipe arguments are defined in Builtins.def -def : Builtin<"is_valid_reserve_id", [Bool, ReserveId]>; +let Extension = FuncExtOpenCLCPipes in { + def : Builtin<"is_valid_reserve_id", [Bool, ReserveId]>; +} // --- Table 29 --- // Defined in Builtins.def diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index ed03b0c7f68..045847d0ce0 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -145,6 +145,10 @@ const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { return DefaultParsedAttrInfo; } +ArrayRef ParsedAttrInfo::getAllBuiltin() { + return llvm::makeArrayRef(AttrInfoMap); +} + unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } unsigned ParsedAttr::getMaxArgs() const { @@ -180,7 +184,10 @@ void ParsedAttr::getMatchRules( } bool ParsedAttr::diagnoseLangOpts(Sema &S) const { - return getInfo().diagLangOpts(S, *this); + if (getInfo().acceptsLangOpts(S.getLangOpts())) + return true; + S.Diag(getLoc(), diag::warn_attribute_ignored) << *this; + return false; } bool ParsedAttr::isTargetSpecificAttr() const { diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index 4857346018a..cc7de16de2f 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -37,7 +37,7 @@ void FunctionScopeInfo::Clear() { ObjCIsSecondaryInit = false; ObjCWarnForNoInitDelegation = false; FirstReturnLoc = SourceLocation(); - FirstCXXTryLoc = SourceLocation(); + FirstCXXOrObjCTryLoc = SourceLocation(); FirstSEHTryLoc = SourceLocation(); // Coroutine state diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 5d3de06e957..a2b8f475aa8 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -169,7 +169,7 @@ public: } // end namespace clang const unsigned Sema::MaxAlignmentExponent; -const unsigned Sema::MaximumAlignment; +const uint64_t Sema::MaximumAlignment; Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) @@ -324,10 +324,11 @@ void Sema::Initialize() { Context.getTargetInfo().getSupportedOpenCLOpts(), getLangOpts()); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); - if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) { + if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); addImplicitTypedef("queue_t", Context.OCLQueueTy); - addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy); + if (getLangOpts().OpenCLPipes) + addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy); addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy)); addImplicitTypedef("atomic_uint", Context.getAtomicType(Context.UnsignedIntTy)); @@ -366,6 +367,11 @@ void Sema::Initialize() { AddPointerSizeDependentTypes(); } + if (getOpenCLOptions().isSupported("cl_khr_fp16", getLangOpts())) { + auto AtomicHalfT = Context.getAtomicType(Context.HalfTy); + addImplicitTypedef("atomic_half", AtomicHalfT); + } + std::vector Atomic64BitTypes; if (getOpenCLOptions().isSupported("cl_khr_int64_base_atomics", getLangOpts()) && @@ -402,13 +408,10 @@ void Sema::Initialize() { #include "clang/Basic/AArch64SVEACLETypes.def" } - if (Context.getTargetInfo().getTriple().isPPC64() && - Context.getTargetInfo().hasFeature("paired-vector-memops")) { - if (Context.getTargetInfo().hasFeature("mma")) { + if (Context.getTargetInfo().getTriple().isPPC64()) { #define PPC_VECTOR_MMA_TYPE(Name, Id, Size) \ addImplicitTypedef(#Name, Context.Id##Ty); #include "clang/Basic/PPCTypes.def" - } #define PPC_VECTOR_VSX_TYPE(Name, Id, Size) \ addImplicitTypedef(#Name, Context.Id##Ty); #include "clang/Basic/PPCTypes.def" @@ -1429,7 +1432,7 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { LangAS Sema::getDefaultCXXMethodAddrSpace() const { if (getLangOpts().OpenCL) - return LangAS::opencl_generic; + return getASTContext().getDefaultOpenCLPointeeAddrSpace(); return LangAS::Default; } @@ -1851,8 +1854,8 @@ Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID, return DB; } -void Sema::checkDeviceDecl(ValueDecl *D, SourceLocation Loc) { - if (isUnevaluatedContext()) +void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { + if (isUnevaluatedContext() || Ty.isNull()) return; Decl *C = cast(getCurLexicalContext()); @@ -1871,46 +1874,114 @@ void Sema::checkDeviceDecl(ValueDecl *D, SourceLocation Loc) { // Try to associate errors with the lexical context, if that is a function, or // the value declaration otherwise. - FunctionDecl *FD = - isa(C) ? cast(C) : dyn_cast(D); - auto CheckType = [&](QualType Ty) { + FunctionDecl *FD = isa(C) ? cast(C) + : dyn_cast_or_null(D); + + auto CheckDeviceType = [&](QualType Ty) { if (Ty->isDependentType()) return; if (Ty->isExtIntType()) { if (!Context.getTargetInfo().hasExtIntType()) { - targetDiag(Loc, diag::err_device_unsupported_type, FD) - << D << false /*show bit size*/ << 0 /*bitsize*/ + PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); + if (D) + PD << D; + else + PD << "expression"; + targetDiag(Loc, PD, FD) + << false /*show bit size*/ << 0 /*bitsize*/ << false /*return*/ << Ty << Context.getTargetInfo().getTriple().str(); } return; } + // Check if we are dealing with two 'long double' but with different + // semantics. + bool LongDoubleMismatched = false; + if (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128) { + const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(Ty); + if ((&Sem != &llvm::APFloat::PPCDoubleDouble() && + !Context.getTargetInfo().hasFloat128Type()) || + (&Sem == &llvm::APFloat::PPCDoubleDouble() && + !Context.getTargetInfo().hasIbm128Type())) + LongDoubleMismatched = true; + } + if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || - ((Ty->isFloat128Type() || - (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) && - !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isFloat128Type() && !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isIbm128Type() && !Context.getTargetInfo().hasIbm128Type()) || (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && - !Context.getTargetInfo().hasInt128Type())) { - if (targetDiag(Loc, diag::err_device_unsupported_type, FD) - << D << true /*show bit size*/ + !Context.getTargetInfo().hasInt128Type()) || + LongDoubleMismatched) { + PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); + if (D) + PD << D; + else + PD << "expression"; + + if (targetDiag(Loc, PD, FD) + << true /*show bit size*/ << static_cast(Context.getTypeSize(Ty)) << Ty - << Context.getTargetInfo().getTriple().str()) - D->setInvalidDecl(); - targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; + << false /*return*/ << Context.getTargetInfo().getTriple().str()) { + if (D) + D->setInvalidDecl(); + } + if (D) + targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } }; - QualType Ty = D->getType(); - CheckType(Ty); + auto CheckType = [&](QualType Ty, bool IsRetTy = false) { + if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) + CheckDeviceType(Ty); + QualType UnqualTy = Ty.getCanonicalType().getUnqualifiedType(); + const TargetInfo &TI = Context.getTargetInfo(); + if (!TI.hasLongDoubleType() && UnqualTy == Context.LongDoubleTy) { + PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); + if (D) + PD << D; + else + PD << "expression"; + + if (Diag(Loc, PD, FD) + << false /*show bit size*/ << 0 << Ty << false /*return*/ + << Context.getTargetInfo().getTriple().str()) { + if (D) + D->setInvalidDecl(); + } + if (D) + targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; + } + + bool IsDouble = UnqualTy == Context.DoubleTy; + bool IsFloat = UnqualTy == Context.FloatTy; + if (IsRetTy && !TI.hasFPReturn() && (IsDouble || IsFloat)) { + PartialDiagnostic PD = PDiag(diag::err_target_unsupported_type); + if (D) + PD << D; + else + PD << "expression"; + + if (Diag(Loc, PD, FD) + << false /*show bit size*/ << 0 << Ty << true /*return*/ + << Context.getTargetInfo().getTriple().str()) { + if (D) + D->setInvalidDecl(); + } + if (D) + targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; + } + }; + + CheckType(Ty); if (const auto *FPTy = dyn_cast(Ty)) { for (const auto &ParamTy : FPTy->param_types()) CheckType(ParamTy); - CheckType(FPTy->getReturnType()); + CheckType(FPTy->getReturnType(), /*IsRetTy=*/true); } if (const auto *FNPTy = dyn_cast(Ty)) - CheckType(FNPTy->getReturnType()); + CheckType(FNPTy->getReturnType(), /*IsRetTy=*/true); } /// Looks through the macro-expansion chain for the given @@ -2009,7 +2080,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) { Expr *VarRef = new (S.Context) DeclRefExpr(S.Context, VD, false, T, VK_LValue, Loc); ExprResult Result; - auto IE = InitializedEntity::InitializeBlock(Loc, T, false); + auto IE = InitializedEntity::InitializeBlock(Loc, T); if (S.getLangOpts().CPlusPlus2b) { auto *E = ImplicitCastExpr::Create(S.Context, T, CK_NoOp, VarRef, nullptr, VK_XValue, FPOptionsOverride()); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 580305c1110..3f7b387ec92 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -140,7 +140,7 @@ struct EffectiveContext { bool includesClass(const CXXRecordDecl *R) const { R = R->getCanonicalDecl(); - return llvm::find(Records, R) != Records.end(); + return llvm::is_contained(Records, R); } /// Retrieves the innermost "useful" context. Can be null if we're diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index fe8f02f0236..100f8e36a9b 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -340,7 +340,7 @@ void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, // pack(0) is like pack(), which just works out since that is what // we use 0 for in PackAttr. - if (Alignment->isTypeDependent() || Alignment->isValueDependent() || !Val || + if (Alignment->isTypeDependent() || !Val || !(*Val == 0 || Val->isPowerOf2()) || Val->getZExtValue() > 16) { Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); return; // Ignore @@ -475,8 +475,9 @@ void Sema::ActOnPragmaFloatControl(SourceLocation Loc, PragmaFloatControlKind Value) { FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) && - !(CurContext->isTranslationUnit()) && !CurContext->isNamespace()) { - // Push and pop can only occur at file or namespace scope. + !CurContext->getRedeclContext()->isFileContext()) { + // Push and pop can only occur at file or namespace scope, or within a + // language linkage declaration. Diag(Loc, diag::err_pragma_fc_pp_scope); return; } diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp index bb704b1066c..dc15c87cb71 100644 --- a/clang/lib/Sema/SemaAvailability.cpp +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -57,7 +57,7 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, /// \param D The declaration to check. /// \param Message If non-null, this will be populated with the message from /// the availability attribute that is selected. -/// \param ClassReceiver If we're checking the the method of a class message +/// \param ClassReceiver If we're checking the method of a class message /// send, the class. Otherwise nullptr. static std::pair ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, @@ -268,7 +268,7 @@ tryParseObjCMethodName(StringRef Name, SmallVectorImpl &SlotNames, for (StringRef S : SlotNames) { if (S.empty()) continue; - if (!isValidIdentifier(S, AllowDollar)) + if (!isValidAsciiIdentifier(S, AllowDollar)) return None; } return NumParams; @@ -630,8 +630,7 @@ public: const CompoundStmt *Scope) { LastDeclUSEFinder Visitor; Visitor.D = D; - for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) { - const Stmt *S = *I; + for (const Stmt *S : llvm::reverse(Scope->body())) { if (!Visitor.TraverseStmt(const_cast(S))) return S; } diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 75364c10c15..840b3daae63 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -878,8 +878,13 @@ void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, diag::err_capture_bad_target, Callee, *this) << Capture.getVariable(); } else if (Capture.isThisCapture()) { + // Capture of this pointer is allowed since this pointer may be pointing to + // managed memory which is accessible on both device and host sides. It only + // results in invalid memory access if this pointer points to memory not + // accessible on device side. SemaDiagnosticBuilder(DiagKind, Capture.getLocation(), - diag::err_capture_bad_target_this_ptr, Callee, *this); + diag::warn_maybe_capture_bad_target_this_ptr, Callee, + *this); } return; } diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 1c8f6329bd6..c4826b5a6e8 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -442,7 +442,7 @@ bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, namespace { // Callback to only accept typo corrections that can be a valid C++ member -// intializer: either a non-static field member or a base class. +// initializer: either a non-static field member or a base class. class NestedNameSpecifierValidatorCCC final : public CorrectionCandidateCallback { public: @@ -865,7 +865,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, assert(DS.getTypeSpecType() == DeclSpec::TST_decltype); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); if (T.isNull()) return true; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index cac43075f86..7ef1732496c 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -1313,7 +1313,9 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // lvalue-to-rvalue, array-to-pointer, function-to-pointer, and boolean // conversions, subject to further restrictions. // Also, C++ 5.2.9p1 forbids casting away constness, which makes reversal - // of qualification conversions impossible. + // of qualification conversions impossible. (In C++20, adding an array bound + // would be the reverse of a qualification conversion, but adding permission + // to add an array bound in a static_cast is a wording oversight.) // In the CStyle case, the earlier attempt to const_cast should have taken // care of reverse qualification conversions. @@ -2637,6 +2639,19 @@ bool Sema::ShouldSplatAltivecScalarInCast(const VectorType *VecTy) { return false; } +bool Sema::CheckAltivecInitFromScalar(SourceRange R, QualType VecTy, + QualType SrcTy) { + bool SrcCompatGCC = this->getLangOpts().getAltivecSrcCompat() == + LangOptions::AltivecSrcCompatKind::GCC; + if (this->getLangOpts().AltiVec && SrcCompatGCC) { + this->Diag(R.getBegin(), + diag::err_invalid_conversion_between_vector_and_integer) + << VecTy << SrcTy << R; + return true; + } + return false; +} + void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { assert(Self.getLangOpts().CPlusPlus); @@ -2690,7 +2705,12 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, } // AltiVec vector initialization with a single literal. - if (const VectorType *vecTy = DestType->getAs()) + if (const VectorType *vecTy = DestType->getAs()) { + if (Self.CheckAltivecInitFromScalar(OpRange, DestType, + SrcExpr.get()->getType())) { + SrcExpr = ExprError(); + return; + } if (Self.ShouldSplatAltivecScalarInCast(vecTy) && (SrcExpr.get()->getType()->isIntegerType() || SrcExpr.get()->getType()->isFloatingType())) { @@ -2698,6 +2718,7 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, SrcExpr = Self.prepareVectorSplat(DestType, SrcExpr.get()); return; } + } // C++ [expr.cast]p5: The conversions performed by // - a const_cast, @@ -2976,6 +2997,10 @@ void CastOperation::CheckCStyleCast() { } if (const VectorType *DestVecTy = DestType->getAs()) { + if (Self.CheckAltivecInitFromScalar(OpRange, DestType, SrcType)) { + SrcExpr = ExprError(); + return; + } if (Self.ShouldSplatAltivecScalarInCast(DestVecTy) && (SrcType->isIntegerType() || SrcType->isFloatingType())) { Kind = CK_VectorSplat; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index de75c10417e..6ffd2096cbc 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -408,6 +408,64 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { namespace { +class ScanfDiagnosticFormatHandler + : public analyze_format_string::FormatStringHandler { + // Accepts the argument index (relative to the first destination index) of the + // argument whose size we want. + using ComputeSizeFunction = + llvm::function_ref(unsigned)>; + + // Accepts the argument index (relative to the first destination index), the + // destination size, and the source size). + using DiagnoseFunction = + llvm::function_ref; + + ComputeSizeFunction ComputeSizeArgument; + DiagnoseFunction Diagnose; + +public: + ScanfDiagnosticFormatHandler(ComputeSizeFunction ComputeSizeArgument, + DiagnoseFunction Diagnose) + : ComputeSizeArgument(ComputeSizeArgument), Diagnose(Diagnose) {} + + bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, + const char *StartSpecifier, + unsigned specifierLen) override { + if (!FS.consumesDataArgument()) + return true; + + unsigned NulByte = 0; + switch ((FS.getConversionSpecifier().getKind())) { + default: + return true; + case analyze_format_string::ConversionSpecifier::sArg: + case analyze_format_string::ConversionSpecifier::ScanListArg: + NulByte = 1; + break; + case analyze_format_string::ConversionSpecifier::cArg: + break; + } + + auto OptionalFW = FS.getFieldWidth(); + if (OptionalFW.getHowSpecified() != + analyze_format_string::OptionalAmount::HowSpecified::Constant) + return true; + + unsigned SourceSize = OptionalFW.getConstantAmount() + NulByte; + + auto DestSizeAPS = ComputeSizeArgument(FS.getArgIndex()); + if (!DestSizeAPS) + return true; + + unsigned DestSize = DestSizeAPS->getZExtValue(); + + if (DestSize < SourceSize) + Diagnose(FS.getArgIndex(), DestSize, SourceSize); + + return true; + } +}; + class EstimateSizeFormatHandler : public analyze_format_string::FormatStringHandler { size_t Size; @@ -588,14 +646,8 @@ private: } // namespace -/// Check a call to BuiltinID for buffer overflows. If BuiltinID is a -/// __builtin_*_chk function, then use the object size argument specified in the -/// source. Otherwise, infer the object size using __builtin_object_size. void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall) { - // FIXME: There are some more useful checks we could be doing here: - // - Evaluate strlen of strcpy arguments, use as object size. - if (TheCall->isValueDependent() || TheCall->isTypeDependent() || isConstantEvaluated()) return; @@ -607,13 +659,138 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, const TargetInfo &TI = getASTContext().getTargetInfo(); unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); + auto ComputeExplicitObjectSizeArgument = + [&](unsigned Index) -> Optional { + Expr::EvalResult Result; + Expr *SizeArg = TheCall->getArg(Index); + if (!SizeArg->EvaluateAsInt(Result, getASTContext())) + return llvm::None; + return Result.Val.getInt(); + }; + + auto ComputeSizeArgument = [&](unsigned Index) -> Optional { + // If the parameter has a pass_object_size attribute, then we should use its + // (potentially) more strict checking mode. Otherwise, conservatively assume + // type 0. + int BOSType = 0; + // This check can fail for variadic functions. + if (Index < FD->getNumParams()) { + if (const auto *POS = + FD->getParamDecl(Index)->getAttr()) + BOSType = POS->getType(); + } + + const Expr *ObjArg = TheCall->getArg(Index); + uint64_t Result; + if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) + return llvm::None; + + // Get the object size in the target's size_t width. + return llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); + }; + + auto ComputeStrLenArgument = [&](unsigned Index) -> Optional { + Expr *ObjArg = TheCall->getArg(Index); + uint64_t Result; + if (!ObjArg->tryEvaluateStrLen(Result, getASTContext())) + return llvm::None; + // Add 1 for null byte. + return llvm::APSInt::getUnsigned(Result + 1).extOrTrunc(SizeTypeWidth); + }; + + Optional SourceSize; + Optional DestinationSize; unsigned DiagID = 0; bool IsChkVariant = false; - Optional UsedSize; - unsigned SizeIndex, ObjectIndex; + + auto GetFunctionName = [&]() { + StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID); + // Skim off the details of whichever builtin was called to produce a better + // diagnostic, as it's unlikely that the user wrote the __builtin + // explicitly. + if (IsChkVariant) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); + FunctionName = FunctionName.drop_back(std::strlen("_chk")); + } else if (FunctionName.startswith("__builtin_")) { + FunctionName = FunctionName.drop_front(std::strlen("__builtin_")); + } + return FunctionName; + }; + switch (BuiltinID) { default: return; + case Builtin::BI__builtin_strcpy: + case Builtin::BIstrcpy: { + DiagID = diag::warn_fortify_strlen_overflow; + SourceSize = ComputeStrLenArgument(1); + DestinationSize = ComputeSizeArgument(0); + break; + } + + case Builtin::BI__builtin___strcpy_chk: { + DiagID = diag::warn_fortify_strlen_overflow; + SourceSize = ComputeStrLenArgument(1); + DestinationSize = ComputeExplicitObjectSizeArgument(2); + IsChkVariant = true; + break; + } + + case Builtin::BIscanf: + case Builtin::BIfscanf: + case Builtin::BIsscanf: { + unsigned FormatIndex = 1; + unsigned DataIndex = 2; + if (BuiltinID == Builtin::BIscanf) { + FormatIndex = 0; + DataIndex = 1; + } + + const auto *FormatExpr = + TheCall->getArg(FormatIndex)->IgnoreParenImpCasts(); + + const auto *Format = dyn_cast(FormatExpr); + if (!Format) + return; + + if (!Format->isAscii() && !Format->isUTF8()) + return; + + auto Diagnose = [&](unsigned ArgIndex, unsigned DestSize, + unsigned SourceSize) { + DiagID = diag::warn_fortify_scanf_overflow; + unsigned Index = ArgIndex + DataIndex; + StringRef FunctionName = GetFunctionName(); + DiagRuntimeBehavior(TheCall->getArg(Index)->getBeginLoc(), TheCall, + PDiag(DiagID) << FunctionName << (Index + 1) + << DestSize << SourceSize); + }; + + StringRef FormatStrRef = Format->getString(); + auto ShiftedComputeSizeArgument = [&](unsigned Index) { + return ComputeSizeArgument(Index + DataIndex); + }; + ScanfDiagnosticFormatHandler H(ShiftedComputeSizeArgument, Diagnose); + const char *FormatBytes = FormatStrRef.data(); + const ConstantArrayType *T = + Context.getAsConstantArrayType(Format->getType()); + assert(T && "String literal not of constant array type!"); + size_t TypeSize = T->getSize().getZExtValue(); + + // In case there's a null byte somewhere. + size_t StrLen = + std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0)); + + analyze_format_string::ParseScanfString(H, FormatBytes, + FormatBytes + StrLen, getLangOpts(), + Context.getTargetInfo()); + + // Unlike the other cases, in this one we have already issued the diagnostic + // here, so no need to continue (because unlike the other cases, here the + // diagnostic refers to the argument number). + return; + } + case Builtin::BIsprintf: case Builtin::BI__builtin___sprintf_chk: { size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3; @@ -639,14 +816,13 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, H, FormatBytes, FormatBytes + StrLen, getLangOpts(), Context.getTargetInfo(), false)) { DiagID = diag::warn_fortify_source_format_overflow; - UsedSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) - .extOrTrunc(SizeTypeWidth); + SourceSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) + .extOrTrunc(SizeTypeWidth); if (BuiltinID == Builtin::BI__builtin___sprintf_chk) { + DestinationSize = ComputeExplicitObjectSizeArgument(2); IsChkVariant = true; - ObjectIndex = 2; } else { - IsChkVariant = false; - ObjectIndex = 0; + DestinationSize = ComputeSizeArgument(0); } break; } @@ -664,18 +840,19 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___memccpy_chk: case Builtin::BI__builtin___mempcpy_chk: { DiagID = diag::warn_builtin_chk_overflow; + SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 2); + DestinationSize = + ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); IsChkVariant = true; - SizeIndex = TheCall->getNumArgs() - 2; - ObjectIndex = TheCall->getNumArgs() - 1; break; } case Builtin::BI__builtin___snprintf_chk: case Builtin::BI__builtin___vsnprintf_chk: { DiagID = diag::warn_builtin_chk_overflow; + SourceSize = ComputeExplicitObjectSizeArgument(1); + DestinationSize = ComputeExplicitObjectSizeArgument(3); IsChkVariant = true; - SizeIndex = 1; - ObjectIndex = 3; break; } @@ -691,8 +868,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, // size larger than the destination buffer though; this is a runtime abort // in _FORTIFY_SOURCE mode, and is quite suspicious otherwise. DiagID = diag::warn_fortify_source_size_mismatch; - SizeIndex = TheCall->getNumArgs() - 1; - ObjectIndex = 0; + SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + DestinationSize = ComputeSizeArgument(0); break; } @@ -705,8 +882,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BImempcpy: case Builtin::BI__builtin_mempcpy: { DiagID = diag::warn_fortify_source_overflow; - SizeIndex = TheCall->getNumArgs() - 1; - ObjectIndex = 0; + SourceSize = ComputeExplicitObjectSizeArgument(TheCall->getNumArgs() - 1); + DestinationSize = ComputeSizeArgument(0); break; } case Builtin::BIsnprintf: @@ -714,66 +891,25 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BIvsnprintf: case Builtin::BI__builtin_vsnprintf: { DiagID = diag::warn_fortify_source_size_mismatch; - SizeIndex = 1; - ObjectIndex = 0; + SourceSize = ComputeExplicitObjectSizeArgument(1); + DestinationSize = ComputeSizeArgument(0); break; } } - llvm::APSInt ObjectSize; - // For __builtin___*_chk, the object size is explicitly provided by the caller - // (usually using __builtin_object_size). Use that value to check this call. - if (IsChkVariant) { - Expr::EvalResult Result; - Expr *SizeArg = TheCall->getArg(ObjectIndex); - if (!SizeArg->EvaluateAsInt(Result, getASTContext())) - return; - ObjectSize = Result.Val.getInt(); - - // Otherwise, try to evaluate an imaginary call to __builtin_object_size. - } else { - // If the parameter has a pass_object_size attribute, then we should use its - // (potentially) more strict checking mode. Otherwise, conservatively assume - // type 0. - int BOSType = 0; - if (const auto *POS = - FD->getParamDecl(ObjectIndex)->getAttr()) - BOSType = POS->getType(); - - Expr *ObjArg = TheCall->getArg(ObjectIndex); - uint64_t Result; - if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) - return; - // Get the object size in the target's size_t width. - ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); - } - - // Evaluate the number of bytes of the object that this call will use. - if (!UsedSize) { - Expr::EvalResult Result; - Expr *UsedSizeArg = TheCall->getArg(SizeIndex); - if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext())) - return; - UsedSize = Result.Val.getInt().extOrTrunc(SizeTypeWidth); - } - - if (UsedSize.getValue().ule(ObjectSize)) + if (!SourceSize || !DestinationSize || + SourceSize.getValue().ule(DestinationSize.getValue())) return; - StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID); - // Skim off the details of whichever builtin was called to produce a better - // diagnostic, as it's unlikley that the user wrote the __builtin explicitly. - if (IsChkVariant) { - FunctionName = FunctionName.drop_front(std::strlen("__builtin___")); - FunctionName = FunctionName.drop_back(std::strlen("_chk")); - } else if (FunctionName.startswith("__builtin_")) { - FunctionName = FunctionName.drop_front(std::strlen("__builtin_")); - } + StringRef FunctionName = GetFunctionName(); + SmallString<16> DestinationStr; + SmallString<16> SourceStr; + DestinationSize->toString(DestinationStr, /*Radix=*/10); + SourceSize->toString(SourceStr, /*Radix=*/10); DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, PDiag(DiagID) - << FunctionName << toString(ObjectSize, /*Radix=*/10) - << toString(UsedSize.getValue(), /*Radix=*/10)); + << FunctionName << DestinationStr << SourceStr); } static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, @@ -1715,7 +1851,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // value so we bail out. if (SizeOp->isValueDependent()) break; - if (!SizeOp->EvaluateKnownConstInt(Context).isNullValue()) { + if (!SizeOp->EvaluateKnownConstInt(Context).isZero()) { CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc()); } @@ -1962,6 +2098,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } + case Builtin::BI__builtin_elementwise_abs: + if (SemaBuiltinElementwiseMathOneArg(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_elementwise_min: + case Builtin::BI__builtin_elementwise_max: + if (SemaBuiltinElementwiseMath(TheCall)) + return ExprError(); + break; + case Builtin::BI__builtin_reduce_max: + case Builtin::BI__builtin_reduce_min: + if (SemaBuiltinReduceMath(TheCall)) + return ExprError(); + break; case Builtin::BI__builtin_matrix_transpose: return SemaBuiltinMatrixTranspose(TheCall, TheCallResult); @@ -2591,8 +2741,8 @@ static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { // to BPF backend to check whether the access is a // field access or not. return (Arg->IgnoreParens()->getObjectKind() == OK_BitField || - dyn_cast(Arg->IgnoreParens()) || - dyn_cast(Arg->IgnoreParens())); + isa(Arg->IgnoreParens()) || + isa(Arg->IgnoreParens())); } static bool isEltOfVectorTy(ASTContext &Context, CallExpr *Call, Sema &S, @@ -2616,8 +2766,8 @@ static bool isValidBPFPreserveTypeInfoArg(Expr *Arg) { // 1. __builtin_preserve_type_info(*( *)0, flag); // 2. var; // __builtin_preserve_type_info(var, flag); - if (!dyn_cast(Arg->IgnoreParens()) && - !dyn_cast(Arg->IgnoreParens())) + if (!isa(Arg->IgnoreParens()) && + !isa(Arg->IgnoreParens())) return false; // Typedef type. @@ -2674,12 +2824,7 @@ static bool isValidBPFPreserveEnumValueArg(Expr *Arg) { return false; // The enum value must be supported. - for (auto *EDI : ET->getDecl()->enumerators()) { - if (EDI == Enumerator) - return true; - } - - return false; + return llvm::is_contained(ET->getDecl()->enumerators(), Enumerator); } bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, @@ -2974,8 +3119,8 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { unsigned M = 1 << A.Align; Min *= M; Max *= M; - Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max) | - SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); } } return Error; @@ -3280,6 +3425,14 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { case PPC::BI__builtin_ppc_store8r: case PPC::BI__builtin_ppc_insert_exp: case PPC::BI__builtin_ppc_extract_sig: + case PPC::BI__builtin_ppc_addex: + case PPC::BI__builtin_darn: + case PPC::BI__builtin_darn_raw: + case PPC::BI__builtin_ppc_compare_and_swaplp: + case PPC::BI__builtin_ppc_fetch_and_addlp: + case PPC::BI__builtin_ppc_fetch_and_andlp: + case PPC::BI__builtin_ppc_fetch_and_orlp: + case PPC::BI__builtin_ppc_fetch_and_swaplp: return true; } return false; @@ -3351,6 +3504,18 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', + // __builtin_(un)pack_longdouble are available only if long double uses IBM + // extended double representation. + case PPC::BI__builtin_unpack_longdouble: + if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1)) + return true; + LLVM_FALLTHROUGH; + case PPC::BI__builtin_pack_longdouble: + if (&TI.getLongDoubleFormat() != &llvm::APFloat::PPCDoubleDouble()) + return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_requires_abi) + << "ibmlongdouble"; + return false; case PPC::BI__builtin_altivec_dst: case PPC::BI__builtin_altivec_dstt: case PPC::BI__builtin_altivec_dstst: @@ -3410,8 +3575,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must // be a constant that represents a contiguous bit field. case PPC::BI__builtin_ppc_rlwnm: - return SemaBuiltinConstantArg(TheCall, 1, Result) || - SemaValueIsRunOfOnes(TheCall, 2); + return SemaValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_ppc_rlwimi: case PPC::BI__builtin_ppc_rldimi: return SemaBuiltinConstantArg(TheCall, 2, Result) || @@ -3421,6 +3585,19 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_ppc_insert_exp: return SemaFeatureCheck(*this, TheCall, "power9-vector", diag::err_ppc_builtin_only_on_arch, "9"); + case PPC::BI__builtin_ppc_addex: { + if (SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", + diag::err_ppc_builtin_only_on_arch, "9") || + SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) + return true; + // Output warning for reserved values 1 to 3. + int ArgValue = + TheCall->getArg(2)->getIntegerConstantExpr(Context)->getSExtValue(); + if (ArgValue != 0) + Diag(TheCall->getBeginLoc(), diag::warn_argument_undefined_behaviour) + << ArgValue; + return false; + } case PPC::BI__builtin_ppc_mtfsb0: case PPC::BI__builtin_ppc_mtfsb1: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); @@ -3445,9 +3622,50 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, return SemaFeatureCheck(*this, TheCall, "isa-v207-instructions", diag::err_ppc_builtin_only_on_arch, "8") || SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ - case PPC::BI__builtin_##Name: \ - return SemaBuiltinPPCMMACall(TheCall, Types); + case PPC::BI__builtin_altivec_vcntmbb: + case PPC::BI__builtin_altivec_vcntmbh: + case PPC::BI__builtin_altivec_vcntmbw: + case PPC::BI__builtin_altivec_vcntmbd: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + case PPC::BI__builtin_darn: + case PPC::BI__builtin_darn_raw: + case PPC::BI__builtin_darn_32: + return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", + diag::err_ppc_builtin_only_on_arch, "9"); + case PPC::BI__builtin_vsx_xxgenpcvbm: + case PPC::BI__builtin_vsx_xxgenpcvhm: + case PPC::BI__builtin_vsx_xxgenpcvwm: + case PPC::BI__builtin_vsx_xxgenpcvdm: + return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + case PPC::BI__builtin_ppc_compare_exp_uo: + case PPC::BI__builtin_ppc_compare_exp_lt: + case PPC::BI__builtin_ppc_compare_exp_gt: + case PPC::BI__builtin_ppc_compare_exp_eq: + return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", + diag::err_ppc_builtin_only_on_arch, "9") || + SemaFeatureCheck(*this, TheCall, "vsx", + diag::err_ppc_builtin_requires_vsx); + case PPC::BI__builtin_ppc_test_data_class: { + // Check if the first argument of the __builtin_ppc_test_data_class call is + // valid. The argument must be either a 'float' or a 'double'. + QualType ArgType = TheCall->getArg(0)->getType(); + if (ArgType != QualType(Context.FloatTy) && + ArgType != QualType(Context.DoubleTy)) + return Diag(TheCall->getBeginLoc(), + diag::err_ppc_invalid_test_data_class_type); + return SemaFeatureCheck(*this, TheCall, "isa-v30-instructions", + diag::err_ppc_builtin_only_on_arch, "9") || + SemaFeatureCheck(*this, TheCall, "vsx", + diag::err_ppc_builtin_requires_vsx) || + SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); + } + case PPC::BI__builtin_ppc_load8r: + case PPC::BI__builtin_ppc_store8r: + return SemaFeatureCheck(*this, TheCall, "isa-v206-instructions", + diag::err_ppc_builtin_only_on_arch, "7"); +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc) \ + case PPC::BI__builtin_##Name: \ + return SemaBuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" } return SemaBuiltinConstantArgRange(TheCall, i, l, u); @@ -3499,7 +3717,7 @@ bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, << ArgExpr->getType(); auto Ord = ArgResult.Val.getInt().getZExtValue(); - // Check valididty of memory ordering as per C11 / C++11's memody model. + // Check validity of memory ordering as per C11 / C++11's memody model. // Only fence needs check. Atomic dec/inc allow all memory orders. if (!llvm::isValidAtomicOrderingCABI(Ord)) return Diag(ArgExpr->getBeginLoc(), @@ -3586,138 +3804,12 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, return true; switch (BuiltinID) { - case RISCV::BI__builtin_rvv_vsetvli: + case RISCVVector::BI__builtin_rvv_vsetvli: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3) || CheckRISCVLMUL(TheCall, 2); - case RISCV::BI__builtin_rvv_vsetvlimax: + case RISCVVector::BI__builtin_rvv_vsetvlimax: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || CheckRISCVLMUL(TheCall, 1); - case RISCV::BI__builtin_rvv_vget_v_i8m2_i8m1: - case RISCV::BI__builtin_rvv_vget_v_i16m2_i16m1: - case RISCV::BI__builtin_rvv_vget_v_i32m2_i32m1: - case RISCV::BI__builtin_rvv_vget_v_i64m2_i64m1: - case RISCV::BI__builtin_rvv_vget_v_f32m2_f32m1: - case RISCV::BI__builtin_rvv_vget_v_f64m2_f64m1: - case RISCV::BI__builtin_rvv_vget_v_u8m2_u8m1: - case RISCV::BI__builtin_rvv_vget_v_u16m2_u16m1: - case RISCV::BI__builtin_rvv_vget_v_u32m2_u32m1: - case RISCV::BI__builtin_rvv_vget_v_u64m2_u64m1: - case RISCV::BI__builtin_rvv_vget_v_i8m4_i8m2: - case RISCV::BI__builtin_rvv_vget_v_i16m4_i16m2: - case RISCV::BI__builtin_rvv_vget_v_i32m4_i32m2: - case RISCV::BI__builtin_rvv_vget_v_i64m4_i64m2: - case RISCV::BI__builtin_rvv_vget_v_f32m4_f32m2: - case RISCV::BI__builtin_rvv_vget_v_f64m4_f64m2: - case RISCV::BI__builtin_rvv_vget_v_u8m4_u8m2: - case RISCV::BI__builtin_rvv_vget_v_u16m4_u16m2: - case RISCV::BI__builtin_rvv_vget_v_u32m4_u32m2: - case RISCV::BI__builtin_rvv_vget_v_u64m4_u64m2: - case RISCV::BI__builtin_rvv_vget_v_i8m8_i8m4: - case RISCV::BI__builtin_rvv_vget_v_i16m8_i16m4: - case RISCV::BI__builtin_rvv_vget_v_i32m8_i32m4: - case RISCV::BI__builtin_rvv_vget_v_i64m8_i64m4: - case RISCV::BI__builtin_rvv_vget_v_f32m8_f32m4: - case RISCV::BI__builtin_rvv_vget_v_f64m8_f64m4: - case RISCV::BI__builtin_rvv_vget_v_u8m8_u8m4: - case RISCV::BI__builtin_rvv_vget_v_u16m8_u16m4: - case RISCV::BI__builtin_rvv_vget_v_u32m8_u32m4: - case RISCV::BI__builtin_rvv_vget_v_u64m8_u64m4: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case RISCV::BI__builtin_rvv_vget_v_i8m4_i8m1: - case RISCV::BI__builtin_rvv_vget_v_i16m4_i16m1: - case RISCV::BI__builtin_rvv_vget_v_i32m4_i32m1: - case RISCV::BI__builtin_rvv_vget_v_i64m4_i64m1: - case RISCV::BI__builtin_rvv_vget_v_f32m4_f32m1: - case RISCV::BI__builtin_rvv_vget_v_f64m4_f64m1: - case RISCV::BI__builtin_rvv_vget_v_u8m4_u8m1: - case RISCV::BI__builtin_rvv_vget_v_u16m4_u16m1: - case RISCV::BI__builtin_rvv_vget_v_u32m4_u32m1: - case RISCV::BI__builtin_rvv_vget_v_u64m4_u64m1: - case RISCV::BI__builtin_rvv_vget_v_i8m8_i8m2: - case RISCV::BI__builtin_rvv_vget_v_i16m8_i16m2: - case RISCV::BI__builtin_rvv_vget_v_i32m8_i32m2: - case RISCV::BI__builtin_rvv_vget_v_i64m8_i64m2: - case RISCV::BI__builtin_rvv_vget_v_f32m8_f32m2: - case RISCV::BI__builtin_rvv_vget_v_f64m8_f64m2: - case RISCV::BI__builtin_rvv_vget_v_u8m8_u8m2: - case RISCV::BI__builtin_rvv_vget_v_u16m8_u16m2: - case RISCV::BI__builtin_rvv_vget_v_u32m8_u32m2: - case RISCV::BI__builtin_rvv_vget_v_u64m8_u64m2: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); - case RISCV::BI__builtin_rvv_vget_v_i8m8_i8m1: - case RISCV::BI__builtin_rvv_vget_v_i16m8_i16m1: - case RISCV::BI__builtin_rvv_vget_v_i32m8_i32m1: - case RISCV::BI__builtin_rvv_vget_v_i64m8_i64m1: - case RISCV::BI__builtin_rvv_vget_v_f32m8_f32m1: - case RISCV::BI__builtin_rvv_vget_v_f64m8_f64m1: - case RISCV::BI__builtin_rvv_vget_v_u8m8_u8m1: - case RISCV::BI__builtin_rvv_vget_v_u16m8_u16m1: - case RISCV::BI__builtin_rvv_vget_v_u32m8_u32m1: - case RISCV::BI__builtin_rvv_vget_v_u64m8_u64m1: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); - case RISCV::BI__builtin_rvv_vset_v_i8m1_i8m2: - case RISCV::BI__builtin_rvv_vset_v_i16m1_i16m2: - case RISCV::BI__builtin_rvv_vset_v_i32m1_i32m2: - case RISCV::BI__builtin_rvv_vset_v_i64m1_i64m2: - case RISCV::BI__builtin_rvv_vset_v_f32m1_f32m2: - case RISCV::BI__builtin_rvv_vset_v_f64m1_f64m2: - case RISCV::BI__builtin_rvv_vset_v_u8m1_u8m2: - case RISCV::BI__builtin_rvv_vset_v_u16m1_u16m2: - case RISCV::BI__builtin_rvv_vset_v_u32m1_u32m2: - case RISCV::BI__builtin_rvv_vset_v_u64m1_u64m2: - case RISCV::BI__builtin_rvv_vset_v_i8m2_i8m4: - case RISCV::BI__builtin_rvv_vset_v_i16m2_i16m4: - case RISCV::BI__builtin_rvv_vset_v_i32m2_i32m4: - case RISCV::BI__builtin_rvv_vset_v_i64m2_i64m4: - case RISCV::BI__builtin_rvv_vset_v_f32m2_f32m4: - case RISCV::BI__builtin_rvv_vset_v_f64m2_f64m4: - case RISCV::BI__builtin_rvv_vset_v_u8m2_u8m4: - case RISCV::BI__builtin_rvv_vset_v_u16m2_u16m4: - case RISCV::BI__builtin_rvv_vset_v_u32m2_u32m4: - case RISCV::BI__builtin_rvv_vset_v_u64m2_u64m4: - case RISCV::BI__builtin_rvv_vset_v_i8m4_i8m8: - case RISCV::BI__builtin_rvv_vset_v_i16m4_i16m8: - case RISCV::BI__builtin_rvv_vset_v_i32m4_i32m8: - case RISCV::BI__builtin_rvv_vset_v_i64m4_i64m8: - case RISCV::BI__builtin_rvv_vset_v_f32m4_f32m8: - case RISCV::BI__builtin_rvv_vset_v_f64m4_f64m8: - case RISCV::BI__builtin_rvv_vset_v_u8m4_u8m8: - case RISCV::BI__builtin_rvv_vset_v_u16m4_u16m8: - case RISCV::BI__builtin_rvv_vset_v_u32m4_u32m8: - case RISCV::BI__builtin_rvv_vset_v_u64m4_u64m8: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); - case RISCV::BI__builtin_rvv_vset_v_i8m1_i8m4: - case RISCV::BI__builtin_rvv_vset_v_i16m1_i16m4: - case RISCV::BI__builtin_rvv_vset_v_i32m1_i32m4: - case RISCV::BI__builtin_rvv_vset_v_i64m1_i64m4: - case RISCV::BI__builtin_rvv_vset_v_f32m1_f32m4: - case RISCV::BI__builtin_rvv_vset_v_f64m1_f64m4: - case RISCV::BI__builtin_rvv_vset_v_u8m1_u8m4: - case RISCV::BI__builtin_rvv_vset_v_u16m1_u16m4: - case RISCV::BI__builtin_rvv_vset_v_u32m1_u32m4: - case RISCV::BI__builtin_rvv_vset_v_u64m1_u64m4: - case RISCV::BI__builtin_rvv_vset_v_i8m2_i8m8: - case RISCV::BI__builtin_rvv_vset_v_i16m2_i16m8: - case RISCV::BI__builtin_rvv_vset_v_i32m2_i32m8: - case RISCV::BI__builtin_rvv_vset_v_i64m2_i64m8: - case RISCV::BI__builtin_rvv_vset_v_f32m2_f32m8: - case RISCV::BI__builtin_rvv_vset_v_f64m2_f64m8: - case RISCV::BI__builtin_rvv_vset_v_u8m2_u8m8: - case RISCV::BI__builtin_rvv_vset_v_u16m2_u16m8: - case RISCV::BI__builtin_rvv_vset_v_u32m2_u32m8: - case RISCV::BI__builtin_rvv_vset_v_u64m2_u64m8: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); - case RISCV::BI__builtin_rvv_vset_v_i8m1_i8m8: - case RISCV::BI__builtin_rvv_vset_v_i16m1_i16m8: - case RISCV::BI__builtin_rvv_vset_v_i32m1_i32m8: - case RISCV::BI__builtin_rvv_vset_v_i64m1_i64m8: - case RISCV::BI__builtin_rvv_vset_v_f32m1_f32m8: - case RISCV::BI__builtin_rvv_vset_v_f64m1_f64m8: - case RISCV::BI__builtin_rvv_vset_v_u8m1_u8m8: - case RISCV::BI__builtin_rvv_vset_v_u16m1_u16m8: - case RISCV::BI__builtin_rvv_vset_v_u32m1_u32m8: - case RISCV::BI__builtin_rvv_vset_v_u64m1_u64m8: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); } return false; @@ -3850,14 +3942,22 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvttss2si64: case X86::BI__builtin_ia32_vcvttss2usi32: case X86::BI__builtin_ia32_vcvttss2usi64: + case X86::BI__builtin_ia32_vcvttsh2si32: + case X86::BI__builtin_ia32_vcvttsh2si64: + case X86::BI__builtin_ia32_vcvttsh2usi32: + case X86::BI__builtin_ia32_vcvttsh2usi64: ArgNum = 1; break; case X86::BI__builtin_ia32_maxpd512: case X86::BI__builtin_ia32_maxps512: case X86::BI__builtin_ia32_minpd512: case X86::BI__builtin_ia32_minps512: + case X86::BI__builtin_ia32_maxph512: + case X86::BI__builtin_ia32_minph512: ArgNum = 2; break; + case X86::BI__builtin_ia32_vcvtph2pd512_mask: + case X86::BI__builtin_ia32_vcvtph2psx512_mask: case X86::BI__builtin_ia32_cvtps2pd512_mask: case X86::BI__builtin_ia32_cvttpd2dq512_mask: case X86::BI__builtin_ia32_cvttpd2qq512_mask: @@ -3867,16 +3967,24 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvttps2qq512_mask: case X86::BI__builtin_ia32_cvttps2udq512_mask: case X86::BI__builtin_ia32_cvttps2uqq512_mask: + case X86::BI__builtin_ia32_vcvttph2w512_mask: + case X86::BI__builtin_ia32_vcvttph2uw512_mask: + case X86::BI__builtin_ia32_vcvttph2dq512_mask: + case X86::BI__builtin_ia32_vcvttph2udq512_mask: + case X86::BI__builtin_ia32_vcvttph2qq512_mask: + case X86::BI__builtin_ia32_vcvttph2uqq512_mask: case X86::BI__builtin_ia32_exp2pd_mask: case X86::BI__builtin_ia32_exp2ps_mask: case X86::BI__builtin_ia32_getexppd512_mask: case X86::BI__builtin_ia32_getexpps512_mask: + case X86::BI__builtin_ia32_getexpph512_mask: case X86::BI__builtin_ia32_rcp28pd_mask: case X86::BI__builtin_ia32_rcp28ps_mask: case X86::BI__builtin_ia32_rsqrt28pd_mask: case X86::BI__builtin_ia32_rsqrt28ps_mask: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_vcomish: case X86::BI__builtin_ia32_vcvtph2ps512_mask: ArgNum = 3; break; @@ -3884,21 +3992,30 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cmpps512_mask: case X86::BI__builtin_ia32_cmpsd_mask: case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_cmpsh_mask: + case X86::BI__builtin_ia32_vcvtsh2sd_round_mask: + case X86::BI__builtin_ia32_vcvtsh2ss_round_mask: case X86::BI__builtin_ia32_cvtss2sd_round_mask: case X86::BI__builtin_ia32_getexpsd128_round_mask: case X86::BI__builtin_ia32_getexpss128_round_mask: + case X86::BI__builtin_ia32_getexpsh128_round_mask: case X86::BI__builtin_ia32_getmantpd512_mask: case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_getmantph512_mask: case X86::BI__builtin_ia32_maxsd_round_mask: case X86::BI__builtin_ia32_maxss_round_mask: + case X86::BI__builtin_ia32_maxsh_round_mask: case X86::BI__builtin_ia32_minsd_round_mask: case X86::BI__builtin_ia32_minss_round_mask: + case X86::BI__builtin_ia32_minsh_round_mask: case X86::BI__builtin_ia32_rcp28sd_round_mask: case X86::BI__builtin_ia32_rcp28ss_round_mask: case X86::BI__builtin_ia32_reducepd512_mask: case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_reduceph512_mask: case X86::BI__builtin_ia32_rndscalepd_mask: case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rndscaleph_mask: case X86::BI__builtin_ia32_rsqrt28sd_round_mask: case X86::BI__builtin_ia32_rsqrt28ss_round_mask: ArgNum = 4; @@ -3913,14 +4030,17 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_fixupimmss_maskz: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_getmantsh_round_mask: case X86::BI__builtin_ia32_rangepd512_mask: case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_rangesd128_round_mask: case X86::BI__builtin_ia32_rangess128_round_mask: case X86::BI__builtin_ia32_reducesd_mask: case X86::BI__builtin_ia32_reducess_mask: + case X86::BI__builtin_ia32_reducesh_mask: case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: + case X86::BI__builtin_ia32_rndscalesh_round_mask: ArgNum = 5; break; case X86::BI__builtin_ia32_vcvtsd2si64: @@ -3931,11 +4051,20 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vcvtss2si64: case X86::BI__builtin_ia32_vcvtss2usi32: case X86::BI__builtin_ia32_vcvtss2usi64: + case X86::BI__builtin_ia32_vcvtsh2si32: + case X86::BI__builtin_ia32_vcvtsh2si64: + case X86::BI__builtin_ia32_vcvtsh2usi32: + case X86::BI__builtin_ia32_vcvtsh2usi64: case X86::BI__builtin_ia32_sqrtpd512: case X86::BI__builtin_ia32_sqrtps512: + case X86::BI__builtin_ia32_sqrtph512: ArgNum = 1; HasRC = true; break; + case X86::BI__builtin_ia32_addph512: + case X86::BI__builtin_ia32_divph512: + case X86::BI__builtin_ia32_mulph512: + case X86::BI__builtin_ia32_subph512: case X86::BI__builtin_ia32_addpd512: case X86::BI__builtin_ia32_addps512: case X86::BI__builtin_ia32_divpd512: @@ -3950,11 +4079,17 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtusi2sd64: case X86::BI__builtin_ia32_cvtusi2ss32: case X86::BI__builtin_ia32_cvtusi2ss64: + case X86::BI__builtin_ia32_vcvtusi2sh: + case X86::BI__builtin_ia32_vcvtusi642sh: + case X86::BI__builtin_ia32_vcvtsi2sh: + case X86::BI__builtin_ia32_vcvtsi642sh: ArgNum = 2; HasRC = true; break; case X86::BI__builtin_ia32_cvtdq2ps512_mask: case X86::BI__builtin_ia32_cvtudq2ps512_mask: + case X86::BI__builtin_ia32_vcvtpd2ph512_mask: + case X86::BI__builtin_ia32_vcvtps2phx512_mask: case X86::BI__builtin_ia32_cvtpd2ps512_mask: case X86::BI__builtin_ia32_cvtpd2dq512_mask: case X86::BI__builtin_ia32_cvtpd2qq512_mask: @@ -3968,30 +4103,54 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_cvtqq2ps512_mask: case X86::BI__builtin_ia32_cvtuqq2pd512_mask: case X86::BI__builtin_ia32_cvtuqq2ps512_mask: + case X86::BI__builtin_ia32_vcvtdq2ph512_mask: + case X86::BI__builtin_ia32_vcvtudq2ph512_mask: + case X86::BI__builtin_ia32_vcvtw2ph512_mask: + case X86::BI__builtin_ia32_vcvtuw2ph512_mask: + case X86::BI__builtin_ia32_vcvtph2w512_mask: + case X86::BI__builtin_ia32_vcvtph2uw512_mask: + case X86::BI__builtin_ia32_vcvtph2dq512_mask: + case X86::BI__builtin_ia32_vcvtph2udq512_mask: + case X86::BI__builtin_ia32_vcvtph2qq512_mask: + case X86::BI__builtin_ia32_vcvtph2uqq512_mask: + case X86::BI__builtin_ia32_vcvtqq2ph512_mask: + case X86::BI__builtin_ia32_vcvtuqq2ph512_mask: ArgNum = 3; HasRC = true; break; + case X86::BI__builtin_ia32_addsh_round_mask: case X86::BI__builtin_ia32_addss_round_mask: case X86::BI__builtin_ia32_addsd_round_mask: + case X86::BI__builtin_ia32_divsh_round_mask: case X86::BI__builtin_ia32_divss_round_mask: case X86::BI__builtin_ia32_divsd_round_mask: + case X86::BI__builtin_ia32_mulsh_round_mask: case X86::BI__builtin_ia32_mulss_round_mask: case X86::BI__builtin_ia32_mulsd_round_mask: + case X86::BI__builtin_ia32_subsh_round_mask: case X86::BI__builtin_ia32_subss_round_mask: case X86::BI__builtin_ia32_subsd_round_mask: + case X86::BI__builtin_ia32_scalefph512_mask: case X86::BI__builtin_ia32_scalefpd512_mask: case X86::BI__builtin_ia32_scalefps512_mask: case X86::BI__builtin_ia32_scalefsd_round_mask: case X86::BI__builtin_ia32_scalefss_round_mask: + case X86::BI__builtin_ia32_scalefsh_round_mask: case X86::BI__builtin_ia32_cvtsd2ss_round_mask: + case X86::BI__builtin_ia32_vcvtss2sh_round_mask: + case X86::BI__builtin_ia32_vcvtsd2sh_round_mask: case X86::BI__builtin_ia32_sqrtsd_round_mask: case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_sqrtsh_round_mask: case X86::BI__builtin_ia32_vfmaddsd3_mask: case X86::BI__builtin_ia32_vfmaddsd3_maskz: case X86::BI__builtin_ia32_vfmaddsd3_mask3: case X86::BI__builtin_ia32_vfmaddss3_mask: case X86::BI__builtin_ia32_vfmaddss3_maskz: case X86::BI__builtin_ia32_vfmaddss3_mask3: + case X86::BI__builtin_ia32_vfmaddsh3_mask: + case X86::BI__builtin_ia32_vfmaddsh3_maskz: + case X86::BI__builtin_ia32_vfmaddsh3_mask3: case X86::BI__builtin_ia32_vfmaddpd512_mask: case X86::BI__builtin_ia32_vfmaddpd512_maskz: case X86::BI__builtin_ia32_vfmaddpd512_mask3: @@ -4000,6 +4159,10 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vfmaddps512_maskz: case X86::BI__builtin_ia32_vfmaddps512_mask3: case X86::BI__builtin_ia32_vfmsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddph512_mask: + case X86::BI__builtin_ia32_vfmaddph512_maskz: + case X86::BI__builtin_ia32_vfmaddph512_mask3: + case X86::BI__builtin_ia32_vfmsubph512_mask3: case X86::BI__builtin_ia32_vfmaddsubpd512_mask: case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: @@ -4008,6 +4171,26 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_vfmaddsubps512_maskz: case X86::BI__builtin_ia32_vfmaddsubps512_mask3: case X86::BI__builtin_ia32_vfmsubaddps512_mask3: + case X86::BI__builtin_ia32_vfmaddsubph512_mask: + case X86::BI__builtin_ia32_vfmaddsubph512_maskz: + case X86::BI__builtin_ia32_vfmaddsubph512_mask3: + case X86::BI__builtin_ia32_vfmsubaddph512_mask3: + case X86::BI__builtin_ia32_vfmaddcsh_mask: + case X86::BI__builtin_ia32_vfmaddcsh_round_mask: + case X86::BI__builtin_ia32_vfmaddcsh_round_mask3: + case X86::BI__builtin_ia32_vfmaddcph512_mask: + case X86::BI__builtin_ia32_vfmaddcph512_maskz: + case X86::BI__builtin_ia32_vfmaddcph512_mask3: + case X86::BI__builtin_ia32_vfcmaddcsh_mask: + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask: + case X86::BI__builtin_ia32_vfcmaddcsh_round_mask3: + case X86::BI__builtin_ia32_vfcmaddcph512_mask: + case X86::BI__builtin_ia32_vfcmaddcph512_maskz: + case X86::BI__builtin_ia32_vfcmaddcph512_mask3: + case X86::BI__builtin_ia32_vfmulcsh_mask: + case X86::BI__builtin_ia32_vfmulcph512_mask: + case X86::BI__builtin_ia32_vfcmulcsh_mask: + case X86::BI__builtin_ia32_vfcmulcph512_mask: ArgNum = 4; HasRC = true; break; @@ -4359,6 +4542,9 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_getmantps256_mask: case X86::BI__builtin_ia32_getmantpd512_mask: case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_getmantph128_mask: + case X86::BI__builtin_ia32_getmantph256_mask: + case X86::BI__builtin_ia32_getmantph512_mask: case X86::BI__builtin_ia32_vec_ext_v16qi: case X86::BI__builtin_ia32_vec_ext_v16hi: i = 1; l = 0; u = 15; @@ -4377,6 +4563,7 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: + case X86::BI__builtin_ia32_getmantsh_round_mask: case X86::BI__builtin_ia32_vec_set_v16qi: case X86::BI__builtin_ia32_vec_set_v16hi: i = 2; l = 0; u = 15; @@ -4429,12 +4616,16 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_rndscalepd_256_mask: case X86::BI__builtin_ia32_rndscaleps_mask: case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_rndscaleph_mask: case X86::BI__builtin_ia32_reducepd128_mask: case X86::BI__builtin_ia32_reducepd256_mask: case X86::BI__builtin_ia32_reducepd512_mask: case X86::BI__builtin_ia32_reduceps128_mask: case X86::BI__builtin_ia32_reduceps256_mask: case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_reduceph128_mask: + case X86::BI__builtin_ia32_reduceph256_mask: + case X86::BI__builtin_ia32_reduceph512_mask: case X86::BI__builtin_ia32_prold512: case X86::BI__builtin_ia32_prolq512: case X86::BI__builtin_ia32_prold128: @@ -4453,8 +4644,12 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_fpclassps256_mask: case X86::BI__builtin_ia32_fpclassps512_mask: case X86::BI__builtin_ia32_fpclasspd512_mask: + case X86::BI__builtin_ia32_fpclassph128_mask: + case X86::BI__builtin_ia32_fpclassph256_mask: + case X86::BI__builtin_ia32_fpclassph512_mask: case X86::BI__builtin_ia32_fpclasssd_mask: case X86::BI__builtin_ia32_fpclassss_mask: + case X86::BI__builtin_ia32_fpclasssh_mask: case X86::BI__builtin_ia32_pslldqi128_byteshift: case X86::BI__builtin_ia32_pslldqi256_byteshift: case X86::BI__builtin_ia32_pslldqi512_byteshift: @@ -4565,6 +4760,8 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_reducess_mask: case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: + case X86::BI__builtin_ia32_rndscalesh_round_mask: + case X86::BI__builtin_ia32_reducesh_mask: i = 4; l = 0; u = 255; break; } @@ -4829,7 +5026,7 @@ void Sema::CheckArgAlignment(SourceLocation Loc, NamedDecl *FDecl, if (ArgAlign < ParamAlign) Diag(Loc, diag::warn_param_mismatched_alignment) << (int)ArgAlign.getQuantity() << (int)ParamAlign.getQuantity() - << ParamName << FDecl; + << ParamName << (FDecl != nullptr) << FDecl; } /// Handles the checks for format strings, non-POD arguments to vararg @@ -5229,6 +5426,7 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__c11_atomic_fetch_nand: case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_xor: @@ -6286,6 +6484,21 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { } bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { + auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool { + const LangOptions &LO = getLangOpts(); + + if (LO.CPlusPlus) + return Arg->getType() + .getCanonicalType() + .getTypePtr() + ->getPointeeType() + .withoutLocalFastQualifiers() == Context.CharTy; + + // In C, allow aliasing through `char *`, this is required for AArch64 at + // least. + return true; + }; + // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); @@ -6314,8 +6527,7 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { const QualType &ConstCharPtrTy = Context.getPointerType(Context.CharTy.withConst()); - if (!Arg1Ty->isPointerType() || - Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy) + if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1)) Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible) << Arg1->getType() << ConstCharPtrTy << 1 /* different class */ << 0 /* qualifier difference */ @@ -6586,7 +6798,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { << TheCall->getArg(i)->getSourceRange()); // Allow -1 which will be translated to undef in the IR. - if (Result->isSigned() && Result->isAllOnesValue()) + if (Result->isSigned() && Result->isAllOnes()) continue; if (Result->getActiveBits() > 64 || @@ -7286,11 +7498,35 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, /// Emit an error and return true on failure; return false on success. /// TypeStr is a string containing the type descriptor of the value returned by /// the builtin and the descriptors of the expected type of the arguments. -bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, const char *TypeStr) { +bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeStr) { assert((TypeStr[0] != '\0') && "Invalid types in PPC MMA builtin declaration"); + switch (BuiltinID) { + default: + // This function is called in CheckPPCBuiltinFunctionCall where the + // BuiltinID is guaranteed to be an MMA or pair vector memop builtin, here + // we are isolating the pair vector memop builtins that can be used with mma + // off so the default case is every builtin that requires mma and paired + // vector memops. + if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", + diag::err_ppc_builtin_only_on_arch, "10") || + SemaFeatureCheck(*this, TheCall, "mma", + diag::err_ppc_builtin_only_on_arch, "10")) + return true; + break; + case PPC::BI__builtin_vsx_lxvp: + case PPC::BI__builtin_vsx_stxvp: + case PPC::BI__builtin_vsx_assemble_pair: + case PPC::BI__builtin_vsx_disassemble_pair: + if (SemaFeatureCheck(*this, TheCall, "paired-vector-memops", + diag::err_ppc_builtin_only_on_arch, "10")) + return true; + break; + } + unsigned Mask = 0; unsigned ArgNum = 0; @@ -7308,13 +7544,23 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, const char *TypeStr) { } Expr *Arg = TheCall->getArg(ArgNum); - QualType ArgType = Arg->getType(); + QualType PassedType = Arg->getType(); + QualType StrippedRVType = PassedType.getCanonicalType(); - if ((ExpectedType->isVoidPointerType() && !ArgType->isPointerType()) || - (!ExpectedType->isVoidPointerType() && - ArgType.getCanonicalType() != ExpectedType)) - return Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible) - << ArgType << ExpectedType << 1 << 0 << 0; + // Strip Restrict/Volatile qualifiers. + if (StrippedRVType.isRestrictQualified() || + StrippedRVType.isVolatileQualified()) + StrippedRVType = StrippedRVType.getCanonicalType().getUnqualifiedType(); + + // The only case where the argument type and expected type are allowed to + // mismatch is if the argument type is a non-void pointer (or array) and + // expected type is a void pointer. + if (StrippedRVType != ExpectedType) + if (!(ExpectedType->isVoidPointerType() && + (StrippedRVType->isPointerType() || StrippedRVType->isArrayType()))) + return Diag(Arg->getBeginLoc(), + diag::err_typecheck_convert_incompatible) + << PassedType << ExpectedType << 1 << 0 << 0; // If the value of the Mask is not 0, we have a constraint in the size of // the integer argument so here we ensure the argument is a constant that @@ -7678,11 +7924,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, // } if (HasVAListArg) { if (const ParmVarDecl *PV = dyn_cast(VD)) { - if (const NamedDecl *ND = dyn_cast(PV->getDeclContext())) { + if (const Decl *D = dyn_cast(PV->getDeclContext())) { int PVIndex = PV->getFunctionScopeIndex() + 1; - for (const auto *PVFormat : ND->specific_attrs()) { + for (const auto *PVFormat : D->specific_attrs()) { // adjust for implicit parameter - if (const CXXMethodDecl *MD = dyn_cast(ND)) + if (const CXXMethodDecl *MD = dyn_cast(D)) if (MD->isInstance()) ++PVIndex; // We also check if the formats are compatible. @@ -9545,8 +9791,7 @@ static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, // Emit a warning if the string literal is truncated and does not contain an // embedded null character. - if (TypeSize <= StrRef.size() && - StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) { + if (TypeSize <= StrRef.size() && !StrRef.substr(0, TypeSize).contains('\0')) { CheckFormatHandler::EmitFormatDiagnostic( S, inFunctionCall, Args[format_idx], S.PDiag(diag::warn_printf_format_string_not_null_terminated), @@ -11138,7 +11383,7 @@ static QualType GetExprType(const Expr *E) { /// /// \param MaxWidth The width to which the value will be truncated. /// \param Approximate If \c true, return a likely range for the result: in -/// particular, assume that aritmetic on narrower types doesn't leave +/// particular, assume that arithmetic on narrower types doesn't leave /// those types. If \c false, return a range including all possible /// result values. static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth, @@ -13059,6 +13304,20 @@ static void AnalyzeImplicitConversions( << OrigE->getSourceRange() << T->isBooleanType() << FixItHint::CreateReplacement(UO->getBeginLoc(), "!"); + if (const auto *BO = dyn_cast(SourceExpr)) + if ((BO->getOpcode() == BO_And || BO->getOpcode() == BO_Or) && + BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue() && + BO->getLHS()->HasSideEffects(S.Context) && + BO->getRHS()->HasSideEffects(S.Context)) { + S.Diag(BO->getBeginLoc(), diag::warn_bitwise_instead_of_logical) + << (BO->getOpcode() == BO_And ? "&" : "|") << OrigE->getSourceRange() + << FixItHint::CreateReplacement( + BO->getOperatorLoc(), + (BO->getOpcode() == BO_And ? "&&" : "||")); + S.Diag(BO->getBeginLoc(), diag::note_cast_operand_to_int); + } + // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (auto *CO = dyn_cast(SourceExpr)) { @@ -15999,7 +16258,7 @@ static bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { /// /// \param MagicValue Type tag magic value. /// -/// \param isConstantEvaluated wether the evalaution should be performed in +/// \param isConstantEvaluated whether the evalaution should be performed in /// constant context. static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, @@ -16079,7 +16338,7 @@ static bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, /// /// \param TypeInfo Information about the corresponding C type. /// -/// \param isConstantEvaluated wether the evalaution should be performed in +/// \param isConstantEvaluated whether the evalaution should be performed in /// constant context. /// /// \returns true if the corresponding C type was found. @@ -16352,10 +16611,8 @@ void Sema::RefersToMemberWithReducedAlignment( // Synthesize offset of the whole access. CharUnits Offset; - for (auto I = ReverseMemberChain.rbegin(); I != ReverseMemberChain.rend(); - I++) { - Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(*I)); - } + for (const FieldDecl *FD : llvm::reverse(ReverseMemberChain)) + Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(FD)); // Compute the CompleteObjectAlignment as the alignment of the whole chain. CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars( @@ -16408,6 +16665,94 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) { _2, _3, _4)); } +// Check if \p Ty is a valid type for the elementwise math builtins. If it is +// not a valid type, emit an error message and return true. Otherwise return +// false. +static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc, + QualType Ty) { + if (!Ty->getAs() && !ConstantMatrixType::isValidElementType(Ty)) { + S.Diag(Loc, diag::err_builtin_invalid_arg_type) + << 1 << /* vector, integer or float ty*/ 0 << Ty; + return true; + } + return false; +} + +bool Sema::SemaBuiltinElementwiseMathOneArg(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 1)) + return true; + + ExprResult A = UsualUnaryConversions(TheCall->getArg(0)); + SourceLocation ArgLoc = TheCall->getArg(0)->getBeginLoc(); + if (A.isInvalid()) + return true; + + TheCall->setArg(0, A.get()); + QualType TyA = A.get()->getType(); + if (checkMathBuiltinElementType(*this, ArgLoc, TyA)) + return true; + + QualType EltTy = TyA; + if (auto *VecTy = EltTy->getAs()) + EltTy = VecTy->getElementType(); + if (EltTy->isUnsignedIntegerType()) + return Diag(ArgLoc, diag::err_builtin_invalid_arg_type) + << 1 << /*signed integer or float ty*/ 3 << TyA; + + TheCall->setType(TyA); + return false; +} + +bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 2)) + return true; + + ExprResult A = TheCall->getArg(0); + ExprResult B = TheCall->getArg(1); + // Do standard promotions between the two arguments, returning their common + // type. + QualType Res = + UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison); + if (A.isInvalid() || B.isInvalid()) + return true; + + QualType TyA = A.get()->getType(); + QualType TyB = B.get()->getType(); + + if (Res.isNull() || TyA.getCanonicalType() != TyB.getCanonicalType()) + return Diag(A.get()->getBeginLoc(), + diag::err_typecheck_call_different_arg_types) + << TyA << TyB; + + if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA)) + return true; + + TheCall->setArg(0, A.get()); + TheCall->setArg(1, B.get()); + TheCall->setType(Res); + return false; +} + +bool Sema::SemaBuiltinReduceMath(CallExpr *TheCall) { + if (checkArgCount(*this, TheCall, 1)) + return true; + + ExprResult A = UsualUnaryConversions(TheCall->getArg(0)); + if (A.isInvalid()) + return true; + + TheCall->setArg(0, A.get()); + const VectorType *TyA = A.get()->getType()->getAs(); + if (!TyA) { + SourceLocation ArgLoc = TheCall->getArg(0)->getBeginLoc(); + return Diag(ArgLoc, diag::err_builtin_invalid_arg_type) + << 1 << /* vector ty*/ 4 << A.get()->getType(); + } + + TheCall->setType(TyA->getElementType()); + return false; +} + ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult) { if (checkArgCount(*this, TheCall, 1)) @@ -16420,7 +16765,8 @@ ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, auto *MType = Matrix->getType()->getAs(); if (!MType) { - Diag(Matrix->getBeginLoc(), diag::err_builtin_matrix_arg); + Diag(Matrix->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /* matrix ty*/ 1 << Matrix->getType(); return ExprError(); } @@ -16491,15 +16837,16 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, auto *PtrTy = PtrExpr->getType()->getAs(); QualType ElementTy; if (!PtrTy) { - Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) - << PtrArgIdx + 1; + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << PtrArgIdx + 1 << /*pointer to element ty*/ 2 << PtrExpr->getType(); ArgError = true; } else { ElementTy = PtrTy->getPointeeType().getUnqualifiedType(); if (!ConstantMatrixType::isValidElementType(ElementTy)) { - Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) - << PtrArgIdx + 1; + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << PtrArgIdx + 1 << /* pointer to element ty*/ 2 + << PtrExpr->getType(); ArgError = true; } } @@ -16536,7 +16883,7 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, return CallResult; } - // Check row and column dimenions. + // Check row and column dimensions. llvm::Optional MaybeRows; if (RowsExpr) MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this); @@ -16598,7 +16945,8 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, auto *MatrixTy = MatrixExpr->getType()->getAs(); if (!MatrixTy) { - Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_matrix_arg) << 0; + Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << 1 << /*matrix ty */ 1 << MatrixExpr->getType(); ArgError = true; } @@ -16617,8 +16965,8 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, // Check pointer argument. auto *PtrTy = PtrExpr->getType()->getAs(); if (!PtrTy) { - Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) - << PtrArgIdx + 1; + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_invalid_arg_type) + << PtrArgIdx + 1 << /*pointer to element ty*/ 2 << PtrExpr->getType(); ArgError = true; } else { QualType ElementTy = PtrTy->getPointeeType(); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index e03b671ae61..083a67db7a9 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -23,6 +23,7 @@ #include "clang/AST/QualTypeNames.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" +#include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" @@ -34,6 +35,7 @@ #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" @@ -741,9 +743,7 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) { ReservedIdentifierStatus Status = ND->isReserved(SemaRef.getLangOpts()); // Ignore reserved names for compiler provided decls. - if ((Status != ReservedIdentifierStatus::NotReserved) && - (Status != ReservedIdentifierStatus::StartsWithUnderscoreAtGlobalScope) && - ND->getLocation().isInvalid()) + if (isReservedInAllContexts(Status) && ND->getLocation().isInvalid()) return true; // For system headers ignore only double-underscore names. @@ -2821,7 +2821,7 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, bool SuppressBlock = false, Optional> ObjCSubsts = None) { // Params are unavailable in FunctionTypeLoc if the FunctionType is invalid. - // It would be better to pass in the param Type, which is usually avaliable. + // It would be better to pass in the param Type, which is usually available. // But this case is rare, so just pretend we fell back to int as elsewhere. if (!Param) return "int"; @@ -4335,6 +4335,158 @@ void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, Results.data(), Results.size()); } +static const char *underscoreAttrScope(llvm::StringRef Scope) { + if (Scope == "clang") + return "_Clang"; + if (Scope == "gnu") + return "__gnu__"; + return nullptr; +} + +static const char *noUnderscoreAttrScope(llvm::StringRef Scope) { + if (Scope == "_Clang") + return "clang"; + if (Scope == "__gnu__") + return "gnu"; + return nullptr; +} + +void Sema::CodeCompleteAttribute(AttributeCommonInfo::Syntax Syntax, + AttributeCompletion Completion, + const IdentifierInfo *InScope) { + if (Completion == AttributeCompletion::None) + return; + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_Attribute); + + // We're going to iterate over the normalized spellings of the attribute. + // These don't include "underscore guarding": the normalized spelling is + // clang::foo but you can also write _Clang::__foo__. + // + // (Clang supports a mix like clang::__foo__ but we won't suggest it: either + // you care about clashing with macros or you don't). + // + // So if we're already in a scope, we determine its canonical spellings + // (for comparison with normalized attr spelling) and remember whether it was + // underscore-guarded (so we know how to spell contained attributes). + llvm::StringRef InScopeName; + bool InScopeUnderscore = false; + if (InScope) { + InScopeName = InScope->getName(); + if (const char *NoUnderscore = noUnderscoreAttrScope(InScopeName)) { + InScopeName = NoUnderscore; + InScopeUnderscore = true; + } + } + bool SyntaxSupportsGuards = Syntax == AttributeCommonInfo::AS_GNU || + Syntax == AttributeCommonInfo::AS_CXX11 || + Syntax == AttributeCommonInfo::AS_C2x; + + llvm::DenseSet FoundScopes; + auto AddCompletions = [&](const ParsedAttrInfo &A) { + if (A.IsTargetSpecific && !A.existsInTarget(Context.getTargetInfo())) + return; + if (!A.acceptsLangOpts(getLangOpts())) + return; + for (const auto &S : A.Spellings) { + if (S.Syntax != Syntax) + continue; + llvm::StringRef Name = S.NormalizedFullName; + llvm::StringRef Scope; + if ((Syntax == AttributeCommonInfo::AS_CXX11 || + Syntax == AttributeCommonInfo::AS_C2x)) { + std::tie(Scope, Name) = Name.split("::"); + if (Name.empty()) // oops, unscoped + std::swap(Name, Scope); + } + + // Do we just want a list of scopes rather than attributes? + if (Completion == AttributeCompletion::Scope) { + // Make sure to emit each scope only once. + if (!Scope.empty() && FoundScopes.insert(Scope).second) { + Results.AddResult( + CodeCompletionResult(Results.getAllocator().CopyString(Scope))); + // Include alternate form (__gnu__ instead of gnu). + if (const char *Scope2 = underscoreAttrScope(Scope)) + Results.AddResult(CodeCompletionResult(Scope2)); + } + continue; + } + + // If a scope was specified, it must match but we don't need to print it. + if (!InScopeName.empty()) { + if (Scope != InScopeName) + continue; + Scope = ""; + } + + auto Add = [&](llvm::StringRef Scope, llvm::StringRef Name, + bool Underscores) { + CodeCompletionBuilder Builder(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + llvm::SmallString<32> Text; + if (!Scope.empty()) { + Text.append(Scope); + Text.append("::"); + } + if (Underscores) + Text.append("__"); + Text.append(Name); + if (Underscores) + Text.append("__"); + Builder.AddTypedTextChunk(Results.getAllocator().CopyString(Text)); + + if (!A.ArgNames.empty()) { + Builder.AddChunk(CodeCompletionString::CK_LeftParen, "("); + bool First = true; + for (const char *Arg : A.ArgNames) { + if (!First) + Builder.AddChunk(CodeCompletionString::CK_Comma, ", "); + First = false; + Builder.AddPlaceholderChunk(Arg); + } + Builder.AddChunk(CodeCompletionString::CK_RightParen, ")"); + } + + Results.AddResult(Builder.TakeString()); + }; + + // Generate the non-underscore-guarded result. + // Note this is (a suffix of) the NormalizedFullName, no need to copy. + // If an underscore-guarded scope was specified, only the + // underscore-guarded attribute name is relevant. + if (!InScopeUnderscore) + Add(Scope, Name, /*Underscores=*/false); + + // Generate the underscore-guarded version, for syntaxes that support it. + // We skip this if the scope was already spelled and not guarded, or + // we must spell it and can't guard it. + if (!(InScope && !InScopeUnderscore) && SyntaxSupportsGuards) { + llvm::SmallString<32> Guarded; + if (Scope.empty()) { + Add(Scope, Name, /*Underscores=*/true); + } else { + const char *GuardedScope = underscoreAttrScope(Scope); + if (!GuardedScope) + continue; + Add(GuardedScope, Name, /*Underscores=*/true); + } + } + + // It may be nice to include the Kind so we can look up the docs later. + } + }; + + for (const auto *A : ParsedAttrInfo::getAllBuiltin()) + AddCompletions(*A); + for (const auto &Entry : ParsedAttrInfoRegistry::entries()) + AddCompletions(*Entry.instantiate()); + + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + struct Sema::CodeCompleteExpressionData { CodeCompleteExpressionData(QualType PreferredType = QualType(), bool IsParenthesized = false) @@ -5666,7 +5818,8 @@ static void mergeCandidatesWithResults( if (Candidate.Function) { if (Candidate.Function->isDeleted()) continue; - if (!Candidate.Function->isVariadic() && + if (shouldEnforceArgLimit(/*PartialOverloading=*/true, + Candidate.Function) && Candidate.Function->getNumParams() <= ArgSize && // Having zero args is annoying, normally we don't surface a function // with 2 params, if you already have 2 params, because you are @@ -9461,6 +9614,10 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { } } + const StringRef &Dirname = llvm::sys::path::filename(Dir); + const bool isQt = Dirname.startswith("Qt") || Dirname == "ActiveQt"; + const bool ExtensionlessHeaders = + IsSystem || isQt || Dir.endswith(".framework/Headers"); std::error_code EC; unsigned Count = 0; for (auto It = FS.dir_begin(Dir, EC); @@ -9487,18 +9644,19 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { AddCompletion(Filename, /*IsDirectory=*/true); break; - case llvm::sys::fs::file_type::regular_file: - // Only files that really look like headers. (Except in system dirs). - if (!IsSystem) { - // Header extensions from Types.def, which we can't depend on here. - if (!(Filename.endswith_insensitive(".h") || - Filename.endswith_insensitive(".hh") || - Filename.endswith_insensitive(".hpp") || - Filename.endswith_insensitive(".inc"))) - break; - } + case llvm::sys::fs::file_type::regular_file: { + // Only files that really look like headers. (Except in special dirs). + // Header extensions from Types.def, which we can't depend on here. + const bool IsHeader = Filename.endswith_insensitive(".h") || + Filename.endswith_insensitive(".hh") || + Filename.endswith_insensitive(".hpp") || + Filename.endswith_insensitive(".inc") || + (ExtensionlessHeaders && !Filename.contains('.')); + if (!IsHeader) + break; AddCompletion(Filename, /*IsDirectory=*/false); break; + } default: break; } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index f2c70d0a56e..466e37831f6 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1,9 +1,8 @@ //===-- SemaConcept.cpp - Semantic Analysis for Constraints and Concepts --===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -235,7 +234,7 @@ static bool calculateConstraintSatisfaction( // ...If substitution results in an invalid type or expression, the // constraint is not satisfied. if (!Trap.hasErrorOccurred()) - // A non-SFINAE error has occured as a result of this + // A non-SFINAE error has occurred as a result of this // substitution. return ExprError(); @@ -461,7 +460,7 @@ static void diagnoseUnsatisfiedRequirement(Sema &S, Expr *e = Req->getExpr(); S.Diag(e->getBeginLoc(), diag::note_expr_requirement_constraints_not_satisfied_simple) - << (int)First << S.getDecltypeForParenthesizedExpr(e) + << (int)First << S.Context.getReferenceQualifiedType(e) << ConstraintExpr->getNamedConcept(); } else { S.Diag(ConstraintExpr->getBeginLoc(), @@ -742,22 +741,15 @@ Optional NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, ArrayRef E) { assert(E.size() != 0); - auto First = fromConstraintExpr(S, D, E[0]); - if (E.size() == 1) - return First; - auto Second = fromConstraintExpr(S, D, E[1]); - if (!Second) + auto Conjunction = fromConstraintExpr(S, D, E[0]); + if (!Conjunction) return None; - llvm::Optional Conjunction; - Conjunction.emplace(S.Context, std::move(*First), std::move(*Second), - CCK_Conjunction); - for (unsigned I = 2; I < E.size(); ++I) { + for (unsigned I = 1; I < E.size(); ++I) { auto Next = fromConstraintExpr(S, D, E[I]); if (!Next) - return llvm::Optional{}; - NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction), + return None; + *Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction), std::move(*Next), CCK_Conjunction); - *Conjunction = std::move(NewConjunction); } return Conjunction; } @@ -988,8 +980,8 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, // Not the same source level expression - are the expressions // identical? llvm::FoldingSetNodeID IDA, IDB; - EA->Profile(IDA, Context, /*Cannonical=*/true); - EB->Profile(IDB, Context, /*Cannonical=*/true); + EA->Profile(IDA, Context, /*Canonical=*/true); + EB->Profile(IDB, Context, /*Canonical=*/true); if (IDA != IDB) return false; @@ -1073,8 +1065,7 @@ ReturnTypeRequirement(TemplateParameterList *TPL) : assert(TC && "TPL must have a template type parameter with a type constraint"); auto *Constraint = - cast_or_null( - TC->getImmediatelyDeclaredConstraint()); + cast(TC->getImmediatelyDeclaredConstraint()); bool Dependent = Constraint->getTemplateArgsAsWritten() && TemplateSpecializationType::anyInstantiationDependentTemplateArguments( diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 94c728093e7..b999b08d166 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -53,15 +53,10 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, SourceLocation KwLoc) { const FunctionProtoType *FnType = FD->getType()->castAs(); const SourceLocation FuncLoc = FD->getLocation(); - // FIXME: Cache std::coroutine_traits once we've found it. - NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); - if (!StdExp) { - S.Diag(KwLoc, diag::err_implied_coroutine_type_not_found) - << "std::experimental::coroutine_traits"; - return QualType(); - } - ClassTemplateDecl *CoroTraits = S.lookupCoroutineTraits(KwLoc, FuncLoc); + NamespaceDecl *CoroNamespace = nullptr; + ClassTemplateDecl *CoroTraits = + S.lookupCoroutineTraits(KwLoc, FuncLoc, CoroNamespace); if (!CoroTraits) { return QualType(); } @@ -122,7 +117,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, QualType PromiseType = S.Context.getTypeDeclType(Promise); auto buildElaboratedType = [&]() { - auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp); + auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, CoroNamespace); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); return S.Context.getElaboratedType(ETK_None, NNS, PromiseType); @@ -141,20 +136,20 @@ static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, return PromiseType; } -/// Look up the std::experimental::coroutine_handle. +/// Look up the std::coroutine_handle. static QualType lookupCoroutineHandleType(Sema &S, QualType PromiseType, SourceLocation Loc) { if (PromiseType.isNull()) return QualType(); - NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); - assert(StdExp && "Should already be diagnosed"); + NamespaceDecl *CoroNamespace = S.getCachedCoroNamespace(); + assert(CoroNamespace && "Should already be diagnosed"); LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_handle"), Loc, Sema::LookupOrdinaryName); - if (!S.LookupQualifiedName(Result, StdExp)) { + if (!S.LookupQualifiedName(Result, CoroNamespace)) { S.Diag(Loc, diag::err_implied_coroutine_type_not_found) - << "std::experimental::coroutine_handle"; + << "std::coroutine_handle"; return QualType(); } @@ -1000,7 +995,7 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) { LookupResult Result(S, &S.PP.getIdentifierTable().get("nothrow"), Loc, Sema::LookupOrdinaryName); if (!S.LookupQualifiedName(Result, Std)) { - // FIXME: should have been included already. + // FIXME: should have been included already. // If we require it to include then this diagnostic is no longer // needed. S.Diag(Loc, diag::err_implicit_coroutine_std_nothrow_type_not_found); @@ -1533,7 +1528,7 @@ bool CoroutineStmtBuilder::makeGroDeclAndReturnStmt() { if (GroType->isVoidType()) { // Trigger a nice error message. InitializedEntity Entity = - InitializedEntity::InitializeResult(Loc, FnRetType, false); + InitializedEntity::InitializeResult(Loc, FnRetType); S.PerformCopyInitialization(Entity, SourceLocation(), ReturnValue); noteMemberDeclaredHere(S, ReturnValue, Fn); return false; @@ -1663,25 +1658,47 @@ StmtResult Sema::BuildCoroutineBodyStmt(CoroutineBodyStmt::CtorArgs Args) { } ClassTemplateDecl *Sema::lookupCoroutineTraits(SourceLocation KwLoc, - SourceLocation FuncLoc) { + SourceLocation FuncLoc, + NamespaceDecl *&Namespace) { if (!StdCoroutineTraitsCache) { - if (auto StdExp = lookupStdExperimentalNamespace()) { - LookupResult Result(*this, - &PP.getIdentifierTable().get("coroutine_traits"), - FuncLoc, LookupOrdinaryName); - if (!LookupQualifiedName(Result, StdExp)) { + NamespaceDecl *CoroNamespace = getStdNamespace(); + LookupResult Result(*this, &PP.getIdentifierTable().get("coroutine_traits"), + FuncLoc, LookupOrdinaryName); + + if (!CoroNamespace || !LookupQualifiedName(Result, CoroNamespace)) { + /// Look up in namespace std::experimental, for compatibility. + /// TODO: Remove this extra lookup when is + /// removed. + CoroNamespace = lookupStdExperimentalNamespace(); + if (!CoroNamespace || !LookupQualifiedName(Result, CoroNamespace)) { Diag(KwLoc, diag::err_implied_coroutine_type_not_found) - << "std::experimental::coroutine_traits"; + << "std::coroutine_traits"; return nullptr; } - if (!(StdCoroutineTraitsCache = - Result.getAsSingle())) { - Result.suppressDiagnostics(); - NamedDecl *Found = *Result.begin(); - Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + Diag(KwLoc, diag::warn_deprecated_coroutine_namespace) + << "coroutine_traits"; + } else { + /// When we found coroutine_traits in std namespace. Make sure there is no + /// misleading definition in std::experimental namespace. + NamespaceDecl *ExpNamespace = lookupStdExperimentalNamespace(); + LookupResult ExpResult(*this, + &PP.getIdentifierTable().get("coroutine_traits"), + FuncLoc, LookupOrdinaryName); + if (ExpNamespace && LookupQualifiedName(ExpResult, ExpNamespace)) { + Diag(KwLoc, + diag::err_mixed_use_std_and_experimental_namespace_for_coroutine); return nullptr; } } + + if (!(StdCoroutineTraitsCache = Result.getAsSingle())) { + Result.suppressDiagnostics(); + NamedDecl *Found = *Result.begin(); + Diag(Found->getLocation(), diag::err_malformed_std_coroutine_traits); + return nullptr; + } + CoroTraitsNamespaceCache = CoroNamespace; } + Namespace = CoroTraitsNamespaceCache; return StdCoroutineTraitsCache; } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 205f5800030..4fcc01012d4 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -141,6 +141,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw___bf16: case tok::kw__Float16: case tok::kw___float128: + case tok::kw___ibm128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: @@ -1920,8 +1921,10 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { } void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) { - // If it's not referenced, it can't be set. - if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr()) + // If it's not referenced, it can't be set. If it has the Cleanup attribute, + // it's not really unused. + if (!VD->isReferenced() || !VD->getDeclName() || VD->hasAttr() || + VD->hasAttr()) return; const auto *Ty = VD->getType().getTypePtr()->getBaseElementTypeUnsafe(); @@ -1941,6 +1944,12 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD) { } } + // Don't warn about __block Objective-C pointer variables, as they might + // be assigned in the block but not used elsewhere for the purpose of lifetime + // extension. + if (VD->hasAttr() && Ty->isObjCObjectPointerType()) + return; + auto iter = RefsMinusAssignments.find(VD); if (iter == RefsMinusAssignments.end()) return; @@ -2113,8 +2122,9 @@ FunctionDecl *Sema::CreateBuiltin(IdentifierInfo *II, QualType Type, } FunctionDecl *New = FunctionDecl::Create(Context, Parent, Loc, Loc, II, Type, - /*TInfo=*/nullptr, SC_Extern, false, - Type->isFunctionProtoType()); + /*TInfo=*/nullptr, SC_Extern, + getCurFPFeatures().isFPConstrained(), + false, Type->isFunctionProtoType()); New->setImplicit(); New->addAttr(BuiltinAttr::CreateImplicit(Context, ID)); @@ -2627,6 +2637,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeDLLImportAttr(D, *ImportA); else if (const auto *ExportA = dyn_cast(Attr)) NewAttr = S.mergeDLLExportAttr(D, *ExportA); + else if (const auto *EA = dyn_cast(Attr)) + NewAttr = S.mergeErrorAttr(D, *EA, EA->getUserDiagnostic()); else if (const auto *FA = dyn_cast(Attr)) NewAttr = S.mergeFormatAttr(D, *FA, FA->getType(), FA->getFormatIdx(), FA->getFirstArg()); @@ -2673,6 +2685,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeEnforceTCBAttr(D, *TCBA); else if (const auto *TCBLA = dyn_cast(Attr)) NewAttr = S.mergeEnforceTCBLeafAttr(D, *TCBLA); + else if (const auto *BTFA = dyn_cast(Attr)) + NewAttr = S.mergeBTFDeclTagAttr(D, *BTFA); else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast(Attr->clone(S.Context)); @@ -2954,8 +2968,7 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, if (const auto *NewAbiTagAttr = New->getAttr()) { if (const auto *OldAbiTagAttr = Old->getAttr()) { for (const auto &NewTag : NewAbiTagAttr->tags()) { - if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(), - NewTag) == OldAbiTagAttr->tags_end()) { + if (!llvm::is_contained(OldAbiTagAttr->tags(), NewTag)) { Diag(NewAbiTagAttr->getLocation(), diag::err_new_abi_tag_on_redeclaration) << NewTag; @@ -3352,12 +3365,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } } - if (New->hasAttr() && - !Old->hasAttr()) { - Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) - << New->getDeclName(); - notePreviousDefinition(Old, New->getLocation()); - New->dropAttr(); + if (const auto *ILA = New->getAttr()) + if (!Old->hasAttr()) { + Diag(New->getLocation(), diag::err_attribute_missing_on_first_decl) + << ILA; + Diag(Old->getLocation(), diag::note_previous_declaration); + New->dropAttr(); + } + + if (auto *EA = New->getAttr()) { + if (!Old->hasAttr()) { + Diag(EA->getLocation(), diag::err_attribute_missing_on_first_decl) << EA; + Diag(Old->getLocation(), diag::note_previous_declaration); + New->dropAttr(); + } } if (CheckRedeclarationModuleOwnership(New, Old)) @@ -3592,14 +3613,14 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // defined, copy the deduced value from the old declaration. AutoType *OldAT = Old->getReturnType()->getContainedAutoType(); if (OldAT && OldAT->isDeduced()) { - New->setType( - SubstAutoType(New->getType(), - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); - NewQType = Context.getCanonicalType( - SubstAutoType(NewQType, - OldAT->isDependentType() ? Context.DependentTy - : OldAT->getDeducedType())); + QualType DT = OldAT->getDeducedType(); + if (DT.isNull()) { + New->setType(SubstAutoTypeDependent(New->getType())); + NewQType = Context.getCanonicalType(SubstAutoTypeDependent(NewQType)); + } else { + New->setType(SubstAutoType(New->getType(), DT)); + NewQType = Context.getCanonicalType(SubstAutoType(NewQType, DT)); + } } } @@ -3677,12 +3698,12 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // The first declaration of a function shall specify the noreturn // attribute if any declaration of that function specifies the noreturn // attribute. - const CXX11NoReturnAttr *NRA = New->getAttr(); - if (NRA && !Old->hasAttr()) { - Diag(NRA->getLocation(), diag::err_noreturn_missing_on_first_decl); - Diag(Old->getFirstDecl()->getLocation(), - diag::note_noreturn_missing_first_decl); - } + if (const auto *NRA = New->getAttr()) + if (!Old->hasAttr()) { + Diag(NRA->getLocation(), diag::err_attribute_missing_on_first_decl) + << NRA; + Diag(Old->getLocation(), diag::note_previous_declaration); + } // C++11 [dcl.attr.depend]p2: // The first declaration of a function shall specify the @@ -4160,18 +4181,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { Old->getStorageClass() == SC_None && !Old->hasAttr()) { Diag(New->getLocation(), diag::warn_weak_import) << New->getDeclName(); - notePreviousDefinition(Old, New->getLocation()); + Diag(Old->getLocation(), diag::note_previous_declaration); // Remove weak_import attribute on new declaration. New->dropAttr(); } - if (New->hasAttr() && - !Old->hasAttr()) { - Diag(New->getLocation(), diag::err_internal_linkage_redeclaration) - << New->getDeclName(); - notePreviousDefinition(Old, New->getLocation()); - New->dropAttr(); - } + if (const auto *ILA = New->getAttr()) + if (!Old->hasAttr()) { + Diag(New->getLocation(), diag::err_attribute_missing_on_first_decl) + << ILA; + Diag(Old->getLocation(), diag::note_previous_declaration); + New->dropAttr(); + } // Merge the types. VarDecl *MostRecent = Old->getMostRecentDecl(); @@ -5281,8 +5302,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // trivial in almost all cases, except if a union member has an in-class // initializer: // union { int n = 0; }; - if (!Invalid) - ActOnUninitializedDecl(Anon); + ActOnUninitializedDecl(Anon); } Anon->setImplicit(); @@ -5761,8 +5781,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data()); while (SpecLoc.getPrefix()) SpecLoc = SpecLoc.getPrefix(); - if (dyn_cast_or_null( - SpecLoc.getNestedNameSpecifier()->getAsType())) + if (isa_and_nonnull( + SpecLoc.getNestedNameSpecifier()->getAsType())) Diag(Loc, diag::err_decltype_in_declarator) << SpecLoc.getTypeLoc().getSourceRange(); @@ -7327,10 +7347,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec(); if (TSC != TSCS_unspecified) { - bool IsCXX = getLangOpts().OpenCLCPlusPlus; Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_opencl_unknown_type_specifier) - << IsCXX << getLangOpts().getOpenCLVersionTuple().getAsString() + << getLangOpts().getOpenCLVersionString() << DeclSpec::getSpecifierName(TSC) << 1; NewVD->setInvalidDecl(); } @@ -8552,10 +8571,11 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!R->getAsAdjusted() && R->isFunctionProtoType()); - NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo, - R, TInfo, SC, isInline, HasPrototype, - ConstexprSpecKind::Unspecified, - /*TrailingRequiresClause=*/nullptr); + NewFD = FunctionDecl::Create( + SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, + SemaRef.getCurFPFeatures().isFPConstrained(), isInline, HasPrototype, + ConstexprSpecKind::Unspecified, + /*TrailingRequiresClause=*/nullptr); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -8591,9 +8611,9 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, R = SemaRef.CheckConstructorDeclarator(D, R, SC); return CXXConstructorDecl::Create( SemaRef.Context, cast(DC), D.getBeginLoc(), NameInfo, R, - TInfo, ExplicitSpecifier, isInline, - /*isImplicitlyDeclared=*/false, ConstexprKind, InheritedConstructor(), - TrailingRequiresClause); + TInfo, ExplicitSpecifier, SemaRef.getCurFPFeatures().isFPConstrained(), + isInline, /*isImplicitlyDeclared=*/false, ConstexprKind, + InheritedConstructor(), TrailingRequiresClause); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. @@ -8602,7 +8622,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, CXXRecordDecl *Record = cast(DC); CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo, - isInline, /*isImplicitlyDeclared=*/false, ConstexprKind, + SemaRef.getCurFPFeatures().isFPConstrained(), isInline, + /*isImplicitlyDeclared=*/false, ConstexprKind, TrailingRequiresClause); // If the destructor needs an implicit exception specification, set it @@ -8620,11 +8641,10 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // Create a FunctionDecl to satisfy the function definition parsing // code path. - return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), - D.getIdentifierLoc(), Name, R, TInfo, SC, - isInline, - /*hasPrototype=*/true, ConstexprKind, - TrailingRequiresClause); + return FunctionDecl::Create( + SemaRef.Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), Name, R, + TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline, + /*hasPrototype=*/true, ConstexprKind, TrailingRequiresClause); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { @@ -8641,7 +8661,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, IsVirtualOkay = true; return CXXConversionDecl::Create( SemaRef.Context, cast(DC), D.getBeginLoc(), NameInfo, R, - TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation(), + TInfo, SemaRef.getCurFPFeatures().isFPConstrained(), isInline, + ExplicitSpecifier, ConstexprKind, SourceLocation(), TrailingRequiresClause); } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { @@ -8670,8 +8691,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // This is a C++ method declaration. CXXMethodDecl *Ret = CXXMethodDecl::Create( SemaRef.Context, cast(DC), D.getBeginLoc(), NameInfo, R, - TInfo, SC, isInline, ConstexprKind, SourceLocation(), - TrailingRequiresClause); + TInfo, SC, SemaRef.getCurFPFeatures().isFPConstrained(), isInline, + ConstexprKind, SourceLocation(), TrailingRequiresClause); IsVirtualOkay = !Ret->isStatic(); return Ret; } else { @@ -8683,9 +8704,10 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // Determine whether the function was written with a // prototype. This true when: // - we're in C++ (where every function has a prototype), - return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo, - R, TInfo, SC, isInline, true /*HasPrototype*/, - ConstexprKind, TrailingRequiresClause); + return FunctionDecl::Create( + SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, + SemaRef.getCurFPFeatures().isFPConstrained(), isInline, + true /*HasPrototype*/, ConstexprKind, TrailingRequiresClause); } } @@ -8819,8 +8841,7 @@ static void checkIsValidOpenCLKernelParameter( // OpenCL v3.0 s6.11.a: // A kernel function argument cannot be declared as a pointer to a pointer // type. [...] This restriction only applies to OpenCL C 1.2 or below. - if (S.getLangOpts().OpenCLVersion <= 120 && - !S.getLangOpts().OpenCLCPlusPlus) { + if (S.getLangOpts().getOpenCLCompatibleVersion() <= 120) { S.Diag(Param->getLocation(), diag::err_opencl_ptrptr_kernel_param); D.setInvalidType(); return; @@ -9087,8 +9108,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++ [class.union]p2 // A union can have member functions, but not virtual functions. - if (isVirtual && Parent->isUnion()) + if (isVirtual && Parent->isUnion()) { Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_in_union); + NewFD->setInvalidDecl(); + } } SetNestedNameSpecifier(*this, NewFD, D); @@ -9235,8 +9258,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // a friend yet, so 'isDependentContext' on the FD doesn't work. const FunctionProtoType *FPT = NewFD->getType()->castAs(); - QualType Result = - SubstAutoType(FPT->getReturnType(), Context.DependentTy); + QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo())); } @@ -9554,9 +9576,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) - checkDeviceDecl(NewFD, D.getBeginLoc()); - if (!getLangOpts().CPlusPlus) { // Perform semantic checking on the function declaration. if (!NewFD->isInvalidDecl() && NewFD->isMain()) @@ -9955,8 +9974,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().OpenCL && NewFD->hasAttr()) { // OpenCL v1.2 s6.8 static is invalid for kernel functions. - if ((getLangOpts().OpenCLVersion >= 120) - && (SC == SC_Static)) { + if (SC == SC_Static) { Diag(D.getIdentifierLoc(), diag::err_static_kernel); D.setInvalidType(); } @@ -10002,7 +10020,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value // types. - if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) { + if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { if(const PipeType *PipeTy = PT->getAs()) { QualType ElemTy = PipeTy->getElementType(); if (ElemTy->isReferenceType() || ElemTy->isPointerType()) { @@ -10306,8 +10324,8 @@ bool Sema::areMultiversionVariantFunctionsCompatible( ReturnType = 1, ConstexprSpec = 2, InlineSpec = 3, - StorageClass = 4, - Linkage = 5, + Linkage = 4, + LanguageLinkage = 5, }; if (NoProtoDiagID.getDiagID() != 0 && OldFD && @@ -10381,11 +10399,11 @@ bool Sema::areMultiversionVariantFunctionsCompatible( if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec; - if (OldFD->getStorageClass() != NewFD->getStorageClass()) - return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass; + if (OldFD->getFormalLinkage() != NewFD->getFormalLinkage()) + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC()) - return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << LanguageLinkage; if (CheckEquivalentExceptionSpec( OldFD->getType()->getAs(), OldFD->getLocation(), @@ -12331,7 +12349,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - // If the provied initializer fails to initialize the var decl, + // If the provided initializer fails to initialize the var decl, // we attach a recovery expr for better recovery. auto RecoveryExpr = CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); @@ -12595,7 +12613,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInitStyle(VarDecl::ListInit); } - if (LangOpts.OpenMP && VDecl->isFileVarDecl()) + if (LangOpts.OpenMP && + (LangOpts.OpenMPIsDevice || !LangOpts.OMPTargetTriples.empty()) && + VDecl->isFileVarDecl()) DeclsToCheckForDeferredDiags.insert(VDecl); CheckCompleteVariableDeclaration(VDecl); } @@ -14477,7 +14497,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, FunctionScopeInfo *FSI = getCurFunction(); FunctionDecl *FD = dcl ? dcl->getAsFunction() : nullptr; - if (FSI->UsesFPIntrin && !FD->hasAttr()) + if (FSI->UsesFPIntrin && FD && !FD->hasAttr()) FD->addAttr(StrictFPAttr::CreateImplicit(Context)); sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); @@ -14486,333 +14506,340 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (getLangOpts().Coroutines && FSI->isCoroutine()) CheckCompletedCoroutineBody(FD, Body); - // Do not call PopExpressionEvaluationContext() if it is a lambda because one - // is already popped when finishing the lambda in BuildLambdaExpr(). This is - // meant to pop the context added in ActOnStartOfFunctionDef(). - ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); + { + // Do not call PopExpressionEvaluationContext() if it is a lambda because + // one is already popped when finishing the lambda in BuildLambdaExpr(). + // This is meant to pop the context added in ActOnStartOfFunctionDef(). + ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); - if (FD) { - FD->setBody(Body); - FD->setWillHaveBody(false); + if (FD) { + FD->setBody(Body); + FD->setWillHaveBody(false); - if (getLangOpts().CPlusPlus14) { - if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && - FD->getReturnType()->isUndeducedType()) { - // If the function has a deduced result type but contains no 'return' - // statements, the result type as written must be exactly 'auto', and - // the deduced result type is 'void'. - if (!FD->getReturnType()->getAs()) { - Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) - << FD->getReturnType(); - FD->setInvalidDecl(); - } else { - // Substitute 'void' for the 'auto' in the type. - TypeLoc ResultType = getReturnTypeLoc(FD); - Context.adjustDeducedFunctionResultType( - FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); - } - } - } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { - // In C++11, we don't use 'auto' deduction rules for lambda call - // operators because we don't support return type deduction. - auto *LSI = getCurLambda(); - if (LSI->HasImplicitReturnType) { - deduceClosureReturnType(*LSI); - - // C++11 [expr.prim.lambda]p4: - // [...] if there are no return statements in the compound-statement - // [the deduced type is] the type void - QualType RetType = - LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; - - // Update the return type to the deduced type. - const auto *Proto = FD->getType()->castAs(); - FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), - Proto->getExtProtoInfo())); - } - } - - // If the function implicitly returns zero (like 'main') or is naked, - // don't complain about missing return statements. - if (FD->hasImplicitReturnZero() || FD->hasAttr()) - WP.disableCheckFallThrough(); - - // MSVC permits the use of pure specifier (=0) on function definition, - // defined at class scope, warn about this non-standard construct. - if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine()) - Diag(FD->getLocation(), diag::ext_pure_function_definition); - - if (!FD->isInvalidDecl()) { - // Don't diagnose unused parameters of defaulted or deleted functions. - if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody()) - DiagnoseUnusedParameters(FD->parameters()); - DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), - FD->getReturnType(), FD); - - // If this is a structor, we need a vtable. - if (CXXConstructorDecl *Constructor = dyn_cast(FD)) - MarkVTableUsed(FD->getLocation(), Constructor->getParent()); - else if (CXXDestructorDecl *Destructor = dyn_cast(FD)) - MarkVTableUsed(FD->getLocation(), Destructor->getParent()); - - // Try to apply the named return value optimization. We have to check - // if we can do this here because lambdas keep return statements around - // to deduce an implicit return type. - if (FD->getReturnType()->isRecordType() && - (!getLangOpts().CPlusPlus || !FD->isDependentContext())) - computeNRVO(Body, FSI); - } - - // GNU warning -Wmissing-prototypes: - // Warn if a global function is defined without a previous - // prototype declaration. This warning is issued even if the - // definition itself provides a prototype. The aim is to detect - // global functions that fail to be declared in header files. - const FunctionDecl *PossiblePrototype = nullptr; - if (ShouldWarnAboutMissingPrototype(FD, PossiblePrototype)) { - Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; - - if (PossiblePrototype) { - // We found a declaration that is not a prototype, - // but that could be a zero-parameter prototype - if (TypeSourceInfo *TI = PossiblePrototype->getTypeSourceInfo()) { - TypeLoc TL = TI->getTypeLoc(); - if (FunctionNoProtoTypeLoc FTL = TL.getAs()) - Diag(PossiblePrototype->getLocation(), - diag::note_declaration_not_a_prototype) - << (FD->getNumParams() != 0) - << (FD->getNumParams() == 0 - ? FixItHint::CreateInsertion(FTL.getRParenLoc(), "void") - : FixItHint{}); - } - } else { - // Returns true if the token beginning at this Loc is `const`. - auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM, - const LangOptions &LangOpts) { - std::pair LocInfo = SM.getDecomposedLoc(Loc); - if (LocInfo.first.isInvalid()) - return false; - - bool Invalid = false; - StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); - if (Invalid) - return false; - - if (LocInfo.second > Buffer.size()) - return false; - - const char *LexStart = Buffer.data() + LocInfo.second; - StringRef StartTok(LexStart, Buffer.size() - LocInfo.second); - - return StartTok.consume_front("const") && - (StartTok.empty() || isWhitespace(StartTok[0]) || - StartTok.startswith("/*") || StartTok.startswith("//")); - }; - - auto findBeginLoc = [&]() { - // If the return type has `const` qualifier, we want to insert - // `static` before `const` (and not before the typename). - if ((FD->getReturnType()->isAnyPointerType() && - FD->getReturnType()->getPointeeType().isConstQualified()) || - FD->getReturnType().isConstQualified()) { - // But only do this if we can determine where the `const` is. - - if (isLocAtConst(FD->getBeginLoc(), getSourceManager(), - getLangOpts())) - - return FD->getBeginLoc(); + if (getLangOpts().CPlusPlus14) { + if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && + FD->getReturnType()->isUndeducedType()) { + // If the function has a deduced result type but contains no 'return' + // statements, the result type as written must be exactly 'auto', and + // the deduced result type is 'void'. + if (!FD->getReturnType()->getAs()) { + Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) + << FD->getReturnType(); + FD->setInvalidDecl(); + } else { + // Substitute 'void' for the 'auto' in the type. + TypeLoc ResultType = getReturnTypeLoc(FD); + Context.adjustDeducedFunctionResultType( + FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); } - return FD->getTypeSpecStartLoc(); - }; - Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage) - << /* function */ 1 - << (FD->getStorageClass() == SC_None - ? FixItHint::CreateInsertion(findBeginLoc(), "static ") - : FixItHint{}); - } + } + } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { + // In C++11, we don't use 'auto' deduction rules for lambda call + // operators because we don't support return type deduction. + auto *LSI = getCurLambda(); + if (LSI->HasImplicitReturnType) { + deduceClosureReturnType(*LSI); - // GNU warning -Wstrict-prototypes - // Warn if K&R function is defined without a previous declaration. - // This warning is issued only if the definition itself does not provide - // a prototype. Only K&R definitions do not provide a prototype. - if (!FD->hasWrittenPrototype()) { - TypeSourceInfo *TI = FD->getTypeSourceInfo(); - TypeLoc TL = TI->getTypeLoc(); - FunctionTypeLoc FTL = TL.getAsAdjusted(); - Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2; - } - } + // C++11 [expr.prim.lambda]p4: + // [...] if there are no return statements in the compound-statement + // [the deduced type is] the type void + QualType RetType = + LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; - // Warn on CPUDispatch with an actual body. - if (FD->isMultiVersion() && FD->hasAttr() && Body) - if (const auto *CmpndBody = dyn_cast(Body)) - if (!CmpndBody->body_empty()) - Diag(CmpndBody->body_front()->getBeginLoc(), - diag::warn_dispatch_body_ignored); - - if (auto *MD = dyn_cast(FD)) { - const CXXMethodDecl *KeyFunction; - if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && - MD->isVirtual() && - (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && - MD == KeyFunction->getCanonicalDecl()) { - // Update the key-function state if necessary for this ABI. - if (FD->isInlined() && - !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { - Context.setNonKeyFunction(MD); - - // If the newly-chosen key function is already defined, then we - // need to mark the vtable as used retroactively. - KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); - const FunctionDecl *Definition; - if (KeyFunction && KeyFunction->isDefined(Definition)) - MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); - } else { - // We just defined they key function; mark the vtable as used. - MarkVTableUsed(FD->getLocation(), MD->getParent(), true); + // Update the return type to the deduced type. + const auto *Proto = FD->getType()->castAs(); + FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), + Proto->getExtProtoInfo())); } } - } - assert((FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && - "Function parsing confused"); - } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { - assert(MD == getCurMethodDecl() && "Method parsing confused"); - MD->setBody(Body); - if (!MD->isInvalidDecl()) { - DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), - MD->getReturnType(), MD); + // If the function implicitly returns zero (like 'main') or is naked, + // don't complain about missing return statements. + if (FD->hasImplicitReturnZero() || FD->hasAttr()) + WP.disableCheckFallThrough(); - if (Body) - computeNRVO(Body, FSI); - } - if (FSI->ObjCShouldCallSuper) { - Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call) - << MD->getSelector().getAsString(); - FSI->ObjCShouldCallSuper = false; - } - if (FSI->ObjCWarnForNoDesignatedInitChain) { - const ObjCMethodDecl *InitMethod = nullptr; - bool isDesignated = - MD->isDesignatedInitializerForTheInterface(&InitMethod); - assert(isDesignated && InitMethod); - (void)isDesignated; + // MSVC permits the use of pure specifier (=0) on function definition, + // defined at class scope, warn about this non-standard construct. + if (getLangOpts().MicrosoftExt && FD->isPure() && !FD->isOutOfLine()) + Diag(FD->getLocation(), diag::ext_pure_function_definition); - auto superIsNSObject = [&](const ObjCMethodDecl *MD) { - auto IFace = MD->getClassInterface(); - if (!IFace) - return false; - auto SuperD = IFace->getSuperClass(); - if (!SuperD) - return false; - return SuperD->getIdentifier() == - NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); - }; - // Don't issue this warning for unavailable inits or direct subclasses - // of NSObject. - if (!MD->isUnavailable() && !superIsNSObject(MD)) { - Diag(MD->getLocation(), - diag::warn_objc_designated_init_missing_super_call); - Diag(InitMethod->getLocation(), - diag::note_objc_designated_init_marked_here); + if (!FD->isInvalidDecl()) { + // Don't diagnose unused parameters of defaulted or deleted functions. + if (!FD->isDeleted() && !FD->isDefaulted() && !FD->hasSkippedBody()) + DiagnoseUnusedParameters(FD->parameters()); + DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), + FD->getReturnType(), FD); + + // If this is a structor, we need a vtable. + if (CXXConstructorDecl *Constructor = dyn_cast(FD)) + MarkVTableUsed(FD->getLocation(), Constructor->getParent()); + else if (CXXDestructorDecl *Destructor = + dyn_cast(FD)) + MarkVTableUsed(FD->getLocation(), Destructor->getParent()); + + // Try to apply the named return value optimization. We have to check + // if we can do this here because lambdas keep return statements around + // to deduce an implicit return type. + if (FD->getReturnType()->isRecordType() && + (!getLangOpts().CPlusPlus || !FD->isDependentContext())) + computeNRVO(Body, FSI); } - FSI->ObjCWarnForNoDesignatedInitChain = false; - } - if (FSI->ObjCWarnForNoInitDelegation) { - // Don't issue this warning for unavaialable inits. - if (!MD->isUnavailable()) - Diag(MD->getLocation(), - diag::warn_objc_secondary_init_missing_init_call); - FSI->ObjCWarnForNoInitDelegation = false; + + // GNU warning -Wmissing-prototypes: + // Warn if a global function is defined without a previous + // prototype declaration. This warning is issued even if the + // definition itself provides a prototype. The aim is to detect + // global functions that fail to be declared in header files. + const FunctionDecl *PossiblePrototype = nullptr; + if (ShouldWarnAboutMissingPrototype(FD, PossiblePrototype)) { + Diag(FD->getLocation(), diag::warn_missing_prototype) << FD; + + if (PossiblePrototype) { + // We found a declaration that is not a prototype, + // but that could be a zero-parameter prototype + if (TypeSourceInfo *TI = PossiblePrototype->getTypeSourceInfo()) { + TypeLoc TL = TI->getTypeLoc(); + if (FunctionNoProtoTypeLoc FTL = TL.getAs()) + Diag(PossiblePrototype->getLocation(), + diag::note_declaration_not_a_prototype) + << (FD->getNumParams() != 0) + << (FD->getNumParams() == 0 ? FixItHint::CreateInsertion( + FTL.getRParenLoc(), "void") + : FixItHint{}); + } + } else { + // Returns true if the token beginning at this Loc is `const`. + auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + std::pair LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first.isInvalid()) + return false; + + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return false; + + if (LocInfo.second > Buffer.size()) + return false; + + const char *LexStart = Buffer.data() + LocInfo.second; + StringRef StartTok(LexStart, Buffer.size() - LocInfo.second); + + return StartTok.consume_front("const") && + (StartTok.empty() || isWhitespace(StartTok[0]) || + StartTok.startswith("/*") || StartTok.startswith("//")); + }; + + auto findBeginLoc = [&]() { + // If the return type has `const` qualifier, we want to insert + // `static` before `const` (and not before the typename). + if ((FD->getReturnType()->isAnyPointerType() && + FD->getReturnType()->getPointeeType().isConstQualified()) || + FD->getReturnType().isConstQualified()) { + // But only do this if we can determine where the `const` is. + + if (isLocAtConst(FD->getBeginLoc(), getSourceManager(), + getLangOpts())) + + return FD->getBeginLoc(); + } + return FD->getTypeSpecStartLoc(); + }; + Diag(FD->getTypeSpecStartLoc(), + diag::note_static_for_internal_linkage) + << /* function */ 1 + << (FD->getStorageClass() == SC_None + ? FixItHint::CreateInsertion(findBeginLoc(), "static ") + : FixItHint{}); + } + + // GNU warning -Wstrict-prototypes + // Warn if K&R function is defined without a previous declaration. + // This warning is issued only if the definition itself does not + // provide a prototype. Only K&R definitions do not provide a + // prototype. + if (!FD->hasWrittenPrototype()) { + TypeSourceInfo *TI = FD->getTypeSourceInfo(); + TypeLoc TL = TI->getTypeLoc(); + FunctionTypeLoc FTL = TL.getAsAdjusted(); + Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 2; + } + } + + // Warn on CPUDispatch with an actual body. + if (FD->isMultiVersion() && FD->hasAttr() && Body) + if (const auto *CmpndBody = dyn_cast(Body)) + if (!CmpndBody->body_empty()) + Diag(CmpndBody->body_front()->getBeginLoc(), + diag::warn_dispatch_body_ignored); + + if (auto *MD = dyn_cast(FD)) { + const CXXMethodDecl *KeyFunction; + if (MD->isOutOfLine() && (MD = MD->getCanonicalDecl()) && + MD->isVirtual() && + (KeyFunction = Context.getCurrentKeyFunction(MD->getParent())) && + MD == KeyFunction->getCanonicalDecl()) { + // Update the key-function state if necessary for this ABI. + if (FD->isInlined() && + !Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline()) { + Context.setNonKeyFunction(MD); + + // If the newly-chosen key function is already defined, then we + // need to mark the vtable as used retroactively. + KeyFunction = Context.getCurrentKeyFunction(MD->getParent()); + const FunctionDecl *Definition; + if (KeyFunction && KeyFunction->isDefined(Definition)) + MarkVTableUsed(Definition->getLocation(), MD->getParent(), true); + } else { + // We just defined they key function; mark the vtable as used. + MarkVTableUsed(FD->getLocation(), MD->getParent(), true); + } + } + } + + assert( + (FD == getCurFunctionDecl() || getCurLambda()->CallOperator == FD) && + "Function parsing confused"); + } else if (ObjCMethodDecl *MD = dyn_cast_or_null(dcl)) { + assert(MD == getCurMethodDecl() && "Method parsing confused"); + MD->setBody(Body); + if (!MD->isInvalidDecl()) { + DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), + MD->getReturnType(), MD); + + if (Body) + computeNRVO(Body, FSI); + } + if (FSI->ObjCShouldCallSuper) { + Diag(MD->getEndLoc(), diag::warn_objc_missing_super_call) + << MD->getSelector().getAsString(); + FSI->ObjCShouldCallSuper = false; + } + if (FSI->ObjCWarnForNoDesignatedInitChain) { + const ObjCMethodDecl *InitMethod = nullptr; + bool isDesignated = + MD->isDesignatedInitializerForTheInterface(&InitMethod); + assert(isDesignated && InitMethod); + (void)isDesignated; + + auto superIsNSObject = [&](const ObjCMethodDecl *MD) { + auto IFace = MD->getClassInterface(); + if (!IFace) + return false; + auto SuperD = IFace->getSuperClass(); + if (!SuperD) + return false; + return SuperD->getIdentifier() == + NSAPIObj->getNSClassId(NSAPI::ClassId_NSObject); + }; + // Don't issue this warning for unavailable inits or direct subclasses + // of NSObject. + if (!MD->isUnavailable() && !superIsNSObject(MD)) { + Diag(MD->getLocation(), + diag::warn_objc_designated_init_missing_super_call); + Diag(InitMethod->getLocation(), + diag::note_objc_designated_init_marked_here); + } + FSI->ObjCWarnForNoDesignatedInitChain = false; + } + if (FSI->ObjCWarnForNoInitDelegation) { + // Don't issue this warning for unavaialable inits. + if (!MD->isUnavailable()) + Diag(MD->getLocation(), + diag::warn_objc_secondary_init_missing_init_call); + FSI->ObjCWarnForNoInitDelegation = false; + } + + diagnoseImplicitlyRetainedSelf(*this); + } else { + // Parsing the function declaration failed in some way. Pop the fake scope + // we pushed on. + PopFunctionScopeInfo(ActivePolicy, dcl); + return nullptr; } - diagnoseImplicitlyRetainedSelf(*this); - } else { - // Parsing the function declaration failed in some way. Pop the fake scope - // we pushed on. - PopFunctionScopeInfo(ActivePolicy, dcl); - return nullptr; - } + if (Body && FSI->HasPotentialAvailabilityViolations) + DiagnoseUnguardedAvailabilityViolations(dcl); - if (Body && FSI->HasPotentialAvailabilityViolations) - DiagnoseUnguardedAvailabilityViolations(dcl); + assert(!FSI->ObjCShouldCallSuper && + "This should only be set for ObjC methods, which should have been " + "handled in the block above."); - assert(!FSI->ObjCShouldCallSuper && - "This should only be set for ObjC methods, which should have been " - "handled in the block above."); + // Verify and clean out per-function state. + if (Body && (!FD || !FD->isDefaulted())) { + // C++ constructors that have function-try-blocks can't have return + // statements in the handlers of that block. (C++ [except.handle]p14) + // Verify this. + if (FD && isa(FD) && isa(Body)) + DiagnoseReturnInConstructorExceptionHandler(cast(Body)); - // Verify and clean out per-function state. - if (Body && (!FD || !FD->isDefaulted())) { - // C++ constructors that have function-try-blocks can't have return - // statements in the handlers of that block. (C++ [except.handle]p14) - // Verify this. - if (FD && isa(FD) && isa(Body)) - DiagnoseReturnInConstructorExceptionHandler(cast(Body)); + // Verify that gotos and switch cases don't jump into scopes illegally. + if (FSI->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) + DiagnoseInvalidJumps(Body); - // Verify that gotos and switch cases don't jump into scopes illegally. - if (FSI->NeedsScopeChecking() && - !PP.isCodeCompletionEnabled()) - DiagnoseInvalidJumps(Body); + if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { + if (!Destructor->getParent()->isDependentType()) + CheckDestructor(Destructor); - if (CXXDestructorDecl *Destructor = dyn_cast(dcl)) { - if (!Destructor->getParent()->isDependentType()) - CheckDestructor(Destructor); + MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), + Destructor->getParent()); + } - MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), - Destructor->getParent()); - } + // If any errors have occurred, clear out any temporaries that may have + // been leftover. This ensures that these temporaries won't be picked up + // for deletion in some later function. + if (hasUncompilableErrorOccurred() || + getDiagnostics().getSuppressAllDiagnostics()) { + DiscardCleanupsInEvaluationContext(); + } + if (!hasUncompilableErrorOccurred() && !isa(dcl)) { + // Since the body is valid, issue any analysis-based warnings that are + // enabled. + ActivePolicy = &WP; + } - // If any errors have occurred, clear out any temporaries that may have - // been leftover. This ensures that these temporaries won't be picked up for - // deletion in some later function. - if (hasUncompilableErrorOccurred() || - getDiagnostics().getSuppressAllDiagnostics()) { - DiscardCleanupsInEvaluationContext(); - } - if (!hasUncompilableErrorOccurred() && - !isa(dcl)) { - // Since the body is valid, issue any analysis-based warnings that are - // enabled. - ActivePolicy = &WP; - } + if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && + !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose)) + FD->setInvalidDecl(); - if (!IsInstantiation && FD && FD->isConstexpr() && !FD->isInvalidDecl() && - !CheckConstexprFunctionDefinition(FD, CheckConstexprKind::Diagnose)) - FD->setInvalidDecl(); - - if (FD && FD->hasAttr()) { - for (const Stmt *S : Body->children()) { - // Allow local register variables without initializer as they don't - // require prologue. - bool RegisterVariables = false; - if (auto *DS = dyn_cast(S)) { - for (const auto *Decl : DS->decls()) { - if (const auto *Var = dyn_cast(Decl)) { - RegisterVariables = - Var->hasAttr() && !Var->hasInit(); - if (!RegisterVariables) - break; + if (FD && FD->hasAttr()) { + for (const Stmt *S : Body->children()) { + // Allow local register variables without initializer as they don't + // require prologue. + bool RegisterVariables = false; + if (auto *DS = dyn_cast(S)) { + for (const auto *Decl : DS->decls()) { + if (const auto *Var = dyn_cast(Decl)) { + RegisterVariables = + Var->hasAttr() && !Var->hasInit(); + if (!RegisterVariables) + break; + } } } - } - if (RegisterVariables) - continue; - if (!isa(S) && !isa(S)) { - Diag(S->getBeginLoc(), diag::err_non_asm_stmt_in_naked_function); - Diag(FD->getAttr()->getLocation(), diag::note_attribute); - FD->setInvalidDecl(); - break; + if (RegisterVariables) + continue; + if (!isa(S) && !isa(S)) { + Diag(S->getBeginLoc(), diag::err_non_asm_stmt_in_naked_function); + Diag(FD->getAttr()->getLocation(), diag::note_attribute); + FD->setInvalidDecl(); + break; + } } } - } - assert(ExprCleanupObjects.size() == - ExprEvalContexts.back().NumCleanupObjects && - "Leftover temporaries in function"); - assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function"); - assert(MaybeODRUseExprs.empty() && - "Leftover expressions for odr-use checking"); - } + assert(ExprCleanupObjects.size() == + ExprEvalContexts.back().NumCleanupObjects && + "Leftover temporaries in function"); + assert(!Cleanup.exprNeedsCleanups() && + "Unaccounted cleanups in function"); + assert(MaybeODRUseExprs.empty() && + "Leftover expressions for odr-use checking"); + } + } // Pops the ExitFunctionBodyRAII scope, which needs to happen before we pop + // the declaration context below. Otherwise, we're unable to transform + // 'this' expressions when transforming immediate context functions. if (!IsInstantiation) PopDeclContext(); @@ -14825,13 +14852,18 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, DiscardCleanupsInEvaluationContext(); } - if (FD && (LangOpts.OpenMP || LangOpts.CUDA || LangOpts.SYCLIsDevice)) { + if (FD && ((LangOpts.OpenMP && (LangOpts.OpenMPIsDevice || + !LangOpts.OMPTargetTriples.empty())) || + LangOpts.CUDA || LangOpts.SYCLIsDevice)) { auto ES = getEmissionStatus(FD); if (ES == Sema::FunctionEmissionStatus::Emitted || ES == Sema::FunctionEmissionStatus::Unknown) DeclsToCheckForDeferredDiags.insert(FD); } + if (FD && !FD->isDeleted()) + checkTypeSupport(FD->getType(), FD->getLocation(), FD); + return dcl; } @@ -15132,6 +15164,34 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { else FD->addAttr(CUDAHostAttr::CreateImplicit(Context, FD->getLocation())); } + + // Add known guaranteed alignment for allocation functions. + switch (BuiltinID) { + case Builtin::BIaligned_alloc: + if (!FD->hasAttr()) + FD->addAttr(AllocAlignAttr::CreateImplicit(Context, ParamIdx(1, FD), + FD->getLocation())); + LLVM_FALLTHROUGH; + case Builtin::BIcalloc: + case Builtin::BImalloc: + case Builtin::BImemalign: + case Builtin::BIrealloc: + case Builtin::BIstrdup: + case Builtin::BIstrndup: { + if (!FD->hasAttr()) { + unsigned NewAlign = Context.getTargetInfo().getNewAlign() / + Context.getTargetInfo().getCharWidth(); + IntegerLiteral *Alignment = IntegerLiteral::Create( + Context, Context.MakeIntValue(NewAlign, Context.UnsignedIntTy), + Context.UnsignedIntTy, FD->getLocation()); + FD->addAttr(AssumeAlignedAttr::CreateImplicit( + Context, Alignment, /*Offset=*/nullptr, FD->getLocation())); + } + break; + } + default: + break; + } } AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD); @@ -16569,6 +16629,23 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, // Notify the consumer that we've defined a tag. if (!Tag->isInvalidDecl()) Consumer.HandleTagDeclDefinition(Tag); + + // Clangs implementation of #pragma align(packed) differs in bitfield layout + // from XLs and instead matches the XL #pragma pack(1) behavior. + if (Context.getTargetInfo().getTriple().isOSAIX() && + AlignPackStack.hasValue()) { + AlignPackInfo APInfo = AlignPackStack.CurrentValue; + // Only diagnose #pragma align(packed). + if (!APInfo.IsAlignAttr() || APInfo.getAlignMode() != AlignPackInfo::Packed) + return; + const RecordDecl *RD = dyn_cast(Tag); + if (!RD) + return; + // Only warn if there is at least 1 bitfield member. + if (llvm::any_of(RD->fields(), + [](const FieldDecl *FD) { return FD->isBitField(); })) + Diag(BraceRange.getBegin(), diag::warn_pragma_align_not_xl_compatible); + } } void Sema::ActOnObjCContainerFinishDefinition() { @@ -17743,7 +17820,8 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, Val = DefaultLvalueConversion(Val).get(); if (Val) { - if (Enum->isDependentType() || Val->isTypeDependent()) + if (Enum->isDependentType() || Val->isTypeDependent() || + Val->containsErrors()) EltTy = Context.DependentTy; else { // FIXME: We don't allow folding in C++11 mode for an enum with a fixed diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index bb4ce8d4962..ef889a36bd5 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -216,7 +216,7 @@ static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr, uint32_t &Val, unsigned Idx = UINT_MAX, bool StrictlyUnsigned = false) { Optional I = llvm::APSInt(32); - if (Expr->isTypeDependent() || Expr->isValueDependent() || + if (Expr->isTypeDependent() || !(I = Expr->getIntegerConstantExpr(S.Context))) { if (Idx != UINT_MAX) S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) @@ -308,7 +308,7 @@ static bool checkFunctionOrMethodParameterIndex( (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam; Optional IdxInt; - if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() || + if (IdxExpr->isTypeDependent() || !(IdxInt = IdxExpr->getIntegerConstantExpr(S.Context))) { S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type) << &AI << AttrArgNum << AANT_ArgumentIntegerConstant @@ -947,6 +947,14 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg)); } +static void handleErrorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef NewUserDiagnostic; + if (!S.checkStringLiteralArgumentAttr(AL, 0, NewUserDiagnostic)) + return; + if (ErrorAttr *EA = S.mergeErrorAttr(D, AL, NewUserDiagnostic)) + D->addAttr(EA); +} + namespace { /// Determines if a given Expr references any of the given function's /// ParmVarDecls, or the function's implicit `this` parameter (if applicable). @@ -1788,7 +1796,7 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { I->getOwnKind() == OwnershipAttr::Returns) { // A returns attribute conflicts with any other returns attribute using // a different index. - if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) { + if (!llvm::is_contained(I->args(), Idx)) { S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch) << I->args_begin()->getSourceIndex(); if (I->args_size()) @@ -2488,6 +2496,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } + if (II->isStr("fuchsia")) { + Optional Min, Sub; + if ((Min = Introduced.Version.getMinor()) || + (Sub = Introduced.Version.getSubminor())) { + S.Diag(AL.getLoc(), diag::warn_availability_fuchsia_unavailable_minor); + return; + } + } + int PriorityModifier = AL.isPragmaClangAttribute() ? Sema::AP_PragmaClangAttribute : Sema::AP_Explicit; @@ -2843,8 +2860,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() > 0) { Expr *E = AL.getArgAsExpr(0); Optional Idx = llvm::APSInt(32); - if (E->isTypeDependent() || E->isValueDependent() || - !(Idx = E->getIntegerConstantExpr(S.Context))) { + if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; @@ -2863,8 +2879,7 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.getNumArgs() > 1) { Expr *E = AL.getArgAsExpr(1); Optional Idx = llvm::APSInt(32); - if (E->isTypeDependent() || E->isValueDependent() || - !(Idx = E->getIntegerConstantExpr(S.Context))) { + if (E->isTypeDependent() || !(Idx = E->getIntegerConstantExpr(S.Context))) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange(); return; @@ -3196,13 +3211,13 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, Architecture, Tune }; - if (AttrStr.find("fpmath=") != StringRef::npos) + if (AttrStr.contains("fpmath=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "fpmath="; // Diagnose use of tune if target doesn't support it. if (!Context.getTargetInfo().supportsTargetAttributeTune() && - AttrStr.find("tune=") != StringRef::npos) + AttrStr.contains("tune=")) return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << "tune="; @@ -3373,6 +3388,13 @@ static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } Ty = getFunctionOrMethodResultType(D); + // replace instancetype with the class type + auto Instancetype = S.Context.getObjCInstanceTypeDecl()->getTypeForDecl(); + if (Ty->getAs() == Instancetype) + if (auto *OMD = dyn_cast(D)) + if (auto *Interface = OMD->getClassInterface()) + Ty = S.Context.getObjCObjectPointerType( + QualType(Interface->getTypeForDecl(), 0)); if (!isNSStringType(Ty, S.Context, /*AllowNSAttributedString=*/true) && !isCFStringType(Ty, S.Context) && (!Ty->isPointerType() || @@ -3458,6 +3480,29 @@ static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum)); } +ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, + StringRef NewUserDiagnostic) { + if (const auto *EA = D->getAttr()) { + std::string NewAttr = CI.getNormalizedFullName(); + assert((NewAttr == "error" || NewAttr == "warning") && + "unexpected normalized full name"); + bool Match = (EA->isError() && NewAttr == "error") || + (EA->isWarning() && NewAttr == "warning"); + if (!Match) { + Diag(EA->getLocation(), diag::err_attributes_are_not_compatible) + << CI << EA; + Diag(CI.getLoc(), diag::note_conflicting_attribute); + return nullptr; + } + if (EA->getUserDiagnostic() != NewUserDiagnostic) { + Diag(CI.getLoc(), diag::warn_duplicate_attribute) << EA; + Diag(EA->getLoc(), diag::note_previous_attribute); + } + D->dropAttr(); + } + return ::new (Context) ErrorAttr(Context, CI, NewUserDiagnostic); +} + FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI, IdentifierInfo *Format, int FormatIdx, int FirstArg) { @@ -4051,21 +4096,21 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } } - unsigned MaximumAlignment = Sema::MaximumAlignment; + uint64_t MaximumAlignment = Sema::MaximumAlignment; if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF()) - MaximumAlignment = std::min(MaximumAlignment, 8192u); + MaximumAlignment = std::min(MaximumAlignment, uint64_t(8192)); if (AlignVal > MaximumAlignment) { Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaximumAlignment << E->getSourceRange(); return; } - if (Context.getTargetInfo().isTLSSupported()) { + const auto *VD = dyn_cast(D); + if (VD && Context.getTargetInfo().isTLSSupported()) { unsigned MaxTLSAlign = Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign()) .getQuantity(); - const auto *VD = dyn_cast(D); - if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD && + if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD->getTLSKind() != VarDecl::TLS_None) { Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum) << (unsigned)AlignVal << VD << MaxTLSAlign; @@ -4073,6 +4118,17 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } } + // On AIX, an aligned attribute can not decrease the alignment when applied + // to a variable declaration with vector type. + if (VD && Context.getTargetInfo().getTriple().isOSAIX()) { + const Type *Ty = VD->getType().getTypePtr(); + if (Ty->isVectorType() && AlignVal < 16) { + Diag(VD->getLocation(), diag::warn_aligned_attr_underaligned) + << VD->getType() << 16; + return; + } + } + AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get()); AA->setPackExpansion(IsPackExpansion); D->addAttr(AA); @@ -4161,9 +4217,10 @@ bool Sema::checkMSInheritanceAttrOnDefinition( /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, bool &IntegerMode, bool &ComplexMode, - bool &ExplicitIEEE) { + FloatModeKind &ExplicitType) { IntegerMode = true; ComplexMode = false; + ExplicitType = FloatModeKind::NoFloat; switch (Str.size()) { case 2: switch (Str[0]) { @@ -4183,13 +4240,17 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, DestWidth = 96; break; case 'K': // KFmode - IEEE quad precision (__float128) - ExplicitIEEE = true; + ExplicitType = FloatModeKind::Float128; DestWidth = Str[1] == 'I' ? 0 : 128; break; case 'T': - ExplicitIEEE = false; + ExplicitType = FloatModeKind::LongDouble; DestWidth = 128; break; + case 'I': + ExplicitType = FloatModeKind::Ibm128; + DestWidth = Str[1] == 'I' ? 0 : 128; + break; } if (Str[1] == 'F') { IntegerMode = false; @@ -4248,7 +4309,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, unsigned DestWidth = 0; bool IntegerMode = true; bool ComplexMode = false; - bool ExplicitIEEE = false; + FloatModeKind ExplicitType = FloatModeKind::NoFloat; llvm::APInt VectorSize(64, 0); if (Str.size() >= 4 && Str[0] == 'V') { // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2). @@ -4261,7 +4322,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, - IntegerMode, ComplexMode, ExplicitIEEE); + IntegerMode, ComplexMode, ExplicitType); // Avoid duplicate warning from template instantiation. if (!InInstantiation) Diag(AttrLoc, diag::warn_vector_mode_deprecated); @@ -4272,7 +4333,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, if (!VectorSize) parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode, - ExplicitIEEE); + ExplicitType); // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t // and friends, at least with glibc. @@ -4338,7 +4399,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, NewElemTy = Context.getIntTypeForBitwidth(DestWidth, OldElemTy->isSignedIntegerType()); else - NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitIEEE); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitType); if (NewElemTy.isNull()) { Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; @@ -4733,7 +4794,7 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } // To check if earlier decl attributes do not conflict the newly parsed ones - // we always add (and check) the attribute to the cannonical decl. We need + // we always add (and check) the attribute to the canonical decl. We need // to repeat the check for attribute mutual exclusion because we're attaching // all of the attributes to the canonical declaration rather than the current // declaration. @@ -5284,8 +5345,8 @@ static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static bool RISCVAliasValid(unsigned BuiltinID, StringRef AliasName) { - return BuiltinID >= Builtin::FirstTSBuiltin && - BuiltinID < RISCV::LastTSBuiltin; + return BuiltinID >= RISCV::FirstRVVBuiltin && + BuiltinID <= RISCV::LastRVVBuiltin; } static void handleBuiltinAliasAttr(Sema &S, Decl *D, @@ -6063,7 +6124,7 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, if (BaseName.empty()) { BaseName = ContextName; ContextName = StringRef(); - } else if (ContextName.empty() || !isValidIdentifier(ContextName)) { + } else if (ContextName.empty() || !isValidAsciiIdentifier(ContextName)) { S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*context*/ 1; return false; @@ -6071,7 +6132,7 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, IsMember = true; } - if (!isValidIdentifier(BaseName) || BaseName == "_") { + if (!isValidAsciiIdentifier(BaseName) || BaseName == "_") { S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*basename*/ 0; return false; @@ -6121,7 +6182,7 @@ validateSwiftFunctionName(Sema &S, const ParsedAttr &AL, SourceLocation Loc, do { std::tie(CurrentParam, Parameters) = Parameters.split(':'); - if (!isValidIdentifier(CurrentParam)) { + if (!isValidAsciiIdentifier(CurrentParam)) { S.Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*parameter*/2; return false; @@ -6262,13 +6323,12 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, // might be because we've transformed some of them. Check for potential // "out" parameters and err on the side of not warning. unsigned MaybeOutParamCount = - std::count_if(Params.begin(), Params.end(), - [](const ParmVarDecl *Param) -> bool { - QualType ParamTy = Param->getType(); - if (ParamTy->isReferenceType() || ParamTy->isPointerType()) - return !ParamTy->getPointeeType().isConstQualified(); - return false; - }); + llvm::count_if(Params, [](const ParmVarDecl *Param) -> bool { + QualType ParamTy = Param->getType(); + if (ParamTy->isReferenceType() || ParamTy->isPointerType()) + return !ParamTy->getPointeeType().isConstQualified(); + return false; + }); ParamCountValid = SwiftParamCount + MaybeOutParamCount >= ParamCount; } @@ -6290,13 +6350,13 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, if (BaseName.empty()) { BaseName = ContextName; ContextName = StringRef(); - } else if (!isValidIdentifier(ContextName)) { + } else if (!isValidAsciiIdentifier(ContextName)) { Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*context*/1; return false; } - if (!isValidIdentifier(BaseName)) { + if (!isValidAsciiIdentifier(BaseName)) { Diag(Loc, diag::warn_attr_swift_name_invalid_identifier) << AL << /*basename*/0; return false; @@ -6831,6 +6891,30 @@ static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D, Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); } +static bool hasBTFDeclTagAttr(Decl *D, StringRef Tag) { + for (const auto *I : D->specific_attrs()) { + if (I->getBTFDeclTag() == Tag) + return true; + } + return false; +} + +static void handleBTFDeclTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str)) + return; + if (hasBTFDeclTagAttr(D, Str)) + return; + + D->addAttr(::new (S.Context) BTFDeclTagAttr(S.Context, AL, Str)); +} + +BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { + if (hasBTFDeclTagAttr(D, AL.getBTFDeclTag())) + return nullptr; + return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag()); +} + static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -7434,7 +7518,7 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, // index rather than incorrectly assume the index for NoSanitizeSpecificAttr // has the same spellings as the index for NoSanitizeAttr. We don't have a // general way to "translate" between the two, so this hack attempts to work - // around the issue with hard-coded indicies. This is critical for calling + // around the issue with hard-coded indices. This is critical for calling // getSpelling() or prettyPrint() on the resulting semantic attribute object // without failing assertions. unsigned TranslatedSpellingIndex = 0; @@ -7453,12 +7537,12 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (S.LangOpts.OpenCLVersion != 200) + if (S.LangOpts.getOpenCLCompatibleVersion() < 200) S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version) - << AL << "2.0" << 0; + << AL << "2.0" << 1; else - S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) << AL - << "2.0"; + S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << AL << S.LangOpts.getOpenCLVersionString(); } static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -7486,18 +7570,17 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // OpenCL v3.0 s6.8 - For OpenCL C 2.0, or with the // __opencl_c_read_write_images feature, image objects specified as arguments // to a kernel can additionally be declared to be read-write. - // C++ for OpenCL inherits rule from OpenCL C v2.0. + // C++ for OpenCL 1.0 inherits rule from OpenCL C v2.0. + // C++ for OpenCL 2021 inherits rule from OpenCL C v3.0. if (const auto *PDecl = dyn_cast(D)) { const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); - if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) { - bool ReadWriteImagesUnsupportedForOCLC = - (S.getLangOpts().OpenCLVersion < 200) || - (S.getLangOpts().OpenCLVersion == 300 && + if (AL.getAttrName()->getName().contains("read_write")) { + bool ReadWriteImagesUnsupported = + (S.getLangOpts().getOpenCLCompatibleVersion() < 200) || + (S.getLangOpts().getOpenCLCompatibleVersion() == 300 && !S.getOpenCLOptions().isSupported("__opencl_c_read_write_images", S.getLangOpts())); - if ((!S.getLangOpts().OpenCLCPlusPlus && - ReadWriteImagesUnsupportedForOCLC) || - DeclTy->isPipeType()) { + if (ReadWriteImagesUnsupported || DeclTy->isPipeType()) { S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write) << AL << PDecl->getType() << DeclTy->isImageType(); D->setInvalidDecl(true); @@ -7868,6 +7951,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_BPFPreserveAccessIndex: handleBPFPreserveAccessIndexAttr(S, D, AL); break; + case ParsedAttr::AT_BTFDeclTag: + handleBTFDeclTagAttr(S, D, AL); + break; case ParsedAttr::AT_WebAssemblyExportName: handleWebAssemblyExportNameAttr(S, D, AL); break; @@ -7941,6 +8027,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_EnableIf: handleEnableIfAttr(S, D, AL); break; + case ParsedAttr::AT_Error: + handleErrorAttr(S, D, AL); + break; case ParsedAttr::AT_DiagnoseIf: handleDiagnoseIfAttr(S, D, AL); break; @@ -8592,8 +8681,9 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, NewFD = FunctionDecl::Create( FD->getASTContext(), FD->getDeclContext(), Loc, Loc, DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None, - false /*isInlineSpecified*/, FD->hasPrototype(), - ConstexprSpecKind::Unspecified, FD->getTrailingRequiresClause()); + getCurFPFeatures().isFPConstrained(), false /*isInlineSpecified*/, + FD->hasPrototype(), ConstexprSpecKind::Unspecified, + FD->getTrailingRequiresClause()); NewD = NewFD; if (FD->getQualifier()) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 83c97626ff7..20410a959cd 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -26,6 +26,7 @@ #include "clang/AST/TypeOrdering.h" #include "clang/Basic/AttributeCommonInfo.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/Preprocessor.h" @@ -435,7 +436,7 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) { - return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) { + return llvm::any_of(FD->parameters(), [](ParmVarDecl *P) { return P->hasDefaultArg() && !P->hasInheritedDefaultArg(); }); } @@ -983,9 +984,9 @@ static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, for (auto &Arg : Args.arguments()) { if (!First) OS << ", "; - Arg.getArgument().print( - PrintingPolicy, OS, - TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); + Arg.getArgument().print(PrintingPolicy, OS, + TemplateParameterList::shouldIncludeTypeForArgument( + PrintingPolicy, Params, I)); First = false; I++; } @@ -1383,9 +1384,8 @@ static bool checkMemberDecomposition(Sema &S, ArrayRef Bindings, DecompType.getQualifiers()); auto DiagnoseBadNumberOfBindings = [&]() -> bool { - unsigned NumFields = - std::count_if(RD->field_begin(), RD->field_end(), - [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); + unsigned NumFields = llvm::count_if( + RD->fields(), [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); assert(Bindings.size() != NumFields); S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) << DecompType << (unsigned)Bindings.size() << NumFields << NumFields @@ -2050,6 +2050,13 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, ReturnStmts.push_back(S->getBeginLoc()); return true; + case Stmt::AttributedStmtClass: + // Attributes on a statement don't affect its formal kind and hence don't + // affect its validity in a constexpr function. + return CheckConstexprFunctionStmt(SemaRef, Dcl, + cast(S)->getSubStmt(), + ReturnStmts, Cxx1yLoc, Cxx2aLoc, Kind); + case Stmt::CompoundStmtClass: { // C++1y allows compound-statements. if (!Cxx1yLoc.isValid()) @@ -2064,11 +2071,6 @@ CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S, return true; } - case Stmt::AttributedStmtClass: - if (!Cxx1yLoc.isValid()) - Cxx1yLoc = S->getBeginLoc(); - return true; - case Stmt::IfStmtClass: { // C++1y allows if-statements. if (!Cxx1yLoc.isValid()) @@ -2727,6 +2729,8 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; + if (NewBaseType->isDependentType()) + continue; // Note this base's direct & indirect bases, if there could be ambiguity. if (Bases.size() > 1) NoteIndirectBases(Context, IndirectBaseTypes, NewBaseType); @@ -3581,9 +3585,8 @@ namespace { llvm::SmallVector UsedFieldIndex; // Discard the first field since it is the field decl that is being // initialized. - for (auto I = Fields.rbegin() + 1, E = Fields.rend(); I != E; ++I) { - UsedFieldIndex.push_back((*I)->getFieldIndex()); - } + for (const FieldDecl *FD : llvm::drop_begin(llvm::reverse(Fields))) + UsedFieldIndex.push_back(FD->getFieldIndex()); for (auto UsedIter = UsedFieldIndex.begin(), UsedEnd = UsedFieldIndex.end(), @@ -4114,7 +4117,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, namespace { // Callback to only accept typo corrections that can be a valid C++ member -// intializer: either a non-static field member or a base class. +// initializer: either a non-static field member or a base class. class MemInitializerValidatorCCC final : public CorrectionCandidateCallback { public: explicit MemInitializerValidatorCCC(CXXRecordDecl *ClassDecl) @@ -4162,7 +4165,8 @@ Sema::BuildMemInitializer(Decl *ConstructorD, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc) { - ExprResult Res = CorrectDelayedTyposInExpr(Init); + ExprResult Res = CorrectDelayedTyposInExpr(Init, /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); if (!Res.isUsable()) return true; Init = Res.get(); @@ -4214,7 +4218,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD, if (BaseType.isNull()) return true; } else if (DS.getTypeSpecType() == TST_decltype) { - BaseType = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + BaseType = BuildDecltypeType(DS.getRepAsExpr()); } else if (DS.getTypeSpecType() == TST_decltype_auto) { Diag(DS.getTypeSpecTypeLoc(), diag::err_decltype_auto_invalid); return true; @@ -4375,18 +4379,25 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, InitializationSequence InitSeq(*this, MemberEntity, Kind, Args); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, Args, nullptr); - if (MemberInit.isInvalid()) - return true; + if (!MemberInit.isInvalid()) { + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin(), + /*DiscardedValue*/ false); + } - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - MemberInit = ActOnFinishFullExpr(MemberInit.get(), InitRange.getBegin(), - /*DiscardedValue*/ false); - if (MemberInit.isInvalid()) - return true; - - Init = MemberInit.get(); + if (MemberInit.isInvalid()) { + // Args were sensible expressions but we couldn't initialize the member + // from them. Preserve them in a RecoveryExpr instead. + Init = CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), Args, + Member->getType()) + .get(); + if (!Init) + return true; + } else { + Init = MemberInit.get(); + } } if (DirectMember) { @@ -4428,29 +4439,35 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, Args, nullptr); - if (DelegationInit.isInvalid()) - return true; + if (!DelegationInit.isInvalid()) { + assert((DelegationInit.get()->containsErrors() || + cast(DelegationInit.get())->getConstructor()) && + "Delegating constructor with no target?"); - assert(cast(DelegationInit.get())->getConstructor() && - "Delegating constructor with no target?"); + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + DelegationInit = ActOnFinishFullExpr( + DelegationInit.get(), InitRange.getBegin(), /*DiscardedValue*/ false); + } - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - DelegationInit = ActOnFinishFullExpr( - DelegationInit.get(), InitRange.getBegin(), /*DiscardedValue*/ false); - if (DelegationInit.isInvalid()) - return true; - - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the base - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - DelegationInit = Init; + if (DelegationInit.isInvalid()) { + DelegationInit = + CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), Args, + QualType(ClassDecl->getTypeForDecl(), 0)); + if (DelegationInit.isInvalid()) + return true; + } else { + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + DelegationInit = Init; + } return new (Context) CXXCtorInitializer(Context, TInfo, InitRange.getBegin(), DelegationInit.getAs(), @@ -4474,7 +4491,12 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, // of that class, the mem-initializer is ill-formed. A // mem-initializer-list can initialize a base class using any // name that denotes that base class type. - bool Dependent = BaseType->isDependentType() || Init->isTypeDependent(); + + // We can store the initializers in "as-written" form and delay analysis until + // instantiation if the constructor is dependent. But not for dependent + // (broken) code in a non-template! SetCtorInitializers does not expect this. + bool Dependent = CurContext->isDependentContext() && + (BaseType->isDependentType() || Init->isTypeDependent()); SourceRange InitRange = Init->getSourceRange(); if (EllipsisLoc.isValid()) { @@ -4561,26 +4583,30 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, Args, nullptr); - if (BaseInit.isInvalid()) - return true; + if (!BaseInit.isInvalid()) { + // C++11 [class.base.init]p7: + // The initialization of each base and member constitutes a + // full-expression. + BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin(), + /*DiscardedValue*/ false); + } - // C++11 [class.base.init]p7: - // The initialization of each base and member constitutes a - // full-expression. - BaseInit = ActOnFinishFullExpr(BaseInit.get(), InitRange.getBegin(), - /*DiscardedValue*/ false); - if (BaseInit.isInvalid()) - return true; - - // If we are in a dependent context, template instantiation will - // perform this type-checking again. Just save the arguments that we - // received in a ParenListExpr. - // FIXME: This isn't quite ideal, since our ASTs don't capture all - // of the information that we have about the base - // initializer. However, deconstructing the ASTs is a dicey process, - // and this approach is far more likely to get the corner cases right. - if (CurContext->isDependentContext()) - BaseInit = Init; + if (BaseInit.isInvalid()) { + BaseInit = CreateRecoveryExpr(InitRange.getBegin(), InitRange.getEnd(), + Args, BaseType); + if (BaseInit.isInvalid()) + return true; + } else { + // If we are in a dependent context, template instantiation will + // perform this type-checking again. Just save the arguments that we + // received in a ParenListExpr. + // FIXME: This isn't quite ideal, since our ASTs don't capture all + // of the information that we have about the base + // initializer. However, deconstructing the ASTs is a dicey process, + // and this approach is far more likely to get the corner cases right. + if (CurContext->isDependentContext()) + BaseInit = Init; + } return new (Context) CXXCtorInitializer(Context, BaseTInfo, BaseSpec->isVirtual(), @@ -5859,6 +5885,7 @@ struct CheckAbstractUsage { if (CT != Info.AbstractType) return; // It matched; do some magic. + // FIXME: These should be at most warnings. See P0929R2, CWG1640, CWG1646. if (Sel == Sema::AbstractArrayType) { Info.S.Diag(Ctx->getLocation(), diag::err_array_of_abstract_type) << T << TL.getSourceRange(); @@ -5877,19 +5904,31 @@ void AbstractUsageInfo::CheckType(const NamedDecl *D, TypeLoc TL, } -/// Check for invalid uses of an abstract type in a method declaration. +/// Check for invalid uses of an abstract type in a function declaration. static void CheckAbstractClassUsage(AbstractUsageInfo &Info, - CXXMethodDecl *MD) { + FunctionDecl *FD) { // No need to do the check on definitions, which require that // the return/param types be complete. - if (MD->doesThisDeclarationHaveABody()) + if (FD->doesThisDeclarationHaveABody()) return; // For safety's sake, just ignore it if we don't have type source // information. This should never happen for non-implicit methods, // but... - if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) - Info.CheckType(MD, TSI->getTypeLoc(), Sema::AbstractNone); + if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) + Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractNone); +} + +/// Check for invalid uses of an abstract type in a variable0 declaration. +static void CheckAbstractClassUsage(AbstractUsageInfo &Info, + VarDecl *VD) { + // No need to do the check on definitions, which require that + // the type is complete. + if (VD->isThisDeclarationADefinition()) + return; + + Info.CheckType(VD, VD->getTypeSourceInfo()->getTypeLoc(), + Sema::AbstractVariableType); } /// Check for invalid uses of an abstract type within a class definition. @@ -5898,29 +5937,32 @@ static void CheckAbstractClassUsage(AbstractUsageInfo &Info, for (auto *D : RD->decls()) { if (D->isImplicit()) continue; - // Methods and method templates. - if (isa(D)) { - CheckAbstractClassUsage(Info, cast(D)); - } else if (isa(D)) { - FunctionDecl *FD = cast(D)->getTemplatedDecl(); - CheckAbstractClassUsage(Info, cast(FD)); + // Step through friends to the befriended declaration. + if (auto *FD = dyn_cast(D)) { + D = FD->getFriendDecl(); + if (!D) continue; + } + + // Functions and function templates. + if (auto *FD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, FD); + } else if (auto *FTD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, FTD->getTemplatedDecl()); // Fields and static variables. - } else if (isa(D)) { - FieldDecl *FD = cast(D); + } else if (auto *FD = dyn_cast(D)) { if (TypeSourceInfo *TSI = FD->getTypeSourceInfo()) Info.CheckType(FD, TSI->getTypeLoc(), Sema::AbstractFieldType); - } else if (isa(D)) { - VarDecl *VD = cast(D); - if (TypeSourceInfo *TSI = VD->getTypeSourceInfo()) - Info.CheckType(VD, TSI->getTypeLoc(), Sema::AbstractVariableType); + } else if (auto *VD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, VD); + } else if (auto *VTD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, VTD->getTemplatedDecl()); // Nested classes and class templates. - } else if (isa(D)) { - CheckAbstractClassUsage(Info, cast(D)); - } else if (isa(D)) { - CheckAbstractClassUsage(Info, - cast(D)->getTemplatedDecl()); + } else if (auto *RD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, RD); + } else if (auto *CTD = dyn_cast(D)) { + CheckAbstractClassUsage(Info, CTD->getTemplatedDecl()); } } } @@ -5960,11 +6002,14 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { S.MarkVTableUsed(Class->getLocation(), Class, true); for (Decl *Member : Class->decls()) { + // Skip members that were not marked exported. + if (!Member->hasAttr()) + continue; + // Defined static variables that are members of an exported base // class must be marked export too. auto *VD = dyn_cast(Member); - if (VD && Member->getAttr() && - VD->getStorageClass() == SC_Static && + if (VD && VD->getStorageClass() == SC_Static && TSK == TSK_ImplicitInstantiation) S.MarkVariableReferenced(VD->getLocation(), VD); @@ -5972,40 +6017,47 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { if (!MD) continue; - if (Member->getAttr()) { - if (MD->isUserProvided()) { - // Instantiate non-default class member functions ... + if (MD->isUserProvided()) { + // Instantiate non-default class member functions ... - // .. except for certain kinds of template specializations. - if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) - continue; + // .. except for certain kinds of template specializations. + if (TSK == TSK_ImplicitInstantiation && !ClassAttr->isInherited()) + continue; - S.MarkFunctionReferenced(Class->getLocation(), MD); - - // The function will be passed to the consumer when its definition is - // encountered. - } else if (MD->isExplicitlyDefaulted()) { - // Synthesize and instantiate explicitly defaulted methods. - S.MarkFunctionReferenced(Class->getLocation(), MD); - - if (TSK != TSK_ExplicitInstantiationDefinition) { - // Except for explicit instantiation defs, we will not see the - // definition again later, so pass it to the consumer now. - S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); + // If this is an MS ABI dllexport default constructor, instantiate any + // default arguments. + if (S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + auto *CD = dyn_cast(MD); + if (CD && CD->isDefaultConstructor() && TSK == TSK_Undeclared) { + S.InstantiateDefaultCtorDefaultArgs(CD); } - } else if (!MD->isTrivial() || - MD->isCopyAssignmentOperator() || - MD->isMoveAssignmentOperator()) { - // Synthesize and instantiate non-trivial implicit methods, and the copy - // and move assignment operators. The latter are exported even if they - // are trivial, because the address of an operator can be taken and - // should compare equal across libraries. - S.MarkFunctionReferenced(Class->getLocation(), MD); + } - // There is no later point when we will see the definition of this - // function, so pass it to the consumer now. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // The function will be passed to the consumer when its definition is + // encountered. + } else if (MD->isExplicitlyDefaulted()) { + // Synthesize and instantiate explicitly defaulted methods. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + if (TSK != TSK_ExplicitInstantiationDefinition) { + // Except for explicit instantiation defs, we will not see the + // definition again later, so pass it to the consumer now. S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); } + } else if (!MD->isTrivial() || + MD->isCopyAssignmentOperator() || + MD->isMoveAssignmentOperator()) { + // Synthesize and instantiate non-trivial implicit methods, and the copy + // and move assignment operators. The latter are exported even if they + // are trivial, because the address of an operator can be taken and + // should compare equal across libraries. + S.MarkFunctionReferenced(Class->getLocation(), MD); + + // There is no later point when we will see the definition of this + // function, so pass it to the consumer now. + S.Consumer.HandleTopLevelDecl(DeclGroupRef(MD)); } } } @@ -7771,9 +7823,21 @@ private: DCK == DefaultedComparisonKind::Relational) && !Best->RewriteKind) { if (Diagnose == ExplainDeleted) { - S.Diag(Best->Function->getLocation(), - diag::note_defaulted_comparison_not_rewritten_callee) - << FD; + if (Best->Function) { + S.Diag(Best->Function->getLocation(), + diag::note_defaulted_comparison_not_rewritten_callee) + << FD; + } else { + assert(Best->Conversions.size() == 2 && + Best->Conversions[0].isUserDefined() && + "non-user-defined conversion from class to built-in " + "comparison"); + S.Diag(Best->Conversions[0] + .UserDefined.FoundConversionFunction.getDecl() + ->getLocation(), + diag::note_defaulted_comparison_not_rewritten_conversion) + << FD; + } } return Result::deleted(); } @@ -7929,7 +7993,7 @@ private: if (Diagnose == ExplainDeleted) { S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function) - << FD << Subobj.Kind << Subobj.Decl; + << FD << (OO == OO_ExclaimEqual) << Subobj.Kind << Subobj.Decl; // For a three-way comparison, list both the candidates for the // original operator and the candidates for the synthesized operator. @@ -8157,7 +8221,7 @@ private: if (ReturnFalse.isInvalid()) return StmtError(); - return S.ActOnIfStmt(Loc, false, Loc, nullptr, + return S.ActOnIfStmt(Loc, IfStatementKind::Ordinary, Loc, nullptr, S.ActOnCondition(nullptr, Loc, NotCond.get(), Sema::ConditionKind::Boolean), Loc, ReturnFalse.get(), SourceLocation(), nullptr); @@ -8312,8 +8376,8 @@ private: return StmtError(); // if (...) - return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, Loc, InitStmt, Cond, Loc, - ReturnStmt.get(), + return S.ActOnIfStmt(Loc, IfStatementKind::Ordinary, Loc, InitStmt, Cond, + Loc, ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), /*Else=*/nullptr); } @@ -9778,7 +9842,7 @@ public: }; } // end anonymous namespace -/// Add the most overriden methods from MD to Methods +/// Add the most overridden methods from MD to Methods static void AddMostOverridenMethods(const CXXMethodDecl *MD, llvm::SmallPtrSetImpl& Methods) { if (MD->size_overridden_methods() == 0) @@ -12472,6 +12536,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, return false; } + const NestedNameSpecifier *CNNS = + Context.getCanonicalNestedNameSpecifier(Qual); for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; @@ -12497,8 +12563,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // using decls differ if they name different scopes (but note that // template instantiation can cause this check to trigger when it // didn't before instantiation). - if (Context.getCanonicalNestedNameSpecifier(Qual) != - Context.getCanonicalNestedNameSpecifier(DQual)) + if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual)) continue; Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); @@ -13234,6 +13299,7 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(), /*TInfo=*/nullptr, ExplicitSpecifier(), + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified); @@ -13355,7 +13421,8 @@ Sema::findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, - BaseCtor->getExplicitSpecifier(), /*isInline=*/true, + BaseCtor->getExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? BaseCtor->getConstexprKind() : ConstexprSpecKind::Unspecified, InheritedConstructor(Shadow, BaseCtor), @@ -13510,12 +13577,13 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { DeclarationName Name = Context.DeclarationNames.getCXXDestructorName(ClassType); DeclarationNameInfo NameInfo(Name, ClassLoc); - CXXDestructorDecl *Destructor = - CXXDestructorDecl::Create(Context, ClassDecl, ClassLoc, NameInfo, - QualType(), nullptr, /*isInline=*/true, - /*isImplicitlyDeclared=*/true, - Constexpr ? ConstexprSpecKind::Constexpr - : ConstexprSpecKind::Unspecified); + CXXDestructorDecl *Destructor = CXXDestructorDecl::Create( + Context, ClassDecl, ClassLoc, NameInfo, QualType(), nullptr, + getCurFPFeatures().isFPConstrained(), + /*isInline=*/true, + /*isImplicitlyDeclared=*/true, + Constexpr ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); Destructor->setAccess(AS_public); Destructor->setDefaulted(); @@ -14151,6 +14219,7 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *CopyAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); @@ -14485,6 +14554,7 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { CXXMethodDecl *MoveAssignment = CXXMethodDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, /*StorageClass=*/SC_None, + getCurFPFeatures().isFPConstrained(), /*isInline=*/true, Constexpr ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, SourceLocation()); @@ -14864,7 +14934,7 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // member of its class. CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, - ExplicitSpecifier(), + ExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr @@ -15004,7 +15074,7 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( // member of its class. CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create( Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr, - ExplicitSpecifier(), + ExplicitSpecifier(), getCurFPFeatures().isFPConstrained(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? ConstexprSpecKind::Constexpr @@ -15261,8 +15331,17 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // can be omitted by constructing the temporary object // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor && + // FIXME: Converting constructors should also be accepted. + // But to fix this, the logic that digs down into a CXXConstructExpr + // to find the source object needs to handle it. + // Right now it assumes the source object is passed directly as the + // first argument. Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ExprArgs[0]; + // FIXME: Per above, this is also incorrect if we want to accept + // converting constructors, as isTemporaryObject will + // reject temporaries with different type from the + // CXXRecord itself. Elidable = SubExpr->isTemporaryObject( Context, cast(FoundDecl->getDeclContext())); } @@ -15400,7 +15479,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; // If initializing the variable failed, don't also diagnose problems with - // the desctructor, they're likely related. + // the destructor, they're likely related. if (VD->getInit() && VD->getInit()->containsErrors()) return; @@ -15830,7 +15909,7 @@ checkLiteralOperatorTemplateParameterList(Sema &SemaRef, // // As a DR resolution, we also allow placeholders for deduced class // template specializations. - if (SemaRef.getLangOpts().CPlusPlus20 && + if (SemaRef.getLangOpts().CPlusPlus20 && PmDecl && !PmDecl->isTemplateParameterPack() && (PmDecl->getType()->isRecordType() || PmDecl->getType()->getAs())) @@ -16806,10 +16885,7 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, while (DC->isRecord()) DC = DC->getParent(); - DeclContext *LookupDC = DC; - while (LookupDC->isTransparentContext()) - LookupDC = LookupDC->getParent(); - + DeclContext *LookupDC = DC->getNonTransparentContext(); while (true) { LookupQualifiedName(Previous, LookupDC); @@ -17572,16 +17648,12 @@ bool Sema::DefineUsedVTables() { // no key function or the key function is inlined. Don't warn in C++ ABIs // that lack key functions, since the user won't be able to make one. if (Context.getTargetInfo().getCXXABI().hasKeyFunctions() && - Class->isExternallyVisible() && ClassTSK != TSK_ImplicitInstantiation) { + Class->isExternallyVisible() && ClassTSK != TSK_ImplicitInstantiation && + ClassTSK != TSK_ExplicitInstantiationDefinition) { const FunctionDecl *KeyFunctionDef = nullptr; if (!KeyFunction || (KeyFunction->hasBody(KeyFunctionDef) && - KeyFunctionDef->isInlined())) { - Diag(Class->getLocation(), - ClassTSK == TSK_ExplicitInstantiationDefinition - ? diag::warn_weak_template_vtable - : diag::warn_weak_vtable) - << Class; - } + KeyFunctionDef->isInlined())) + Diag(Class->getLocation(), diag::warn_weak_vtable) << Class; } } VTableUses.clear(); diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index e0f8c6e92d5..d6e659e1706 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -611,7 +611,7 @@ ActOnSuperClassOfClassInterface(Scope *S, } } - if (!dyn_cast_or_null(PrevDecl)) { + if (!isa_and_nonnull(PrevDecl)) { if (!SuperClassDecl) Diag(SuperLoc, diag::err_undef_superclass) << SuperName << ClassName << SourceRange(AtInterfaceLoc, ClassLoc); @@ -2614,7 +2614,7 @@ void Sema::WarnExactTypedMethods(ObjCMethodDecl *ImpMethodDecl, if (MethodDecl->getImplementationControl() == ObjCMethodDecl::Optional) return; // don't issue warning when primary class's method is - // depecated/unavailable. + // deprecated/unavailable. if (MethodDecl->hasAttr() || MethodDecl->hasAttr()) return; @@ -2711,8 +2711,7 @@ static void CheckProtocolMethodDefs(Sema &S, ProtocolsExplictImpl.reset(new ProtocolNameSet); findProtocolsWithExplicitImpls(Super, *ProtocolsExplictImpl); } - if (ProtocolsExplictImpl->find(PDecl->getIdentifier()) != - ProtocolsExplictImpl->end()) + if (ProtocolsExplictImpl->contains(PDecl->getIdentifier())) return; // If no super class conforms to the protocol, we should not search @@ -3427,8 +3426,10 @@ void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, GlobalMethodPool::iterator Pos = MethodPool.find(Method->getSelector()); if (Pos == MethodPool.end()) - Pos = MethodPool.insert(std::make_pair(Method->getSelector(), - GlobalMethods())).first; + Pos = MethodPool + .insert(std::make_pair(Method->getSelector(), + GlobalMethodPool::Lists())) + .first; Method->setDefined(impl); @@ -3636,7 +3637,7 @@ ObjCMethodDecl *Sema::LookupImplementedMethodInGlobalPool(Selector Sel) { if (Pos == MethodPool.end()) return nullptr; - GlobalMethods &Methods = Pos->second; + GlobalMethodPool::Lists &Methods = Pos->second; for (const ObjCMethodList *Method = &Methods.first; Method; Method = Method->getNext()) if (Method->getMethod() && @@ -4832,7 +4833,7 @@ Decl *Sema::ActOnMethodDeclaration( // If this method overrides a previous @synthesize declaration, // register it with the property. Linear search through all // properties here, because the autosynthesized stub hasn't been - // made visible yet, so it can be overriden by a later + // made visible yet, so it can be overridden by a later // user-specified implementation. for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) { if (auto *Setter = PropertyImpl->getSetterMethodDecl()) diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 8816c9c1fea..3af4c6f4bc4 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -78,14 +78,21 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { .Default(false); } -ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, - Expr *NoexceptExpr, +ExprResult Sema::ActOnNoexceptSpec(Expr *NoexceptExpr, ExceptionSpecificationType &EST) { - // FIXME: This is bogus, a noexcept expression is not a condition. - ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); + + if (NoexceptExpr->isTypeDependent() || + NoexceptExpr->containsUnexpandedParameterPack()) { + EST = EST_DependentNoexcept; + return NoexceptExpr; + } + + llvm::APSInt Result; + ExprResult Converted = CheckConvertedConstantExpression( + NoexceptExpr, Context.BoolTy, Result, CCEK_Noexcept); + if (Converted.isInvalid()) { EST = EST_NoexceptFalse; - // Fill in an expression of 'false' as a fixup. auto *BoolExpr = new (Context) CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc()); @@ -99,9 +106,6 @@ ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, return Converted; } - llvm::APSInt Result; - Converted = VerifyIntegerConstantExpression( - Converted.get(), &Result, diag::err_noexcept_needs_constant_expression); if (!Converted.isInvalid()) EST = !Result ? EST_NoexceptFalse : EST_NoexceptTrue; return Converted; @@ -1492,6 +1496,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPInteropDirectiveClass: case Stmt::OMPDispatchDirectiveClass: case Stmt::OMPMaskedDirectiveClass: + case Stmt::OMPMetaDirectiveClass: + case Stmt::OMPGenericLoopDirectiveClass: case Stmt::ReturnStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0e6c933cd4f..97f2062d448 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -25,9 +25,11 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -366,10 +368,10 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); - if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) { - if (auto *VD = dyn_cast(D)) - checkDeviceDecl(VD, Loc); + if (auto *VD = dyn_cast(D)) + checkTypeSupport(VD->getType(), Loc, VD); + if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) { if (!Context.getTargetInfo().isTLSSupported()) if (const auto *VD = dyn_cast(D)) if (VD->getTLSKind() != VarDecl::TLS_None) @@ -1197,45 +1199,32 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS, /*ConvertInt=*/!IsCompAssign); } -/// Diagnose attempts to convert between __float128 and long double if -/// there is no support for such conversion. Helper function of -/// UsualArithmeticConversions(). +/// Diagnose attempts to convert between __float128, __ibm128 and +/// long double if there is no support for such conversion. +/// Helper function of UsualArithmeticConversions(). static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, QualType RHSType) { - /* No issue converting if at least one of the types is not a floating point - type or the two types have the same rank. - */ - if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || - S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) + // No issue if either is not a floating point type. + if (!LHSType->isFloatingType() || !RHSType->isFloatingType()) return false; - assert(LHSType->isFloatingType() && RHSType->isFloatingType() && - "The remaining types must be floating point types."); - + // No issue if both have the same 128-bit float semantics. auto *LHSComplex = LHSType->getAs(); auto *RHSComplex = RHSType->getAs(); - QualType LHSElemType = LHSComplex ? - LHSComplex->getElementType() : LHSType; - QualType RHSElemType = RHSComplex ? - RHSComplex->getElementType() : RHSType; + QualType LHSElem = LHSComplex ? LHSComplex->getElementType() : LHSType; + QualType RHSElem = RHSComplex ? RHSComplex->getElementType() : RHSType; - // No issue if the two types have the same representation - if (&S.Context.getFloatTypeSemantics(LHSElemType) == - &S.Context.getFloatTypeSemantics(RHSElemType)) + const llvm::fltSemantics &LHSSem = S.Context.getFloatTypeSemantics(LHSElem); + const llvm::fltSemantics &RHSSem = S.Context.getFloatTypeSemantics(RHSElem); + + if ((&LHSSem != &llvm::APFloat::PPCDoubleDouble() || + &RHSSem != &llvm::APFloat::IEEEquad()) && + (&LHSSem != &llvm::APFloat::IEEEquad() || + &RHSSem != &llvm::APFloat::PPCDoubleDouble())) return false; - bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && - RHSElemType == S.Context.LongDoubleTy); - Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && - RHSElemType == S.Context.Float128Ty); - - // We've handled the situation where __float128 and long double have the same - // representation. We allow all conversions for all possible long double types - // except PPC's double double. - return Float128AndLongDouble && - (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == - &llvm::APFloat::PPCDoubleDouble()); + return true; } typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); @@ -1547,8 +1536,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // At this point, we have two different arithmetic types. - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return QualType(); @@ -3193,9 +3182,8 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } -static void -diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var, DeclContext *DC); +static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + ValueDecl *var); /// Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( @@ -3219,8 +3207,7 @@ ExprResult Sema::BuildDeclarationNameExpr( // Make sure that we're referring to a value. if (!isa(D)) { - Diag(Loc, diag::err_ref_non_value) - << D << SS.getRange(); + Diag(Loc, diag::err_ref_non_value) << D << SS.getRange(); Diag(D->getLocation(), diag::note_declared_at); return ExprError(); } @@ -3246,210 +3233,204 @@ ExprResult Sema::BuildDeclarationNameExpr( return BuildAnonymousStructUnionMemberReference(SS, NameInfo.getLoc(), indirectField); - { - QualType type = VD->getType(); - if (type.isNull()) - return ExprError(); - ExprValueKind valueKind = VK_PRValue; + QualType type = VD->getType(); + if (type.isNull()) + return ExprError(); + ExprValueKind valueKind = VK_PRValue; - // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of - // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, - // is expanded by some outer '...' in the context of the use. - type = type.getNonPackExpansionType(); + // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of + // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, + // is expanded by some outer '...' in the context of the use. + type = type.getNonPackExpansionType(); - switch (D->getKind()) { + switch (D->getKind()) { // Ignore all the non-ValueDecl kinds. #define ABSTRACT_DECL(kind) #define VALUE(type, base) -#define DECL(type, base) \ - case Decl::type: +#define DECL(type, base) case Decl::type: #include "clang/AST/DeclNodes.inc" - llvm_unreachable("invalid value decl kind"); + llvm_unreachable("invalid value decl kind"); - // These shouldn't make it here. - case Decl::ObjCAtDefsField: - llvm_unreachable("forming non-member reference to ivar?"); + // These shouldn't make it here. + case Decl::ObjCAtDefsField: + llvm_unreachable("forming non-member reference to ivar?"); - // Enum constants are always r-values and never references. - // Unresolved using declarations are dependent. - case Decl::EnumConstant: - case Decl::UnresolvedUsingValue: - case Decl::OMPDeclareReduction: - case Decl::OMPDeclareMapper: - valueKind = VK_PRValue; - break; + // Enum constants are always r-values and never references. + // Unresolved using declarations are dependent. + case Decl::EnumConstant: + case Decl::UnresolvedUsingValue: + case Decl::OMPDeclareReduction: + case Decl::OMPDeclareMapper: + valueKind = VK_PRValue; + break; - // Fields and indirect fields that got here must be for - // pointer-to-member expressions; we just call them l-values for - // internal consistency, because this subexpression doesn't really - // exist in the high-level semantics. - case Decl::Field: - case Decl::IndirectField: - case Decl::ObjCIvar: - assert(getLangOpts().CPlusPlus && - "building reference to field in C?"); + // Fields and indirect fields that got here must be for + // pointer-to-member expressions; we just call them l-values for + // internal consistency, because this subexpression doesn't really + // exist in the high-level semantics. + case Decl::Field: + case Decl::IndirectField: + case Decl::ObjCIvar: + assert(getLangOpts().CPlusPlus && "building reference to field in C?"); - // These can't have reference type in well-formed programs, but - // for internal consistency we do this anyway. - type = type.getNonReferenceType(); - valueKind = VK_LValue; - break; + // These can't have reference type in well-formed programs, but + // for internal consistency we do this anyway. + type = type.getNonReferenceType(); + valueKind = VK_LValue; + break; - // Non-type template parameters are either l-values or r-values - // depending on the type. - case Decl::NonTypeTemplateParm: { - if (const ReferenceType *reftype = type->getAs()) { - type = reftype->getPointeeType(); - valueKind = VK_LValue; // even if the parameter is an r-value reference - break; - } - - // [expr.prim.id.unqual]p2: - // If the entity is a template parameter object for a template - // parameter of type T, the type of the expression is const T. - // [...] The expression is an lvalue if the entity is a [...] template - // parameter object. - if (type->isRecordType()) { - type = type.getUnqualifiedType().withConst(); - valueKind = VK_LValue; - break; - } - - // For non-references, we need to strip qualifiers just in case - // the template parameter was declared as 'const int' or whatever. - valueKind = VK_PRValue; - type = type.getUnqualifiedType(); + // Non-type template parameters are either l-values or r-values + // depending on the type. + case Decl::NonTypeTemplateParm: { + if (const ReferenceType *reftype = type->getAs()) { + type = reftype->getPointeeType(); + valueKind = VK_LValue; // even if the parameter is an r-value reference break; } - case Decl::Var: - case Decl::VarTemplateSpecialization: - case Decl::VarTemplatePartialSpecialization: - case Decl::Decomposition: - case Decl::OMPCapturedExpr: - // In C, "extern void blah;" is valid and is an r-value. - if (!getLangOpts().CPlusPlus && - !type.hasQualifiers() && - type->isVoidType()) { + // [expr.prim.id.unqual]p2: + // If the entity is a template parameter object for a template + // parameter of type T, the type of the expression is const T. + // [...] The expression is an lvalue if the entity is a [...] template + // parameter object. + if (type->isRecordType()) { + type = type.getUnqualifiedType().withConst(); + valueKind = VK_LValue; + break; + } + + // For non-references, we need to strip qualifiers just in case + // the template parameter was declared as 'const int' or whatever. + valueKind = VK_PRValue; + type = type.getUnqualifiedType(); + break; + } + + case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: + case Decl::Decomposition: + case Decl::OMPCapturedExpr: + // In C, "extern void blah;" is valid and is an r-value. + if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && + type->isVoidType()) { + valueKind = VK_PRValue; + break; + } + LLVM_FALLTHROUGH; + + case Decl::ImplicitParam: + case Decl::ParmVar: { + // These are always l-values. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + + // FIXME: Does the addition of const really only apply in + // potentially-evaluated contexts? Since the variable isn't actually + // captured in an unevaluated context, it seems that the answer is no. + if (!isUnevaluatedContext()) { + QualType CapturedType = getCapturedDeclRefType(cast(VD), Loc); + if (!CapturedType.isNull()) + type = CapturedType; + } + + break; + } + + case Decl::Binding: { + // These are always lvalues. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + // FIXME: Support lambda-capture of BindingDecls, once CWG actually + // decides how that's supposed to work. + auto *BD = cast(VD); + if (BD->getDeclContext() != CurContext) { + auto *DD = dyn_cast_or_null(BD->getDecomposedDecl()); + if (DD && DD->hasLocalStorage()) + diagnoseUncapturableValueReference(*this, Loc, BD); + } + break; + } + + case Decl::Function: { + if (unsigned BID = cast(VD)->getBuiltinID()) { + if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { + type = Context.BuiltinFnTy; valueKind = VK_PRValue; break; } - LLVM_FALLTHROUGH; + } - case Decl::ImplicitParam: - case Decl::ParmVar: { - // These are always l-values. - valueKind = VK_LValue; - type = type.getNonReferenceType(); - - // FIXME: Does the addition of const really only apply in - // potentially-evaluated contexts? Since the variable isn't actually - // captured in an unevaluated context, it seems that the answer is no. - if (!isUnevaluatedContext()) { - QualType CapturedType = getCapturedDeclRefType(cast(VD), Loc); - if (!CapturedType.isNull()) - type = CapturedType; - } + const FunctionType *fty = type->castAs(); + // If we're referring to a function with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + if (fty->getReturnType() == Context.UnknownAnyTy) { + type = Context.UnknownAnyTy; + valueKind = VK_PRValue; break; } - case Decl::Binding: { - // These are always lvalues. + // Functions are l-values in C++. + if (getLangOpts().CPlusPlus) { valueKind = VK_LValue; - type = type.getNonReferenceType(); - // FIXME: Support lambda-capture of BindingDecls, once CWG actually - // decides how that's supposed to work. - auto *BD = cast(VD); - if (BD->getDeclContext() != CurContext) { - auto *DD = dyn_cast_or_null(BD->getDecomposedDecl()); - if (DD && DD->hasLocalStorage()) - diagnoseUncapturableValueReference(*this, Loc, BD, CurContext); - } break; } - case Decl::Function: { - if (unsigned BID = cast(VD)->getBuiltinID()) { - if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { - type = Context.BuiltinFnTy; - valueKind = VK_PRValue; - break; - } - } + // C99 DR 316 says that, if a function type comes from a + // function definition (without a prototype), that type is only + // used for checking compatibility. Therefore, when referencing + // the function, we pretend that we don't have the full function + // type. + if (!cast(VD)->hasPrototype() && isa(fty)) + type = Context.getFunctionNoProtoType(fty->getReturnType(), + fty->getExtInfo()); - const FunctionType *fty = type->castAs(); + // Functions are r-values in C. + valueKind = VK_PRValue; + break; + } - // If we're referring to a function with an __unknown_anytype - // result type, make the entire expression __unknown_anytype. - if (fty->getReturnType() == Context.UnknownAnyTy) { + case Decl::CXXDeductionGuide: + llvm_unreachable("building reference to deduction guide"); + + case Decl::MSProperty: + case Decl::MSGuid: + case Decl::TemplateParamObject: + // FIXME: Should MSGuidDecl and template parameter objects be subject to + // capture in OpenMP, or duplicated between host and device? + valueKind = VK_LValue; + break; + + case Decl::CXXMethod: + // If we're referring to a method with an __unknown_anytype + // result type, make the entire expression __unknown_anytype. + // This should only be possible with a type written directly. + if (const FunctionProtoType *proto = + dyn_cast(VD->getType())) + if (proto->getReturnType() == Context.UnknownAnyTy) { type = Context.UnknownAnyTy; valueKind = VK_PRValue; break; } - // Functions are l-values in C++. - if (getLangOpts().CPlusPlus) { - valueKind = VK_LValue; - break; - } - - // C99 DR 316 says that, if a function type comes from a - // function definition (without a prototype), that type is only - // used for checking compatibility. Therefore, when referencing - // the function, we pretend that we don't have the full function - // type. - if (!cast(VD)->hasPrototype() && - isa(fty)) - type = Context.getFunctionNoProtoType(fty->getReturnType(), - fty->getExtInfo()); - - // Functions are r-values in C. - valueKind = VK_PRValue; - break; - } - - case Decl::CXXDeductionGuide: - llvm_unreachable("building reference to deduction guide"); - - case Decl::MSProperty: - case Decl::MSGuid: - case Decl::TemplateParamObject: - // FIXME: Should MSGuidDecl and template parameter objects be subject to - // capture in OpenMP, or duplicated between host and device? + // C++ methods are l-values if static, r-values if non-static. + if (cast(VD)->isStatic()) { valueKind = VK_LValue; break; - - case Decl::CXXMethod: - // If we're referring to a method with an __unknown_anytype - // result type, make the entire expression __unknown_anytype. - // This should only be possible with a type written directly. - if (const FunctionProtoType *proto - = dyn_cast(VD->getType())) - if (proto->getReturnType() == Context.UnknownAnyTy) { - type = Context.UnknownAnyTy; - valueKind = VK_PRValue; - break; - } - - // C++ methods are l-values if static, r-values if non-static. - if (cast(VD)->isStatic()) { - valueKind = VK_LValue; - break; - } - LLVM_FALLTHROUGH; - - case Decl::CXXConversion: - case Decl::CXXDestructor: - case Decl::CXXConstructor: - valueKind = VK_PRValue; - break; } + LLVM_FALLTHROUGH; - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, - /*FIXME: TemplateKWLoc*/ SourceLocation(), - TemplateArgs); + case Decl::CXXConversion: + case Decl::CXXDestructor: + case Decl::CXXConstructor: + valueKind = VK_PRValue; + break; } + + return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, + /*FIXME: TemplateKWLoc*/ SourceLocation(), + TemplateArgs); } static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, @@ -3832,7 +3813,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { llvm::APInt Val(bit_width, 0, isSigned); bool Overflowed = Literal.GetFixedPointValue(Val, scale); - bool ValIsZero = Val.isNullValue() && !Overflowed; + bool ValIsZero = Val.isZero() && !Overflowed; auto MaxVal = Context.getFixedPointMax(Ty).getValue(); if (Literal.isFract && Val == MaxVal + 1 && !ValIsZero) @@ -3877,7 +3858,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { "cl_khr_fp64", getLangOpts())) { // Impose single-precision float type when cl_khr_fp64 is not enabled. Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64) - << (getLangOpts().OpenCLVersion >= 300); + << (getLangOpts().getOpenCLCompatibleVersion() >= 300); Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } } @@ -5273,7 +5254,7 @@ ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, // OpenMP 5.0, 2.1.6 Iterators, Restrictions // If the step expression of a range-specification equals zero, the // behavior is unspecified. - if (Result && Result->isNullValue()) { + if (Result && Result->isZero()) { Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero) << Step << Step->getSourceRange(); IsCorrect = false; @@ -5728,7 +5709,7 @@ Sema::VariadicCallType Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn) { if (Proto && Proto->isVariadic()) { - if (dyn_cast_or_null(FDecl)) + if (isa_and_nonnull(FDecl)) return VariadicConstructor; else if (Fn && Fn->getType()->isBlockPointerType()) return VariadicBlock; @@ -6249,14 +6230,12 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, QualType OverloadTy = Context.getFunctionType(FT->getReturnType(), OverloadParams, EPI); DeclContext *Parent = FDecl->getParent(); - FunctionDecl *OverloadDecl = FunctionDecl::Create(Context, Parent, - FDecl->getLocation(), - FDecl->getLocation(), - FDecl->getIdentifier(), - OverloadTy, - /*TInfo=*/nullptr, - SC_Extern, false, - /*hasPrototype=*/true); + FunctionDecl *OverloadDecl = FunctionDecl::Create( + Context, Parent, FDecl->getLocation(), FDecl->getLocation(), + FDecl->getIdentifier(), OverloadTy, + /*TInfo=*/nullptr, SC_Extern, Sema->getCurFPFeatures().isFPConstrained(), + false, + /*hasPrototype=*/true); SmallVector Params; FT = cast(OverloadTy); for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) { @@ -6476,7 +6455,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.BoundMemberTy) { return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc, AllowRecovery); + RParenLoc, ExecConfig, IsExecConfig, + AllowRecovery); } } @@ -6495,7 +6475,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, Scope, Fn, ULE, LParenLoc, ArgExprs, RParenLoc, ExecConfig, /*AllowTypoCorrection=*/true, find.IsAddressOfOperand); return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, - RParenLoc, AllowRecovery); + RParenLoc, ExecConfig, IsExecConfig, + AllowRecovery); } } @@ -6543,6 +6524,57 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, return ExprError(); checkDirectCallValidity(*this, Fn, FD, ArgExprs); + + // If this expression is a call to a builtin function in HIP device + // compilation, allow a pointer-type argument to default address space to be + // passed as a pointer-type parameter to a non-default address space. + // If Arg is declared in the default address space and Param is declared + // in a non-default address space, perform an implicit address space cast to + // the parameter type. + if (getLangOpts().HIP && getLangOpts().CUDAIsDevice && FD && + FD->getBuiltinID()) { + for (unsigned Idx = 0; Idx < FD->param_size(); ++Idx) { + ParmVarDecl *Param = FD->getParamDecl(Idx); + if (!ArgExprs[Idx] || !Param || !Param->getType()->isPointerType() || + !ArgExprs[Idx]->getType()->isPointerType()) + continue; + + auto ParamAS = Param->getType()->getPointeeType().getAddressSpace(); + auto ArgTy = ArgExprs[Idx]->getType(); + auto ArgPtTy = ArgTy->getPointeeType(); + auto ArgAS = ArgPtTy.getAddressSpace(); + + // Add address space cast if target address spaces are different + bool NeedImplicitASC = + ParamAS != LangAS::Default && // Pointer params in generic AS don't need special handling. + ( ArgAS == LangAS::Default || // We do allow implicit conversion from generic AS + // or from specific AS which has target AS matching that of Param. + getASTContext().getTargetAddressSpace(ArgAS) == getASTContext().getTargetAddressSpace(ParamAS)); + if (!NeedImplicitASC) + continue; + + // First, ensure that the Arg is an RValue. + if (ArgExprs[Idx]->isGLValue()) { + ArgExprs[Idx] = ImplicitCastExpr::Create( + Context, ArgExprs[Idx]->getType(), CK_NoOp, ArgExprs[Idx], + nullptr, VK_PRValue, FPOptionsOverride()); + } + + // Construct a new arg type with address space of Param + Qualifiers ArgPtQuals = ArgPtTy.getQualifiers(); + ArgPtQuals.setAddressSpace(ParamAS); + auto NewArgPtTy = + Context.getQualifiedType(ArgPtTy.getUnqualifiedType(), ArgPtQuals); + auto NewArgTy = + Context.getQualifiedType(Context.getPointerType(NewArgPtTy), + ArgTy.getQualifiers()); + + // Finally perform an implicit address space cast + ArgExprs[Idx] = ImpCastExprToType(ArgExprs[Idx], NewArgTy, + CK_AddressSpaceConversion) + .get(); + } + } } if (Context.isDependenceAllowed() && @@ -7706,6 +7738,9 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, // initializers must be one or must match the size of the vector. // If a single value is specified in the initializer then it will be // replicated to all the components of the vector + if (CheckAltivecInitFromScalar(E->getSourceRange(), Ty, + VTy->getElementType())) + return ExprError(); if (ShouldSplatAltivecScalarInCast(VTy)) { // The number of initializers must be one or must match the size of the // vector. If a single value is specified in the initializer then it will @@ -8334,8 +8369,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy @@ -8346,7 +8381,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary // selection operator (?:). if (getLangOpts().OpenCL && - (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) { + ((int)checkBlockType(*this, LHS.get()) | (int)checkBlockType(*this, RHS.get()))) { return QualType(); } @@ -9269,8 +9304,8 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return Incompatible; } - // Diagnose attempts to convert between __float128 and long double where - // such conversions currently can't be handled. + // Diagnose attempts to convert between __ibm128, __float128 and long double + // where such conversions currently can't be handled. if (unsupportedTypeConversion(*this, LHSType, RHSType)) return Incompatible; @@ -12191,7 +12226,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (getLangOpts().OpenCLVersion >= 200 || getLangOpts().OpenCLCPlusPlus) { + if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { if (LHSType->isClkEventT() && RHSType->isClkEventT()) { return computeResultTy(); } @@ -12398,8 +12433,7 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || (RHSStrRef.size() > 1 && RHSStrRef.startswith("0")) || - LHSStrRef.find('\'') != StringRef::npos || - RHSStrRef.find('\'') != StringRef::npos) + LHSStrRef.contains('\'') || RHSStrRef.contains('\'')) return; bool SuggestXor = @@ -12450,8 +12484,9 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, /*AllowBoolConversions*/false); if (vType.isNull()) return InvalidOperands(Loc, LHS, RHS); - if (getLangOpts().OpenCL && getLangOpts().OpenCLVersion < 120 && - !getLangOpts().OpenCLCPlusPlus && vType->hasFloatingRepresentation()) + if (getLangOpts().OpenCL && + getLangOpts().getOpenCLCompatibleVersion() < 120 && + vType->hasFloatingRepresentation()) return InvalidOperands(Loc, LHS, RHS); // FIXME: The check for C++ here is for GCC compatibility. GCC rejects the // usage of the logical operators && and || with vectors in C. This @@ -12913,7 +12948,7 @@ static void DiagnoseRecursiveConstFields(Sema &S, const ValueDecl *VD, // Then we append it to the list to check next in order. FieldTy = FieldTy.getCanonicalType(); if (const auto *FieldRecTy = FieldTy->getAs()) { - if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + if (!llvm::is_contained(RecordTypeList, FieldRecTy)) RecordTypeList.push_back(FieldRecTy); } } @@ -13340,7 +13375,7 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, if (LHS.isInvalid()) return QualType(); - S.DiagnoseUnusedExprResult(LHS.get()); + S.DiagnoseUnusedExprResult(LHS.get(), diag::warn_unused_comma_left_operand); if (!S.getLangOpts().CPlusPlus) { RHS = S.DefaultFunctionArrayLvalueConversion(RHS.get()); @@ -14132,6 +14167,9 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } } + checkTypeSupport(LHSExpr->getType(), OpLoc, /*ValueDecl*/ nullptr); + checkTypeSupport(RHSExpr->getType(), OpLoc, /*ValueDecl*/ nullptr); + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); @@ -14902,8 +14940,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, } } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && - Context.getLangOpts().OpenCLVersion < 120 && - !Context.getLangOpts().OpenCLCPlusPlus) { + Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { // OpenCL v1.1 6.3.h: The logical operator not (!) does not // operate on vector float types. QualType T = resultType->castAs()->getElementType(); @@ -15683,7 +15720,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (!Result.isInvalid()) { Result = PerformCopyInitialization( InitializedEntity::InitializeBlock(Var->getLocation(), - Cap.getCaptureType(), false), + Cap.getCaptureType()), Loc, Result.get()); } @@ -16602,15 +16639,15 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { if (auto *BO = dyn_cast(E->IgnoreParenImpCasts())) { if (BO->getOpcode() == BO_Assign) { auto &LHSs = ExprEvalContexts.back().VolatileAssignmentLHSs; - LHSs.erase(std::remove(LHSs.begin(), LHSs.end(), BO->getLHS()), - LHSs.end()); + llvm::erase_value(LHSs, BO->getLHS()); } } } ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { - if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || - RebuildingImmediateInvocation) + if (isUnevaluatedContext() || !E.isUsable() || !Decl || + !Decl->isConsteval() || isConstantEvaluated() || + RebuildingImmediateInvocation || isImmediateFunctionContext()) return E; /// Opportunistically remove the callee from ReferencesToConsteval if we can. @@ -16881,6 +16918,8 @@ static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) { // An expression or conversion is potentially constant evaluated if it is switch (SemaRef.ExprEvalContexts.back().Context) { case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::ImmediateFunctionContext: + // -- a manifestly constant-evaluated expression, case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: @@ -17003,6 +17042,7 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) { return OdrUseContext::None; case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::ImmediateFunctionContext: case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: Result = OdrUseContext::Used; break; @@ -17351,9 +17391,8 @@ void Sema::MarkCaptureUsedInEnclosingContext(VarDecl *Capture, MarkVarDeclODRUsed(Capture, Loc, *this, &CapturingScopeIndex); } -static void -diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - ValueDecl *var, DeclContext *DC) { +static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + ValueDecl *var) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -17432,7 +17471,7 @@ static DeclContext *getParentOfCapturingContextOrNull(DeclContext *DC, VarDecl * return getLambdaAwareParentOfDeclContext(DC); else if (Var->hasLocalStorage()) { if (Diagnose) - diagnoseUncapturableValueReference(S, Loc, Var, DC); + diagnoseUncapturableValueReference(S, Loc, Var); } return nullptr; } @@ -17906,7 +17945,7 @@ bool Sema::tryCaptureVariable( Diag(LSI->Lambda->getBeginLoc(), diag::note_lambda_decl); buildLambdaCaptureFixit(*this, LSI, Var); } else - diagnoseUncapturableValueReference(*this, ExprLoc, Var, DC); + diagnoseUncapturableValueReference(*this, ExprLoc, Var); } return true; } @@ -18270,7 +18309,6 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(), ME->getFoundDecl(), ME->getMemberNameInfo(), CopiedTemplateArgs(ME), ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR); - return ExprEmpty(); } case Expr::BinaryOperatorClass: { @@ -18726,8 +18764,8 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { OdrUse = false; if (auto *FD = dyn_cast(E->getDecl())) - if (!isConstantEvaluated() && FD->isConsteval() && - !RebuildingImmediateInvocation) + if (!isUnevaluatedContext() && !isConstantEvaluated() && + FD->isConsteval() && !RebuildingImmediateInvocation) ExprEvalContexts.back().ReferenceToConsteval.insert(E); MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse, RefsMinusAssignments); @@ -18829,14 +18867,22 @@ class EvaluatedExprMarker : public UsedDeclVisitor { public: typedef UsedDeclVisitor Inherited; bool SkipLocalVariables; + ArrayRef StopAt; - EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) - : Inherited(S), SkipLocalVariables(SkipLocalVariables) {} + EvaluatedExprMarker(Sema &S, bool SkipLocalVariables, + ArrayRef StopAt) + : Inherited(S), SkipLocalVariables(SkipLocalVariables), StopAt(StopAt) {} void visitUsedDecl(SourceLocation Loc, Decl *D) { S.MarkFunctionReferenced(Loc, cast(D)); } + void Visit(Expr *E) { + if (std::find(StopAt.begin(), StopAt.end(), E) != StopAt.end()) + return; + Inherited::Visit(E); + } + void VisitDeclRefExpr(DeclRefExpr *E) { // If we were asked not to visit local variables, don't. if (SkipLocalVariables) { @@ -18863,9 +18909,43 @@ public: /// /// \param SkipLocalVariables If true, don't mark local variables as /// 'referenced'. +/// \param StopAt Subexpressions that we shouldn't recurse into. void Sema::MarkDeclarationsReferencedInExpr(Expr *E, - bool SkipLocalVariables) { - EvaluatedExprMarker(*this, SkipLocalVariables).Visit(E); + bool SkipLocalVariables, + ArrayRef StopAt) { + EvaluatedExprMarker(*this, SkipLocalVariables, StopAt).Visit(E); +} + +/// Emit a diagnostic when statements are reachable. +/// FIXME: check for reachability even in expressions for which we don't build a +/// CFG (eg, in the initializer of a global or in a constant expression). +/// For example, +/// namespace { auto *p = new double[3][false ? (1, 2) : 3]; } +bool Sema::DiagIfReachable(SourceLocation Loc, ArrayRef Stmts, + const PartialDiagnostic &PD) { + if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { + if (!FunctionScopes.empty()) + FunctionScopes.back()->PossiblyUnreachableDiags.push_back( + sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); + return true; + } + + // The initializer of a constexpr variable or of the first declaration of a + // static data member is not syntactically a constant evaluated constant, + // but nonetheless is always required to be a constant expression, so we + // can skip diagnosing. + // FIXME: Using the mangling context here is a hack. + if (auto *VD = dyn_cast_or_null( + ExprEvalContexts.back().ManglingContextDecl)) { + if (VD->isConstexpr() || + (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) + return false; + // FIXME: For any other kind of variable, we should build a CFG for its + // initializer and check whether the context in question is reachable. + } + + Diag(Loc, PD); + return true; } /// Emit a diagnostic that describes an effect on the run-time behavior @@ -18895,33 +18975,13 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, ArrayRef Stmts, break; case ExpressionEvaluationContext::ConstantEvaluated: + case ExpressionEvaluationContext::ImmediateFunctionContext: // Relevant diagnostics should be produced by constant evaluation. break; case ExpressionEvaluationContext::PotentiallyEvaluated: case ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: - if (!Stmts.empty() && getCurFunctionOrMethodDecl()) { - FunctionScopes.back()->PossiblyUnreachableDiags. - push_back(sema::PossiblyUnreachableDiag(PD, Loc, Stmts)); - return true; - } - - // The initializer of a constexpr variable or of the first declaration of a - // static data member is not syntactically a constant evaluated constant, - // but nonetheless is always required to be a constant expression, so we - // can skip diagnosing. - // FIXME: Using the mangling context here is a hack. - if (auto *VD = dyn_cast_or_null( - ExprEvalContexts.back().ManglingContextDecl)) { - if (VD->isConstexpr() || - (VD->isStaticDataMember() && VD->isFirstDecl() && !VD->isInline())) - break; - // FIXME: For any other kind of variable, we should build a CFG for its - // initializer and check whether the context in question is reachable. - } - - Diag(Loc, PD); - return true; + return DiagIfReachable(Loc, Stmts, PD); } return false; @@ -19371,14 +19431,7 @@ ExprResult RebuildUnknownAnyExpr::VisitCallExpr(CallExpr *E) { if (ParamTypes.empty() && Proto->isVariadic()) { // the special case ArgTypes.reserve(E->getNumArgs()); for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { - Expr *Arg = E->getArg(i); - QualType ArgType = Arg->getType(); - if (E->isLValue()) { - ArgType = S.Context.getLValueReferenceType(ArgType); - } else if (E->isXValue()) { - ArgType = S.Context.getRValueReferenceType(ArgType); - } - ArgTypes.push_back(ArgType); + ArgTypes.push_back(S.Context.getReferenceQualifiedType(E->getArg(i))); } ParamTypes = ArgTypes; } @@ -19505,7 +19558,8 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { FunctionDecl *NewFD = FunctionDecl::Create( S.Context, FD->getDeclContext(), Loc, Loc, FD->getNameInfo().getName(), DestType, FD->getTypeSourceInfo(), - SC_None, false /*isInlineSpecified*/, FD->hasPrototype(), + SC_None, S.getCurFPFeatures().isFPConstrained(), + false /*isInlineSpecified*/, FD->hasPrototype(), /*ConstexprKind*/ ConstexprSpecKind::Unspecified); if (FD->getQualifier()) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 111ffa1f04a..891909c443c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -468,7 +468,7 @@ ParsedType Sema::getDestructorTypeForDecltype(const DeclSpec &DS, assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "unexpected type in getDestructorType"); - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); + QualType T = BuildDecltypeType(DS.getRepAsExpr()); // If we know the type of the object, check that the correct destructor // type was named now; we can give better diagnostics this way. @@ -494,7 +494,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); - if (Status != ReservedIdentifierStatus::NotReserved && + if (isReservedInAllContexts(Status) && !PP.getSourceManager().isInSystemHeader(Loc)) { Diag(Loc, diag::warn_reserved_extern_symbol) << II << static_cast(Status) @@ -893,9 +893,8 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); - InitializedEntity Entity = InitializedEntity::InitializeException( - OpLoc, ExceptionObjectTy, - /*NRVO=*/NRInfo.isCopyElidable()); + InitializedEntity Entity = + InitializedEntity::InitializeException(OpLoc, ExceptionObjectTy); ExprResult Res = PerformMoveOrCopyInitialization(Entity, NRInfo, Ex); if (Res.isInvalid()) return ExprError(); @@ -1137,11 +1136,10 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( } } - // 2) We've run out of ScopeInfos but check if CurDC is a lambda (which can - // happen during instantiation of its nested generic lambda call operator) - if (isLambdaCallOperator(CurDC)) { - assert(CurLSI && "While computing 'this' capture-type for a generic " - "lambda, we must have a corresponding LambdaScopeInfo"); + // 2) We've run out of ScopeInfos but check 1. if CurDC is a lambda (which + // can happen during instantiation of its nested generic lambda call + // operator); 2. if we're in a lambda scope (lambda body). + if (CurLSI && isLambdaCallOperator(CurDC)) { assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator) && "While computing 'this' capture-type for a generic lambda, when we " "run out of enclosing LSI's, yet the enclosing DC is a " @@ -1454,7 +1452,8 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc); - InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); + InitializedEntity Entity = + InitializedEntity::InitializeTemporary(Context, TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization @@ -1968,10 +1967,10 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (Deduced && isa(Deduced)) { if (ArraySize) return ExprError( - Diag(ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), + Diag(*ArraySize ? (*ArraySize)->getExprLoc() : TypeRange.getBegin(), diag::err_deduced_class_template_compound_type) << /*array*/ 2 - << (ArraySize ? (*ArraySize)->getSourceRange() : TypeRange)); + << (*ArraySize ? (*ArraySize)->getSourceRange() : TypeRange)); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, AllocType); @@ -2138,39 +2137,38 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // Let's see if this is a constant < 0. If so, we reject it out of hand, // per CWG1464. Otherwise, if it's not a constant, we must have an // unparenthesized array type. - if (!(*ArraySize)->isValueDependent()) { - // We've already performed any required implicit conversion to integer or - // unscoped enumeration type. - // FIXME: Per CWG1464, we are required to check the value prior to - // converting to size_t. This will never find a negative array size in - // C++14 onwards, because Value is always unsigned here! - if (Optional Value = - (*ArraySize)->getIntegerConstantExpr(Context)) { - if (Value->isSigned() && Value->isNegative()) { - return ExprError(Diag((*ArraySize)->getBeginLoc(), - diag::err_typecheck_negative_array_size) - << (*ArraySize)->getSourceRange()); - } - if (!AllocType->isDependentType()) { - unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits( - Context, AllocType, *Value); - if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) - return ExprError( - Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large) - << toString(*Value, 10) << (*ArraySize)->getSourceRange()); - } - - KnownArraySize = Value->getZExtValue(); - } else if (TypeIdParens.isValid()) { - // Can't have dynamic array size when the type-id is in parentheses. - Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst) - << (*ArraySize)->getSourceRange() - << FixItHint::CreateRemoval(TypeIdParens.getBegin()) - << FixItHint::CreateRemoval(TypeIdParens.getEnd()); - - TypeIdParens = SourceRange(); + // We've already performed any required implicit conversion to integer or + // unscoped enumeration type. + // FIXME: Per CWG1464, we are required to check the value prior to + // converting to size_t. This will never find a negative array size in + // C++14 onwards, because Value is always unsigned here! + if (Optional Value = + (*ArraySize)->getIntegerConstantExpr(Context)) { + if (Value->isSigned() && Value->isNegative()) { + return ExprError(Diag((*ArraySize)->getBeginLoc(), + diag::err_typecheck_negative_array_size) + << (*ArraySize)->getSourceRange()); } + + if (!AllocType->isDependentType()) { + unsigned ActiveSizeBits = + ConstantArrayType::getNumAddressingBits(Context, AllocType, *Value); + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) + return ExprError( + Diag((*ArraySize)->getBeginLoc(), diag::err_array_too_large) + << toString(*Value, 10) << (*ArraySize)->getSourceRange()); + } + + KnownArraySize = Value->getZExtValue(); + } else if (TypeIdParens.isValid()) { + // Can't have dynamic array size when the type-id is in parentheses. + Diag((*ArraySize)->getBeginLoc(), diag::ext_new_paren_array_nonconst) + << (*ArraySize)->getSourceRange() + << FixItHint::CreateRemoval(TypeIdParens.getBegin()) + << FixItHint::CreateRemoval(TypeIdParens.getEnd()); + + TypeIdParens = SourceRange(); } // Note that we do *not* convert the argument in any way. It can @@ -2248,8 +2246,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } IntegerLiteral AllocationSizeLiteral( - Context, - AllocationSize.getValueOr(llvm::APInt::getNullValue(SizeTyWidth)), + Context, AllocationSize.getValueOr(llvm::APInt::getZero(SizeTyWidth)), SizeTy, SourceLocation()); // Otherwise, if we failed to constant-fold the allocation size, we'll // just give up and pass-in something opaque, that isn't a null pointer. @@ -2594,10 +2591,9 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? // FIXME: Using a dummy value will interact poorly with attribute enable_if. - IntegerLiteral Size(Context, llvm::APInt::getNullValue( - Context.getTargetInfo().getPointerWidth(0)), - Context.getSizeType(), - SourceLocation()); + IntegerLiteral Size( + Context, llvm::APInt::getZero(Context.getTargetInfo().getPointerWidth(0)), + Context.getSizeType(), SourceLocation()); AllocArgs.push_back(&Size); QualType AlignValT = Context.VoidTy; @@ -3049,6 +3045,9 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, EPI.ExceptionSpec.Type = EST_Dynamic; EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } + if (getLangOpts().NewInfallible) { + EPI.ExceptionSpec.Type = EST_DynamicNone; + } } else { EPI.ExceptionSpec = getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; @@ -3057,12 +3056,17 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, auto CreateAllocationFunctionDecl = [&](Attr *ExtraAttr) { QualType FnType = Context.getFunctionType(Return, Params, EPI); FunctionDecl *Alloc = FunctionDecl::Create( - Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, - FnType, /*TInfo=*/nullptr, SC_None, false, true); + Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, FnType, + /*TInfo=*/nullptr, SC_None, getCurFPFeatures().isFPConstrained(), false, + true); Alloc->setImplicit(); // Global allocation functions should always be visible. Alloc->setVisibleDespiteOwningModule(); + if (HasBadAllocExceptionSpec && getLangOpts().NewInfallible) + Alloc->addAttr( + ReturnsNonNullAttr::CreateImplicit(Context, Alloc->getLocation())); + Alloc->addAttr(VisibilityAttr::CreateImplicit( Context, LangOpts.GlobalAllocationFunctionVisibilityHidden ? VisibilityAttr::Hidden @@ -5285,7 +5289,8 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, S, Sema::ExpressionEvaluationContext::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); - InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); + InitializedEntity To( + InitializedEntity::InitializeTemporary(S.Context, Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); InitializationSequence Init(S, To, InitKind, ArgExprs); @@ -5891,10 +5896,8 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. - if (To->isLValue() || To->isXValue()) { - QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) - : Self.Context.getRValueReferenceType(ToType); - + if (To->isGLValue()) { + QualType T = Self.Context.getReferenceQualifiedType(To); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); @@ -6670,8 +6673,15 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } else if (Steps.size() == 1) { bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2); bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1); - if (MaybeQ1 == MaybeQ2) - return QualType(); // No unique best address space. + if (MaybeQ1 == MaybeQ2) { + // Exception for ptr size address spaces. Should be able to choose + // either address space during comparison. + if (isPtrSizeAddressSpace(Q1.getAddressSpace()) || + isPtrSizeAddressSpace(Q2.getAddressSpace())) + MaybeQ1 = true; + else + return QualType(); // No unique best address space. + } Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace() : Q2.getAddressSpace()); } else { @@ -6700,6 +6710,36 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } // FIXME: Can we unify the following with UnwrapSimilarTypes? + + const ArrayType *Arr1, *Arr2; + if ((Arr1 = Context.getAsArrayType(Composite1)) && + (Arr2 = Context.getAsArrayType(Composite2))) { + auto *CAT1 = dyn_cast(Arr1); + auto *CAT2 = dyn_cast(Arr2); + if (CAT1 && CAT2 && CAT1->getSize() == CAT2->getSize()) { + Composite1 = Arr1->getElementType(); + Composite2 = Arr2->getElementType(); + Steps.emplace_back(Step::Array, CAT1); + continue; + } + bool IAT1 = isa(Arr1); + bool IAT2 = isa(Arr2); + if ((IAT1 && IAT2) || + (getLangOpts().CPlusPlus20 && (IAT1 != IAT2) && + ((bool)CAT1 != (bool)CAT2) && + (Steps.empty() || Steps.back().K != Step::Array))) { + // In C++20 onwards, we can unify an array of N T with an array of + // a different or unknown bound. But we can't form an array whose + // element type is an array of unknown bound by doing so. + Composite1 = Arr1->getElementType(); + Composite2 = Arr2->getElementType(); + Steps.emplace_back(Step::Array); + if (CAT1 || CAT2) + NeedConstBefore = Steps.size(); + continue; + } + } + const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { @@ -6760,8 +6800,6 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, continue; } - // FIXME: arrays - // FIXME: block pointer types? // Cannot unwrap any more types. @@ -7723,8 +7761,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, return true; } - QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), - false); + QualType T = BuildDecltypeType(DS.getRepAsExpr(), /*AsUnevaluated=*/false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); @@ -8519,7 +8556,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, if (FullExpr.isInvalid()) return ExprError(); - DiagnoseUnusedExprResult(FullExpr.get()); + DiagnoseUnusedExprResult(FullExpr.get(), diag::warn_unused_expr); } FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr, @@ -8743,7 +8780,7 @@ Sema::BuildExprRequirement( TemplateParameterList *TPL = ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); QualType MatchedType = - getDecltypeForParenthesizedExpr(E).getCanonicalType(); + Context.getReferenceQualifiedType(E).getCanonicalType(); llvm::SmallVector Args; Args.push_back(TemplateArgument(MatchedType)); TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index af2aa49c010..83006f9d804 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -144,6 +144,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, case Sema::ExpressionEvaluationContext::DiscardedStatement: case Sema::ExpressionEvaluationContext::ConstantEvaluated: + case Sema::ExpressionEvaluationContext::ImmediateFunctionContext: case Sema::ExpressionEvaluationContext::PotentiallyEvaluated: case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed: break; @@ -340,7 +341,8 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, // Emit a warning if an rgba selector is used earlier than OpenCL C 3.0. if (HasRGBA || (*compStr && IsRGBA(*compStr))) { - if (S.getLangOpts().OpenCL && S.getLangOpts().OpenCLVersion < 300) { + if (S.getLangOpts().OpenCL && + S.getLangOpts().getOpenCLCompatibleVersion() < 300) { const char *DiagBegin = HasRGBA ? CompName->getNameStart() : compStr; S.Diag(OpLoc, diag::ext_opencl_ext_vector_type_rgba_selector) << StringRef(DiagBegin, 1) << SourceRange(CompLoc); @@ -564,10 +566,7 @@ bool Sema::CheckQualifiedMemberReference(Expr *BaseExpr, return false; // Note that we use the DC of the decl, not the underlying decl. - DeclContext *DC = (*I)->getDeclContext(); - while (DC->isTransparentContext()) - DC = DC->getParent(); - + DeclContext *DC = (*I)->getDeclContext()->getNonTransparentContext(); if (!DC->isRecord()) continue; @@ -612,11 +611,10 @@ public: if (Record->containsDecl(ND)) return true; - if (const CXXRecordDecl *RD = dyn_cast(Record)) { + if (const auto *RD = dyn_cast(Record)) { // Accept candidates that occur in any of the current class' base classes. for (const auto &BS : RD->bases()) { - if (const RecordType *BSTy = - dyn_cast_or_null(BS.getType().getTypePtrOrNull())) { + if (const auto *BSTy = BS.getType()->getAs()) { if (BSTy->getDecl()->containsDecl(ND)) return true; } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 8a9c933fc93..bdc8e1e0b33 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -3772,7 +3772,7 @@ static void addFixitForObjCARCConversion( SourceManager &SM = S.getSourceManager(); char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1)); - if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts())) + if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts())) BridgeCall += ' '; BridgeCall += CFBridgeName; @@ -3790,7 +3790,7 @@ static void addFixitForObjCARCConversion( SourceManager &SM = S.getSourceManager(); char PrevChar = *SM.getCharacterData(range.getBegin().getLocWithOffset(-1)); - if (Lexer::isIdentifierBodyChar(PrevChar, S.getLangOpts())) + if (Lexer::isAsciiIdentifierContinueChar(PrevChar, S.getLangOpts())) BridgeCall += ' '; BridgeCall += CFBridgeName; @@ -4015,12 +4015,11 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, if (Parm->isStr("id")) return true; - NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), Sema::LookupOrdinaryName); if (S.LookupName(R, S.TUScope)) { - Target = R.getFoundDecl(); + NamedDecl *Target = R.getFoundDecl(); if (Target && isa(Target)) { ObjCInterfaceDecl *ExprClass = cast(Target); if (const ObjCObjectPointerType *InterfacePointerType = @@ -4056,8 +4055,6 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, diag::err_objc_cf_bridged_not_interface) << castExpr->getType() << Parm; S.Diag(TDNDecl->getBeginLoc(), diag::note_declared_at); - if (Target) - S.Diag(Target->getBeginLoc(), diag::note_declared_at); } return true; } @@ -4453,9 +4450,14 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType, // Allow casts between pointers to lifetime types (e.g., __strong id*) // and pointers to void (e.g., cv void *). Casting from void* to lifetime* // must be explicit. - if (exprACTC == ACTC_indirectRetainable && castACTC == ACTC_voidPtr) + // Allow conversions between pointers to lifetime types and coreFoundation + // pointers too, but only when the conversions are explicit. + if (exprACTC == ACTC_indirectRetainable && + (castACTC == ACTC_voidPtr || + (castACTC == ACTC_coreFoundation && isCast(CCK)))) return ACR_okay; - if (castACTC == ACTC_indirectRetainable && exprACTC == ACTC_voidPtr && + if (castACTC == ACTC_indirectRetainable && + (exprACTC == ACTC_voidPtr || exprACTC == ACTC_coreFoundation) && isCast(CCK)) return ACR_okay; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 78574e34d90..119a90deb9c 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2041,7 +2041,7 @@ void InitListChecker::CheckStructUnionTypes( RecordDecl *structDecl = DeclType->castAs()->getDecl(); // If the record is invalid, some of it's members are invalid. To avoid - // confusion, we forgo checking the intializer for the entire record. + // confusion, we forgo checking the initializer for the entire record. if (structDecl->isInvalidDecl()) { // Assume it was supposed to consume a single initializer. ++Index; @@ -2899,7 +2899,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // We're modifying a string literal init; we have to decompose the string // so we can modify the individual characters. ASTContext &Context = SemaRef.Context; - Expr *SubExpr = StructuredList->getInit(0)->IgnoreParens(); + Expr *SubExpr = StructuredList->getInit(0)->IgnoreParenImpCasts(); // Compute the character type QualType CharTy = AT->getElementType(); @@ -3501,10 +3501,10 @@ void InitializationSequence::Step::Destroy() { bool InitializationSequence::isDirectReferenceBinding() const { // There can be some lvalue adjustments after the SK_BindReference step. - for (auto I = Steps.rbegin(); I != Steps.rend(); ++I) { - if (I->Kind == SK_BindReference) + for (const Step &S : llvm::reverse(Steps)) { + if (S.Kind == SK_BindReference) return true; - if (I->Kind == SK_BindReferenceToTemporary) + if (S.Kind == SK_BindReferenceToTemporary) return false; } return false; @@ -6932,10 +6932,10 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, return; // Once we initialized a value with a reference, it can no longer dangle. if (!Value) { - for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) { - if (It->Kind == IndirectLocalPathEntry::GslReferenceInit) + for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) { + if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit) continue; - if (It->Kind == IndirectLocalPathEntry::GslPointerInit) + if (PE.Kind == IndirectLocalPathEntry::GslPointerInit) return; break; } @@ -8252,7 +8252,7 @@ ExprResult InitializationSequence::Perform(Sema &S, // When this is an incomplete array type (such as when this is // initializing an array of unknown bounds from an init list), use THAT - // type instead so that we propogate the array bounds. + // type instead so that we propagate the array bounds. if (MTETy->isIncompleteArrayType() && !CurInit.get()->getType()->isIncompleteArrayType() && S.Context.hasSameType( @@ -8914,12 +8914,16 @@ static void emitBadConversionNotes(Sema &S, const InitializedEntity &entity, S.EmitRelatedResultTypeNoteForReturn(destType); } QualType fromType = op->getType(); - auto *fromDecl = fromType.getTypePtr()->getPointeeCXXRecordDecl(); - auto *destDecl = destType.getTypePtr()->getPointeeCXXRecordDecl(); + QualType fromPointeeType = fromType.getCanonicalType()->getPointeeType(); + QualType destPointeeType = destType.getCanonicalType()->getPointeeType(); + auto *fromDecl = fromType->getPointeeCXXRecordDecl(); + auto *destDecl = destType->getPointeeCXXRecordDecl(); if (fromDecl && destDecl && fromDecl->getDeclKind() == Decl::CXXRecord && destDecl->getDeclKind() == Decl::CXXRecord && !fromDecl->isInvalidDecl() && !destDecl->isInvalidDecl() && - !fromDecl->hasDefinition()) + !fromDecl->hasDefinition() && + destPointeeType.getQualifiers().compatiblyIncludes( + fromPointeeType.getQualifiers())) S.Diag(fromDecl->getLocation(), diag::note_forward_class_conversion) << S.getASTContext().getTagDeclType(fromDecl) << S.getASTContext().getTagDeclType(destDecl); @@ -9911,8 +9915,7 @@ Sema::PerformCopyInitialization(const InitializedEntity &Entity, const bool ShouldTrackCopy = Entity.isParameterKind() && Seq.isConstructorInitialization(); if (ShouldTrackCopy) { - if (llvm::find(CurrentParameterCopyTypes, Entity.getType()) != - CurrentParameterCopyTypes.end()) { + if (llvm::is_contained(CurrentParameterCopyTypes, Entity.getType())) { Seq.SetOverloadFailure( InitializationSequence::FK_ConstructorOverloadFailed, OR_No_Viable_Function); @@ -9969,7 +9972,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( auto TemplateName = DeducedTST->getTemplateName(); if (TemplateName.isDependent()) - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); // We can only perform deduction for class templates. auto *Template = @@ -9988,7 +9991,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Diag(TSInfo->getTypeLoc().getBeginLoc(), diag::warn_cxx14_compat_class_template_argument_deduction) << TSInfo->getTypeLoc().getSourceRange() << 0; - return SubstAutoType(TSInfo->getType(), Context.DependentTy); + return SubstAutoTypeDependent(TSInfo->getType()); } // FIXME: Perform "exact type" matching first, per CWG discussion? diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index eb1e9c3e5f7..b05e0b5cc0f 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -373,7 +373,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, const FunctionProtoType *FPT = MethodType->castAs(); QualType Result = FPT->getReturnType(); if (Result->isUndeducedType()) { - Result = SubstAutoType(Result, Context.DependentTy); + Result = SubstAutoTypeDependent(Result); MethodType = Context.getFunctionType(Result, FPT->getParamTypes(), FPT->getExtProtoInfo()); } @@ -392,7 +392,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, Context, Class, EndLoc, DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), - MethodType, MethodTypeInfo, SC_None, + MethodType, MethodTypeInfo, SC_None, getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); Method->setAccess(AS_public); if (!TemplateParams) @@ -1245,7 +1245,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // cleanups from the enclosing full-expression. PushExpressionEvaluationContext( LSI->CallOperator->isConsteval() - ? ExpressionEvaluationContext::ConstantEvaluated + ? ExpressionEvaluationContext::ImmediateFunctionContext : ExpressionEvaluationContext::PotentiallyEvaluated); } @@ -1447,6 +1447,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXConversionDecl *Conversion = CXXConversionDecl::Create( S.Context, Class, Loc, DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI, + S.getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ExplicitSpecifier(), S.getLangOpts().CPlusPlus17 ? ConstexprSpecKind::Constexpr : ConstexprSpecKind::Unspecified, @@ -1488,6 +1489,7 @@ static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXMethodDecl *Invoke = CXXMethodDecl::Create( S.Context, Class, Loc, DeclarationNameInfo(InvokerName, Loc), InvokerFunctionTy, CallOperator->getTypeSourceInfo(), SC_Static, + S.getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ConstexprSpecKind::Unspecified, CallOperator->getBody()->getEndLoc()); for (unsigned I = 0, N = CallOperator->getNumParams(); I != N; ++I) @@ -1556,6 +1558,7 @@ static void addBlockPointerConversion(Sema &S, CXXConversionDecl *Conversion = CXXConversionDecl::Create( S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy, S.Context.getTrivialTypeSourceInfo(ConvTy, Loc), + S.getCurFPFeatures().isFPConstrained(), /*isInline=*/true, ExplicitSpecifier(), ConstexprSpecKind::Unspecified, CallOperator->getBody()->getEndLoc()); Conversion->setAccess(AS_public); @@ -1945,6 +1948,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // ratified, it lays out the exact set of conditions where we shouldn't // allow a lambda-expression. case ExpressionEvaluationContext::ConstantEvaluated: + case ExpressionEvaluationContext::ImmediateFunctionContext: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). @@ -1975,8 +1979,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, CallOperator->markUsed(Context); ExprResult Init = PerformCopyInitialization( - InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType(), - /*NRVO=*/false), + InitializedEntity::InitializeLambdaToBlock(ConvLocation, Src->getType()), CurrentLocation, Src); if (!Init.isInvalid()) Init = ActOnFinishFullExpr(Init.get(), /*DiscardedValue*/ false); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 5e8c4de61e5..05529d05562 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -859,7 +859,8 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, for (const auto &FTy : FunctionList) { NewOpenCLBuiltin = FunctionDecl::Create( Context, Parent, Loc, Loc, II, FTy, /*TInfo=*/nullptr, SC_Extern, - false, FTy->isFunctionProtoType()); + S.getCurFPFeatures().isFPConstrained(), false, + FTy->isFunctionProtoType()); NewOpenCLBuiltin->setImplicit(); // Create Decl objects for each parameter, adding them to the @@ -3845,7 +3846,7 @@ private: : Ctx->noload_lookups(/*PreserveInternalState=*/false)) { for (auto *D : R) { if (auto *ND = Result.getAcceptableDecl(D)) { - // Rather than visit immediatelly, we put ND into a vector and visit + // Rather than visit immediately, we put ND into a vector and visit // all decls, in order, outside of this loop. The reason is that // Consumer.FoundDecl() may invalidate the iterators used in the two // loops above. @@ -4595,9 +4596,7 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( dyn_cast_or_null(NamespaceDeclChain.back())) { IdentifierInfo *Name = ND->getIdentifier(); bool SameNameSpecifier = false; - if (std::find(CurNameSpecifierIdentifiers.begin(), - CurNameSpecifierIdentifiers.end(), - Name) != CurNameSpecifierIdentifiers.end()) { + if (llvm::is_contained(CurNameSpecifierIdentifiers, Name)) { std::string NewNameSpecifier; llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier); SmallVector NewNameSpecifierIdentifiers; @@ -4606,8 +4605,7 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( SpecifierOStream.flush(); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } - if (SameNameSpecifier || llvm::find(CurContextIdentifiers, Name) != - CurContextIdentifiers.end()) { + if (SameNameSpecifier || llvm::is_contained(CurContextIdentifiers, Name)) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. NNS = NestedNameSpecifier::GlobalSpecifier(Context); NumSpecifiers = @@ -5325,11 +5323,8 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { return FD->getDefinition(); if (TagDecl *TD = dyn_cast(D)) return TD->getDefinition(); - // The first definition for this ObjCInterfaceDecl might be in the TU - // and not associated with any module. Use the one we know to be complete - // and have just seen in a module. if (ObjCInterfaceDecl *ID = dyn_cast(D)) - return ID; + return ID->getDefinition(); if (ObjCProtocolDecl *PD = dyn_cast(D)) return PD->getDefinition(); if (TemplateDecl *TD = dyn_cast(D)) diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index a329d0f22b0..74c73ace3c5 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -1467,8 +1467,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, LoadSelfExpr, true, true); ExprResult Res = PerformCopyInitialization( InitializedEntity::InitializeResult(PropertyDiagLoc, - getterMethod->getReturnType(), - /*NRVO=*/false), + getterMethod->getReturnType()), PropertyDiagLoc, IvarRefExpr); if (!Res.isInvalid()) { Expr *ResExpr = Res.getAs(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c0cd2bf18a7..22ae5f59d41 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -310,6 +310,8 @@ private: /// Vector of previously encountered target directives SmallVector TargetLocations; SourceLocation AtomicLocation; + /// Vector of declare variant construct traits. + SmallVector ConstructTraits; public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} @@ -513,7 +515,7 @@ public: /// Checks if the specified declaration was used in the inner scan directive. bool isUsedInScanDirective(ValueDecl *D) const { if (const SharingMapTy *Stack = getTopOfStackOrNull()) - return Stack->UsedInScanDirective.count(D) > 0; + return Stack->UsedInScanDirective.contains(D); return false; } @@ -726,6 +728,22 @@ public: OMPC_DEFAULTMAP_MODIFIER_unknown; } + ArrayRef getConstructTraits() { + return ConstructTraits; + } + void handleConstructTrait(ArrayRef Traits, + bool ScopeEntry) { + if (ScopeEntry) + ConstructTraits.append(Traits.begin(), Traits.end()); + else + for (llvm::omp::TraitProperty Trait : llvm::reverse(Traits)) { + llvm::omp::TraitProperty Top = ConstructTraits.pop_back_val(); + assert(Top == Trait && "Something left a trait on the stack!"); + (void)Trait; + (void)Top; + } + } + DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const { return getStackSize() <= Level ? DSA_unspecified : getStackElemAtLevel(Level).DefaultAttr; @@ -1022,7 +1040,7 @@ public: // Return set of mapped classes types bool isClassPreviouslyMapped(QualType QT) const { const SharingMapTy &StackElem = getTopOfStack(); - return StackElem.MappedClassesQualTypes.count(QT) != 0; + return StackElem.MappedClassesQualTypes.contains(QT); } /// Adds global declare target to the parent target region. @@ -1061,7 +1079,7 @@ public: } /// Checks if the decl is implicitly firstprivate in the task-based region. bool isImplicitTaskFirstprivate(Decl *D) const { - return getTopOfStack().ImplicitTaskFirstprivates.count(D) > 0; + return getTopOfStack().ImplicitTaskFirstprivates.contains(D); } /// Marks decl as used in uses_allocators clause as the allocator. @@ -3112,16 +3130,22 @@ static bool checkPreviousOMPAllocateAttribute( static void applyOMPAllocateAttribute(Sema &S, VarDecl *VD, OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, - Expr *Allocator, SourceRange SR) { + Expr *Allocator, Expr *Alignment, SourceRange SR) { if (VD->hasAttr()) return; + if (Alignment && + (Alignment->isTypeDependent() || Alignment->isValueDependent() || + Alignment->isInstantiationDependent() || + Alignment->containsUnexpandedParameterPack())) + // Apply later when we have a usable value. + return; if (Allocator && (Allocator->isTypeDependent() || Allocator->isValueDependent() || Allocator->isInstantiationDependent() || Allocator->containsUnexpandedParameterPack())) return; auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind, - Allocator, SR); + Allocator, Alignment, SR); VD->addAttr(A); if (ASTMutationListener *ML = S.Context.getASTMutationListener()) ML->DeclarationMarkedOpenMPAllocate(VD, A); @@ -3130,7 +3154,8 @@ applyOMPAllocateAttribute(Sema &S, VarDecl *VD, Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( SourceLocation Loc, ArrayRef VarList, ArrayRef Clauses, DeclContext *Owner) { - assert(Clauses.size() <= 1 && "Expected at most one clause."); + assert(Clauses.size() <= 2 && "Expected at most two clauses."); + Expr *Alignment = nullptr; Expr *Allocator = nullptr; if (Clauses.empty()) { // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions. @@ -3141,7 +3166,13 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( !DSAStack->hasRequiresDeclWithClause()) targetDiag(Loc, diag::err_expected_allocator_clause); } else { - Allocator = cast(Clauses.back())->getAllocator(); + for (const OMPClause *C : Clauses) + if (const auto *AC = dyn_cast(C)) + Allocator = AC->getAllocator(); + else if (const auto *AC = dyn_cast(C)) + Alignment = AC->getAlignment(); + else + llvm_unreachable("Unexpected clause on allocate directive"); } OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = getAllocatorKind(*this, DSAStack, Allocator); @@ -3182,7 +3213,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective( } Vars.push_back(RefExpr); - applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, + applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, Alignment, DE->getSourceRange()); } if (Vars.empty()) @@ -3213,7 +3244,7 @@ Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc, void Sema::ActOnOpenMPAssumesDirective(SourceLocation Loc, OpenMPDirectiveKind DKind, - ArrayRef Assumptions, + ArrayRef Assumptions, bool SkippedClauses) { if (!SkippedClauses && Assumptions.empty()) Diag(Loc, diag::err_omp_no_clause_for_directive) @@ -3805,13 +3836,8 @@ public: VisitSubCaptures(S); } - void VisitOMPTileDirective(OMPTileDirective *S) { - // #pragma omp tile does not introduce data sharing. - VisitStmt(S); - } - - void VisitOMPUnrollDirective(OMPUnrollDirective *S) { - // #pragma omp unroll does not introduce data sharing. + void VisitOMPLoopTransformationDirective(OMPLoopTransformationDirective *S) { + // Loop transformation directives do not introduce data sharing VisitStmt(S); } @@ -3871,6 +3897,23 @@ public: }; } // namespace +static void handleDeclareVariantConstructTrait(DSAStackTy *Stack, + OpenMPDirectiveKind DKind, + bool ScopeEntry) { + SmallVector Traits; + if (isOpenMPTargetExecutionDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_target_target); + if (isOpenMPTeamsDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_teams_teams); + if (isOpenMPParallelDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_parallel_parallel); + if (isOpenMPWorksharingDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_for_for); + if (isOpenMPSimdDirective(DKind)) + Traits.emplace_back(llvm::omp::TraitProperty::construct_simd_simd); + Stack->handleConstructTrait(Traits, ScopeEntry); +} + void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { case OMPD_parallel: @@ -3983,6 +4026,9 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_tile: case OMPD_unroll: break; + case OMPD_loop: + // TODO: 'loop' may require additional parameters depending on the binding. + // Treat similar to OMPD_simd/OMPD_for for now. case OMPD_simd: case OMPD_for: case OMPD_for_simd: @@ -4279,12 +4325,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_declare_variant: case OMPD_begin_declare_variant: case OMPD_end_declare_variant: + case OMPD_metadirective: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: default: llvm_unreachable("Unknown OpenMP directive"); } DSAStack->setContext(CurContext); + handleDeclareVariantConstructTrait(DSAStack, DKind, /* ScopeEntry */ true); } int Sema::getNumberOfConstructScopes(unsigned Level) const { @@ -4460,6 +4508,8 @@ static bool checkOrderedOrderSpecified(Sema &S, StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses) { + handleDeclareVariantConstructTrait(DSAStack, DSAStack->getCurrentDirective(), + /* ScopeEntry */ false); if (DSAStack->getCurrentDirective() == OMPD_atomic || DSAStack->getCurrentDirective() == OMPD_critical || DSAStack->getCurrentDirective() == OMPD_section || @@ -4650,6 +4700,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, OpenMPDirectiveKind CurrentRegion, const DeclarationNameInfo &CurrentName, OpenMPDirectiveKind CancelRegion, + OpenMPBindClauseKind BindKind, SourceLocation StartLoc) { if (Stack->getCurScope()) { OpenMPDirectiveKind ParentRegion = Stack->getParentDirective(); @@ -4754,6 +4805,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // A masked region may not be closely nested inside a worksharing, loop, // atomic, task, or taskloop region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPGenericLoopDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion); } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { // OpenMP [2.16, Nesting of Regions] @@ -4787,6 +4839,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // task, taskloop, critical, ordered, atomic, or masked region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPGenericLoopDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion) || ParentRegion == OMPD_master || ParentRegion == OMPD_masked || ParentRegion == OMPD_parallel_master || @@ -4800,6 +4853,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // critical, ordered, atomic, or masked region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPGenericLoopDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion) || ParentRegion == OMPD_master || ParentRegion == OMPD_masked || ParentRegion == OMPD_parallel_master || @@ -4845,14 +4899,28 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, !isOpenMPTargetExecutionDirective(CurrentRegion) && !isOpenMPTargetDataManagementDirective(CurrentRegion) && (ParentRegion == OMPD_teams || ParentRegion == OMPD_target_teams)) { - // OpenMP [2.16, Nesting of Regions] - // distribute, parallel, parallel sections, parallel workshare, and the - // parallel loop and parallel loop SIMD constructs are the only OpenMP - // constructs that can be closely nested in the teams region. + // OpenMP [5.1, 2.22, Nesting of Regions] + // distribute, distribute simd, distribute parallel worksharing-loop, + // distribute parallel worksharing-loop SIMD, loop, parallel regions, + // including any parallel regions arising from combined constructs, + // omp_get_num_teams() regions, and omp_get_team_num() regions are the + // only OpenMP regions that may be strictly nested inside the teams + // region. NestingProhibited = !isOpenMPParallelDirective(CurrentRegion) && - !isOpenMPDistributeDirective(CurrentRegion); + !isOpenMPDistributeDirective(CurrentRegion) && + CurrentRegion != OMPD_loop; Recommend = ShouldBeInParallelRegion; } + if (!NestingProhibited && CurrentRegion == OMPD_loop) { + // OpenMP [5.1, 2.11.7, loop Construct, Restrictions] + // If the bind clause is present on the loop construct and binding is + // teams then the corresponding loop region must be strictly nested inside + // a teams region. + NestingProhibited = BindKind == OMPC_BIND_teams && + ParentRegion != OMPD_teams && + ParentRegion != OMPD_target_teams; + Recommend = ShouldBeInTeamsRegion; + } if (!NestingProhibited && isOpenMPNestingDistributeDirective(CurrentRegion)) { // OpenMP 4.5 [2.17 Nesting of Regions] @@ -4929,14 +4997,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, // directive. // At most one if clause with the particular directive-name-modifier can // appear on the directive. - bool MatchFound = false; - for (auto NM : AllowedNameModifiers) { - if (CurNM == NM) { - MatchFound = true; - break; - } - } - if (!MatchFound) { + if (!llvm::is_contained(AllowedNameModifiers, CurNM)) { S.Diag(IC->getNameModifierLoc(), diag::err_omp_wrong_if_directive_name_modifier) << getOpenMPDirectiveName(CurNM) << getOpenMPDirectiveName(Kind); @@ -5180,8 +5241,10 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD, AllocatorKind, AC->getAllocator())) continue; + // Placeholder until allocate clause supports align modifier. + Expr *Alignment = nullptr; applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(), - E->getSourceRange()); + Alignment, E->getSourceRange()); } } } @@ -5320,8 +5383,9 @@ static CapturedStmt *buildDistanceFunc(Sema &Actions, QualType LogicalTy, if (Rel == BO_LE || Rel == BO_GE) { // Add one to the range if the relational operator is inclusive. - Range = - AssertSuccess(Actions.BuildUnaryOp(nullptr, {}, UO_PreInc, Range)); + Range = AssertSuccess(Actions.BuildBinOp( + nullptr, {}, BO_Add, Range, + Actions.ActOnIntegerConstant(SourceLocation(), 1).get())); } // Divide by the absolute step amount. @@ -5573,6 +5637,19 @@ StmtResult Sema::ActOnOpenMPCanonicalLoop(Stmt *AStmt) { LoopVarFunc, LVRef); } +StmtResult Sema::ActOnOpenMPLoopnest(Stmt *AStmt) { + // Handle a literal loop. + if (isa(AStmt) || isa(AStmt)) + return ActOnOpenMPCanonicalLoop(AStmt); + + // If not a literal loop, it must be the result of a loop transformation. + OMPExecutableDirective *LoopTransform = cast(AStmt); + assert( + isOpenMPLoopTransformationDirective(LoopTransform->getDirectiveKind()) && + "Loop transformation directive expected"); + return LoopTransform; +} + static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S, CXXScopeSpec &MapperIdScopeSpec, const DeclarationNameInfo &MapperId, @@ -5682,7 +5759,7 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, SubExprs.push_back(BaseExpr); continue; } - // Check for the "default" mapper for data memebers. + // Check for the "default" mapper for data members. bool FirstIter = true; for (FieldDecl *FD : RD->fields()) { if (!FD) @@ -5719,10 +5796,14 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { StmtResult Res = StmtError(); + OpenMPBindClauseKind BindKind = OMPC_BIND_unknown; + if (const OMPBindClause *BC = + OMPExecutableDirective::getSingleClause(Clauses)) + BindKind = BC->getBindKind(); // First check CancelRegion which is then used in checkNestingOfRegions. if (checkCancelRegion(*this, Kind, CancelRegion, StartLoc) || checkNestingOfRegions(*this, DSAStack, Kind, DirName, CancelRegion, - StartLoc)) + BindKind, StartLoc)) return StmtError(); llvm::SmallVector ClausesWithImplicit; @@ -5812,6 +5893,31 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( ErrorFound = true; } } + // OpenMP 5.0 [2.19.7] + // If a list item appears in a reduction, lastprivate or linear + // clause on a combined target construct then it is treated as + // if it also appears in a map clause with a map-type of tofrom + if (getLangOpts().OpenMP >= 50 && Kind != OMPD_target && + isOpenMPTargetExecutionDirective(Kind)) { + SmallVector ImplicitExprs; + for (OMPClause *C : Clauses) { + if (auto *RC = dyn_cast(C)) + for (Expr *E : RC->varlists()) + if (!isa(E->IgnoreParenImpCasts())) + ImplicitExprs.emplace_back(E); + } + if (!ImplicitExprs.empty()) { + ArrayRef Exprs = ImplicitExprs; + CXXScopeSpec MapperIdScopeSpec; + DeclarationNameInfo MapperId; + if (OMPClause *Implicit = ActOnOpenMPMapClause( + OMPC_MAP_MODIFIER_unknown, SourceLocation(), MapperIdScopeSpec, + MapperId, OMPC_MAP_tofrom, + /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), + Exprs, OMPVarListLocTy(), /*NoDiagnose=*/true)) + ClausesWithImplicit.emplace_back(Implicit); + } + } for (unsigned I = 0, E = DefaultmapKindNum; I < E; ++I) { int ClauseKindCnt = -1; for (ArrayRef ImplicitMap : ImplicitMaps[I]) { @@ -5940,11 +6046,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPBarrierDirective(StartLoc, EndLoc); break; case OMPD_taskwait: - assert(ClausesWithImplicit.empty() && - "No clauses are allowed for 'omp taskwait' directive"); assert(AStmt == nullptr && "No associated statement allowed for 'omp taskwait' directive"); - Res = ActOnOpenMPTaskwaitDirective(StartLoc, EndLoc); + Res = ActOnOpenMPTaskwaitDirective(ClausesWithImplicit, StartLoc, EndLoc); break; case OMPD_taskgroup: Res = ActOnOpenMPTaskgroupDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -6165,6 +6269,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPDispatchDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); break; + case OMPD_loop: + Res = ActOnOpenMPGenericLoopDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); + break; case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_threadprivate: @@ -6272,6 +6380,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_bind: continue; case OMPC_allocator: case OMPC_flush: @@ -6286,6 +6395,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_when: default: llvm_unreachable("Unexpected clause"); } @@ -6619,7 +6729,7 @@ void Sema::ActOnFinishedFunctionDefinitionInOpenMPAssumeScope(Decl *D) { FD = cast(D); assert(FD && "Expected a function declaration!"); - // If we are intantiating templates we do *not* apply scoped assumptions but + // If we are instantiating templates we do *not* apply scoped assumptions but // only global ones. We apply scoped assumption to the template definition // though. if (!inTemplateInstantiation()) { @@ -6664,9 +6774,11 @@ void Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( for (auto *Candidate : Lookup) { auto *CandidateDecl = Candidate->getUnderlyingDecl(); FunctionDecl *UDecl = nullptr; - if (IsTemplated && isa(CandidateDecl)) - UDecl = cast(CandidateDecl)->getTemplatedDecl(); - else if (!IsTemplated) + if (IsTemplated && isa(CandidateDecl)) { + auto *FTD = cast(CandidateDecl); + if (FTD->getTemplateParameters()->size() == TemplateParamLists.size()) + UDecl = FTD->getTemplatedDecl(); + } else if (!IsTemplated) UDecl = dyn_cast(CandidateDecl); if (!UDecl) continue; @@ -6734,7 +6846,10 @@ void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantFuncRef, DVScope.TI); + Context, VariantFuncRef, DVScope.TI, + /*NothingArgs=*/nullptr, /*NothingArgsSize=*/0, + /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0, + /*AppendArgs=*/nullptr, /*AppendArgsSize=*/0); for (FunctionDecl *BaseFD : Bases) BaseFD->addAttr(OMPDeclareVariantA); } @@ -6765,7 +6880,7 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, << ISATrait; }; TargetOMPContext OMPCtx(Context, std::move(DiagUnknownTrait), - getCurFunctionDecl()); + getCurFunctionDecl(), DSAStack->getConstructTraits()); QualType CalleeFnType = CalleeFnDecl->getType(); @@ -6848,6 +6963,7 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, Optional> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, OMPTraitInfo &TI, + unsigned NumAppendArgs, SourceRange SR) { if (!DG || DG.get().isNull()) return None; @@ -6935,6 +7051,39 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) return None; + QualType AdjustedFnType = FD->getType(); + if (NumAppendArgs) { + if (isa(FD->getType())) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required) + << SR; + return None; + } + // Adjust the function type to account for an extra omp_interop_t for each + // specified in the append_args clause. + const TypeDecl *TD = nullptr; + LookupResult Result(*this, &Context.Idents.get("omp_interop_t"), + SR.getBegin(), Sema::LookupOrdinaryName); + if (LookupName(Result, getCurScope())) { + NamedDecl *ND = Result.getFoundDecl(); + TD = dyn_cast_or_null(ND); + } + if (!TD) { + Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR; + return None; + } + QualType InteropType = QualType(TD->getTypeForDecl(), 0); + auto *PTy = cast(FD->getType()); + if (PTy->isVariadic()) { + Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR; + return None; + } + llvm::SmallVector Params; + Params.append(PTy->param_type_begin(), PTy->param_type_end()); + Params.insert(Params.end(), NumAppendArgs, InteropType); + AdjustedFnType = Context.getFunctionType(PTy->getReturnType(), Params, + PTy->getExtProtoInfo()); + } + // Convert VariantRef expression to the type of the original function to // resolve possible conflicts. ExprResult VariantRefCast = VariantRef; @@ -6944,7 +7093,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (Method && !Method->isStatic()) { const Type *ClassType = Context.getTypeDeclType(Method->getParent()).getTypePtr(); - FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType); + FnPtrType = Context.getMemberPointerType(AdjustedFnType, ClassType); ExprResult ER; { // Build adrr_of unary op to correctly handle type checks for member @@ -6960,7 +7109,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, } VariantRef = ER.get(); } else { - FnPtrType = Context.getPointerType(FD->getType()); + FnPtrType = Context.getPointerType(AdjustedFnType); } QualType VarianPtrType = Context.getPointerType(VariantRef->getType()); if (VarianPtrType.getUnqualifiedType() != FnPtrType.getUnqualifiedType()) { @@ -6975,7 +7124,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, diag::err_omp_declare_variant_incompat_types) << VariantRef->getType() << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType()) - << VariantRef->getSourceRange(); + << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange(); return None; } VariantRefCast = PerformImplicitConversion( @@ -7017,11 +7166,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, // Check if function types are compatible in C. if (!LangOpts.CPlusPlus) { QualType NewType = - Context.mergeFunctionTypes(FD->getType(), NewFD->getType()); + Context.mergeFunctionTypes(AdjustedFnType, NewFD->getType()); if (NewType.isNull()) { Diag(VariantRef->getExprLoc(), diag::err_omp_declare_variant_incompat_types) - << NewFD->getType() << FD->getType() << VariantRef->getSourceRange(); + << NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0) + << VariantRef->getSourceRange(); return None; } if (NewType->isFunctionProtoType()) { @@ -7107,12 +7257,74 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return std::make_pair(FD, cast(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, - Expr *VariantRef, - OMPTraitInfo &TI, - SourceRange SR) { - auto *NewAttr = - OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); +void Sema::ActOnOpenMPDeclareVariantDirective( + FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, + ArrayRef AdjustArgsNothing, + ArrayRef AdjustArgsNeedDevicePtr, + ArrayRef AppendArgs, + SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc, + SourceRange SR) { + + // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions] + // An adjust_args clause or append_args clause can only be specified if the + // dispatch selector of the construct selector set appears in the match + // clause. + + SmallVector AllAdjustArgs; + llvm::append_range(AllAdjustArgs, AdjustArgsNothing); + llvm::append_range(AllAdjustArgs, AdjustArgsNeedDevicePtr); + + if (!AllAdjustArgs.empty() || !AppendArgs.empty()) { + VariantMatchInfo VMI; + TI.getAsVariantMatchInfo(Context, VMI); + if (!llvm::is_contained( + VMI.ConstructTraits, + llvm::omp::TraitProperty::construct_dispatch_dispatch)) { + if (!AllAdjustArgs.empty()) + Diag(AdjustArgsLoc, diag::err_omp_clause_requires_dispatch_construct) + << getOpenMPClauseName(OMPC_adjust_args); + if (!AppendArgs.empty()) + Diag(AppendArgsLoc, diag::err_omp_clause_requires_dispatch_construct) + << getOpenMPClauseName(OMPC_append_args); + return; + } + } + + // OpenMP 5.1 [2.3.5, declare variant directive, Restrictions] + // Each argument can only appear in a single adjust_args clause for each + // declare variant directive. + llvm::SmallPtrSet AdjustVars; + + for (Expr *E : AllAdjustArgs) { + E = E->IgnoreParenImpCasts(); + if (const auto *DRE = dyn_cast(E)) { + if (const auto *PVD = dyn_cast(DRE->getDecl())) { + const VarDecl *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // It's a parameter of the function, check duplicates. + if (!AdjustVars.insert(CanonPVD).second) { + Diag(DRE->getLocation(), diag::err_omp_adjust_arg_multiple_clauses) + << PVD; + return; + } + continue; + } + } + } + // Anything that is not a function parameter is an error. + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) << FD << 0; + return; + } + + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, &TI, const_cast(AdjustArgsNothing.data()), + AdjustArgsNothing.size(), + const_cast(AdjustArgsNeedDevicePtr.data()), + AdjustArgsNeedDevicePtr.size(), + const_cast(AppendArgs.data()), + AppendArgs.size(), SR); FD->addAttr(NewAttr); } @@ -7342,7 +7554,7 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl, // State consistency checking to ensure correct usage. assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); - if (!NewLCDecl || !NewLB) + if (!NewLCDecl || !NewLB || NewLB->containsErrors()) return true; LCDecl = getCanonicalDecl(NewLCDecl); LCRef = NewLCRefExpr; @@ -7365,7 +7577,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, // State consistency checking to ensure correct usage. assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); - if (!NewUB) + if (!NewUB || NewUB->containsErrors()) return true; UB = NewUB; if (LessOp) @@ -7380,7 +7592,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); - if (!NewStep) + if (!NewStep || NewStep->containsErrors()) return true; if (!NewStep->isValueDependent()) { // Check that the step is integer expression. @@ -8648,6 +8860,7 @@ static bool checkOpenMPIterationSpace( ResultIterSpaces[CurrentNestedLoopCount].NumIterations = ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces, (isOpenMPWorksharingDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || isOpenMPLoopTransformationDirective(DKind)), @@ -8971,15 +9184,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } return false; }, - [&SemaRef, &Captures](OMPLoopBasedDirective *Transform) { - Stmt *DependentPreInits; - if (auto *Dir = dyn_cast(Transform)) { - DependentPreInits = Dir->getPreInits(); - } else if (auto *Dir = dyn_cast(Transform)) { - DependentPreInits = Dir->getPreInits(); - } else { - llvm_unreachable("Unexpected loop transformation"); - } + [&SemaRef, &Captures](OMPLoopTransformationDirective *Transform) { + Stmt *DependentPreInits = Transform->getPreInits(); if (!DependentPreInits) return; for (Decl *C : cast(DependentPreInits)->getDeclGroup()) { @@ -9138,6 +9344,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, ExprResult LB, UB, IL, ST, EUB, CombLB, CombUB, PrevLB, PrevUB, CombEUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPLoopTransformationDirective(DKind)) { // Lower bound variable, initialized with zero. VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); @@ -9237,6 +9444,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); Expr *RHS = (isOpenMPWorksharingDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || isOpenMPLoopTransformationDirective(DKind)) @@ -9248,6 +9456,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (isOpenMPLoopBoundSharingDirective(DKind)) { Expr *CombRHS = (isOpenMPWorksharingDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) ? CombLB.get() @@ -9279,6 +9488,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } ExprResult Cond = (isOpenMPWorksharingDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || isOpenMPLoopTransformationDirective(DKind)) ? SemaRef.BuildBinOp(CurScope, CondLoc, @@ -9328,6 +9538,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // base variables for the update ExprResult NextLB, NextUB, CombNextLB, CombNextUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || + isOpenMPGenericLoopDirective(DKind) || isOpenMPDistributeDirective(DKind) || isOpenMPLoopTransformationDirective(DKind)) { // LB + ST @@ -9882,6 +10093,57 @@ StmtResult Sema::ActOnOpenMPDispatchDirective(ArrayRef Clauses, TargetCallLoc); } +StmtResult Sema::ActOnOpenMPGenericLoopDirective( + ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + // OpenMP 5.1 [2.11.7, loop construct] + // A list item may not appear in a lastprivate clause unless it is the + // loop iteration variable of a loop that is associated with the construct. + for (OMPClause *C : Clauses) { + if (auto *LPC = dyn_cast(C)) { + for (Expr *RefExpr : LPC->varlists()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (ValueDecl *D = Res.first) { + auto &&Info = DSAStack->isLoopControlVariable(D); + if (!Info.first) { + Diag(ELoc, diag::err_omp_lastprivate_loop_var_non_loop_iteration); + return StmtError(); + } + } + } + } + } + + auto *CS = cast(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse', it will define the nested loops number. + unsigned NestedLoopCount = checkOpenMPLoop( + OMPD_loop, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses), + AStmt, *this, *DSAStack, VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp loop exprs were not built"); + + setFunctionHasBranchProtectedScope(); + return OMPGenericLoopDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -10203,9 +10465,10 @@ StmtResult Sema::ActOnOpenMPBarrierDirective(SourceLocation StartLoc, return OMPBarrierDirective::Create(Context, StartLoc, EndLoc); } -StmtResult Sema::ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, +StmtResult Sema::ActOnOpenMPTaskwaitDirective(ArrayRef Clauses, + SourceLocation StartLoc, SourceLocation EndLoc) { - return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc); + return OMPTaskwaitDirective::Create(Context, StartLoc, EndLoc, Clauses); } StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef Clauses, @@ -12852,10 +13115,12 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef Clauses, Body, OriginalInits)) return StmtError(); + unsigned NumGeneratedLoops = PartialClause ? 1 : 0; + // Delay unrolling to when template is completely instantiated. if (CurContext->isDependentContext()) return OMPUnrollDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, - nullptr, nullptr); + NumGeneratedLoops, nullptr, nullptr); OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers.front(); @@ -12874,9 +13139,9 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef Clauses, // The generated loop may only be passed to other loop-associated directive // when a partial clause is specified. Without the requirement it is // sufficient to generate loop unroll metadata at code-generation. - if (!PartialClause) + if (NumGeneratedLoops == 0) return OMPUnrollDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, - nullptr, nullptr); + NumGeneratedLoops, nullptr, nullptr); // Otherwise, we need to provide a de-sugared/transformed AST that can be // associated with another loop directive. @@ -13097,7 +13362,8 @@ StmtResult Sema::ActOnOpenMPUnrollDirective(ArrayRef Clauses, LoopHelper.Init->getBeginLoc(), LoopHelper.Inc->getEndLoc()); return OMPUnrollDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, - OuterFor, buildPreInits(Context, PreInits)); + NumGeneratedLoops, OuterFor, + buildPreInits(Context, PreInits)); } OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, @@ -13163,6 +13429,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_partial: Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_align: + Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc); + break; case OMPC_device: case OMPC_if: case OMPC_default: @@ -13223,6 +13492,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_bind: default: llvm_unreachable("Clause is not allowed."); } @@ -13363,6 +13634,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_teams: case OMPD_tile: case OMPD_unroll: @@ -13379,6 +13651,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_teams_distribute: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with if-clause"); case OMPD_unknown: default: @@ -13441,6 +13714,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_teams: case OMPD_simd: case OMPD_tile: @@ -13461,6 +13735,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_teams_distribute: case OMPD_teams_distribute_simd: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); case OMPD_unknown: default: @@ -13524,6 +13799,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13541,6 +13817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_distribute_simd: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: default: @@ -13604,6 +13881,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13621,6 +13899,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_distribute_simd: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); case OMPD_unknown: default: @@ -13685,6 +13964,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13701,6 +13981,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_distribute_simd: case OMPD_target_teams: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: default: @@ -13765,6 +14046,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13781,6 +14063,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_target_teams: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with dist_schedule clause"); case OMPD_unknown: default: @@ -13846,6 +14129,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13863,6 +14147,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_distribute_simd: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with device-clause"); case OMPD_unknown: default: @@ -13928,6 +14213,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: + case OMPD_loop: case OMPD_simd: case OMPD_tile: case OMPD_unroll: @@ -13945,6 +14231,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_atomic: case OMPD_distribute_simd: case OMPD_requires: + case OMPD_metadirective: llvm_unreachable("Unexpected OpenMP directive with grainsize-clause"); case OMPD_unknown: default: @@ -13964,6 +14251,15 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_filter: // Do not capture filter-clause expressions. break; + case OMPC_when: + if (DKind == OMPD_metadirective) { + CaptureRegion = OMPD_metadirective; + } else if (DKind == OMPD_unknown) { + llvm_unreachable("Unknown OpenMP directive"); + } else { + llvm_unreachable("Unexpected OpenMP directive with when clause"); + } + break; case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: @@ -14028,6 +14324,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_bind: default: llvm_unreachable("Unexpected OpenMP clause."); } @@ -14248,7 +14545,7 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, << E->getSourceRange(); return ExprError(); } - if (CKind == OMPC_aligned && !Result.isPowerOf2()) { + if ((CKind == OMPC_aligned || CKind == OMPC_align) && !Result.isPowerOf2()) { Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two) << E->getSourceRange(); return ExprError(); @@ -14419,6 +14716,10 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( Res = ActOnOpenMPUpdateClause(static_cast(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; + case OMPC_bind: + Res = ActOnOpenMPBindClause(static_cast(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -14491,6 +14792,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -14668,6 +14970,17 @@ OMPClause *Sema::ActOnOpenMPPartialClause(Expr *FactorExpr, FactorExpr); } +OMPClause *Sema::ActOnOpenMPAlignClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + ExprResult AlignVal; + AlignVal = VerifyPositiveIntegerConstantInClause(A, OMPC_align); + if (AlignVal.isInvalid()) + return nullptr; + return OMPAlignClause::Create(Context, AlignVal.get(), StartLoc, LParenLoc, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -14783,6 +15096,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: + case OMPC_bind: default: llvm_unreachable("Clause is not allowed."); } @@ -15032,6 +15347,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -15574,6 +15890,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_nocontext: case OMPC_detach: case OMPC_uses_allocators: + case OMPC_when: + case OMPC_bind: default: llvm_unreachable("Clause is not allowed."); } @@ -15736,29 +16054,6 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, PrivateCopies); } -namespace { -class DiagsUninitializedSeveretyRAII { -private: - DiagnosticsEngine &Diags; - SourceLocation SavedLoc; - bool IsIgnored = false; - -public: - DiagsUninitializedSeveretyRAII(DiagnosticsEngine &Diags, SourceLocation Loc, - bool IsIgnored) - : Diags(Diags), SavedLoc(Loc), IsIgnored(IsIgnored) { - if (!IsIgnored) { - Diags.setSeverity(/*Diag*/ diag::warn_uninit_self_reference_in_init, - /*Map*/ diag::Severity::Ignored, Loc); - } - } - ~DiagsUninitializedSeveretyRAII() { - if (!IsIgnored) - Diags.popMappings(SavedLoc); - } -}; -} - OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -17107,14 +17402,13 @@ static bool actOnOMPReductionKindClause( Type = ComplexTy->getElementType(); if (Type->isRealFloatingType()) { llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue( - Context.getFloatTypeSemantics(Type), - Context.getTypeSize(Type)); + Context.getFloatTypeSemantics(Type)); Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } else if (Type->isScalarType()) { uint64_t Size = Context.getTypeSize(Type); QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); - llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); + llvm::APInt InitValue = llvm::APInt::getAllOnes(Size); Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); } if (Init && OrigType->isAnyComplexType()) { @@ -18149,6 +18443,11 @@ Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); return nullptr; } + if (DSAStack->getCurrentDirective() == OMPD_taskwait && + DepKind == OMPC_DEPEND_mutexinoutset) { + Diag(DepLoc, diag::err_omp_taskwait_depend_mutexinoutset_not_allowed); + return nullptr; + } if ((DSAStack->getCurrentDirective() != OMPD_ordered || DSAStack->getCurrentDirective() == OMPD_depobj) && (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || @@ -18322,7 +18621,7 @@ Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, Expr::EvalResult Result; if (Length && !Length->isValueDependent() && Length->EvaluateAsInt(Result, Context) && - Result.Val.getInt().isNullValue()) { + Result.Val.getInt().isZero()) { Diag(ELoc, diag::err_omp_depend_zero_length_array_section_not_allowed) << SimpleExpr->getSourceRange(); @@ -18443,11 +18742,8 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, DSAStackTy *Stack, QualType QTy, bool FullCheck = true) { - NamedDecl *ND; - if (QTy->isIncompleteType(&ND)) { - SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; + if (SemaRef.RequireCompleteType(SL, QTy, diag::err_incomplete_type)) return false; - } if (FullCheck && !SemaRef.CurContext->isDependentContext() && !QTy.isTriviallyCopyableType(SemaRef.Context)) SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR; @@ -18718,7 +19014,7 @@ public: Expr::EvalResult Result; if (!AE->getIdx()->isValueDependent() && AE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext()) && - !Result.Val.getInt().isNullValue()) { + !Result.Val.getInt().isZero()) { SemaRef.Diag(AE->getIdx()->getExprLoc(), diag::err_omp_invalid_map_this_expr); SemaRef.Diag(AE->getIdx()->getExprLoc(), @@ -18735,7 +19031,10 @@ public: } bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) { - assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); + // After OMP 5.0 Array section in reduction clause will be implicitly + // mapped + assert(!(SemaRef.getLangOpts().OpenMP < 50 && NoDiagnose) && + "Array sections cannot be implicitly mapped."); Expr *E = OASE->getBase()->IgnoreParenImpCasts(); QualType CurType = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); @@ -18778,6 +19077,8 @@ public: } else if (AllowUnitySizeArraySection && NotUnity) { // A unity or whole array section is not allowed and that is not // compatible with the properties of the current array section. + if (NoDiagnose) + return false; SemaRef.Diag( ELoc, diag::err_array_section_does_not_specify_contiguous_storage) << OASE->getSourceRange(); @@ -18792,7 +19093,7 @@ public: Expr::EvalResult ResultL; if (!OASE->getLength()->isValueDependent() && OASE->getLength()->EvaluateAsInt(ResultR, SemaRef.getASTContext()) && - !ResultR.Val.getInt().isOneValue()) { + !ResultR.Val.getInt().isOne()) { SemaRef.Diag(OASE->getLength()->getExprLoc(), diag::err_omp_invalid_map_this_expr); SemaRef.Diag(OASE->getLength()->getExprLoc(), @@ -18801,7 +19102,7 @@ public: if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() && OASE->getLowerBound()->EvaluateAsInt(ResultL, SemaRef.getASTContext()) && - !ResultL.Val.getInt().isNullValue()) { + !ResultL.Val.getInt().isZero()) { SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), diag::err_omp_invalid_map_this_expr); SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), @@ -19321,7 +19622,8 @@ static void checkMappableExpressionList( CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId, ArrayRef UnresolvedMappers, OpenMPMapClauseKind MapType = OMPC_MAP_unknown, - bool IsMapTypeImplicit = false) { + ArrayRef Modifiers = None, + bool IsMapTypeImplicit = false, bool NoDiagnose = false) { // We only expect mappable expressions in 'to', 'from', and 'map' clauses. assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && "Unexpected clause kind with mappable expressions!"); @@ -19342,6 +19644,9 @@ static void checkMappableExpressionList( bool UpdateUMIt = false; Expr *UnresolvedMapper = nullptr; + bool HasHoldModifier = + llvm::is_contained(Modifiers, OMPC_MAP_MODIFIER_ompx_hold); + // Keep track of the mappable components and base declarations in this clause. // Each entry in the list is going to have a list of components associated. We // record each set of the components so that we can build the clause later on. @@ -19400,9 +19705,9 @@ static void checkMappableExpressionList( // Obtain the array or member expression bases if required. Also, fill the // components array with all the components identified in the process. - const Expr *BE = checkMapClauseExpressionBase( - SemaRef, SimpleExpr, CurComponents, CKind, DSAS->getCurrentDirective(), - /*NoDiagnose=*/false); + const Expr *BE = + checkMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind, + DSAS->getCurrentDirective(), NoDiagnose); if (!BE) continue; @@ -19448,6 +19753,8 @@ static void checkMappableExpressionList( // OpenMP 4.5 [2.10.5, target update Construct] // threadprivate variables cannot appear in a from clause. if (VD && DSAS->isThreadPrivate(VD)) { + if (NoDiagnose) + continue; DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false); SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause) << getOpenMPClauseName(CKind); @@ -19508,7 +19815,7 @@ static void checkMappableExpressionList( // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] // A list item must have a mappable type. if (!checkTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef, - DSAS, Type)) + DSAS, Type, /*FullCheck=*/true)) continue; if (CKind == OMPC_map) { @@ -19540,6 +19847,21 @@ static void checkMappableExpressionList( continue; } + // The 'ompx_hold' modifier is specifically intended to be used on a + // 'target' or 'target data' directive to prevent data from being unmapped + // during the associated statement. It is not permitted on a 'target + // enter data' or 'target exit data' directive, which have no associated + // statement. + if ((DKind == OMPD_target_enter_data || DKind == OMPD_target_exit_data) && + HasHoldModifier) { + SemaRef.Diag(StartLoc, + diag::err_omp_invalid_map_type_modifier_for_directive) + << getOpenMPSimpleClauseTypeName(OMPC_map, + OMPC_MAP_MODIFIER_ompx_hold) + << getOpenMPDirectiveName(DKind); + continue; + } + // target, target data // OpenMP 5.0 [2.12.2, Restrictions, p. 163] // OpenMP 5.0 [2.12.5, Restrictions, p. 174] @@ -19611,17 +19933,19 @@ OMPClause *Sema::ActOnOpenMPMapClause( CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, - const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers) { + const OMPVarListLocTy &Locs, bool NoDiagnose, + ArrayRef UnresolvedMappers) { OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, - OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; + OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, + OMPC_MAP_MODIFIER_unknown}; SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. unsigned Count = 0; for (unsigned I = 0, E = MapTypeModifiers.size(); I < E; ++I) { if (MapTypeModifiers[I] != OMPC_MAP_MODIFIER_unknown && - llvm::find(Modifiers, MapTypeModifiers[I]) != std::end(Modifiers)) { + llvm::is_contained(Modifiers, MapTypeModifiers[I])) { Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier); continue; } @@ -19635,7 +19959,8 @@ OMPClause *Sema::ActOnOpenMPMapClause( MappableVarListInfo MVLI(VarList); checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, Locs.StartLoc, MapperIdScopeSpec, MapperId, UnresolvedMappers, - MapType, IsMapTypeImplicit); + MapType, Modifiers, IsMapTypeImplicit, + NoDiagnose); // We need to produce a map clause even if we don't have variables so that // other diagnostics related with non-existing map clauses are accurate. @@ -20609,7 +20934,7 @@ OMPClause *Sema::ActOnOpenMPToClause( unsigned Count = 0; for (unsigned I = 0, E = MotionModifiers.size(); I < E; ++I) { if (MotionModifiers[I] != OMPC_MOTION_MODIFIER_unknown && - llvm::find(Modifiers, MotionModifiers[I]) != std::end(Modifiers)) { + llvm::is_contained(Modifiers, MotionModifiers[I])) { Diag(MotionModifiersLoc[I], diag::err_omp_duplicate_motion_modifier); continue; } @@ -20646,7 +20971,7 @@ OMPClause *Sema::ActOnOpenMPFromClause( unsigned Count = 0; for (unsigned I = 0, E = MotionModifiers.size(); I < E; ++I) { if (MotionModifiers[I] != OMPC_MOTION_MODIFIER_unknown && - llvm::find(Modifiers, MotionModifiers[I]) != std::end(Modifiers)) { + llvm::is_contained(Modifiers, MotionModifiers[I])) { Diag(MotionModifiersLoc[I], diag::err_omp_duplicate_motion_modifier); continue; } @@ -21253,3 +21578,20 @@ OMPClause *Sema::ActOnOpenMPAffinityClause( return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Modifier, Vars); } + +OMPClause *Sema::ActOnOpenMPBindClause(OpenMPBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_BIND_unknown) { + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_bind, /*First=*/0, + /*Last=*/unsigned(OMPC_BIND_unknown)) + << getOpenMPClauseName(OMPC_bind); + return nullptr; + } + + return OMPBindClause::Create(Context, Kind, KindLoc, StartLoc, LParenLoc, + EndLoc); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0758fbb8410..42b1340f9a6 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -541,8 +541,8 @@ void UserDefinedConversionSequence::dump() const { /// error. Useful for debugging overloading issues. void ImplicitConversionSequence::dump() const { raw_ostream &OS = llvm::errs(); - if (isStdInitializerListElement()) - OS << "Worst std::initializer_list element conversion: "; + if (hasInitializerListContainerType()) + OS << "Worst list element conversion: "; switch (ConversionKind) { case StandardConversion: OS << "Standard conversion: "; @@ -1869,24 +1869,25 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) { - // FIXME: disable conversions between long double and __float128 if - // their representation is different until there is back end support + // FIXME: disable conversions between long double, __ibm128 and __float128 + // if their representation is different until there is back end support // We of course allow this conversion if long double is really double. // Conversions between bfloat and other floats are not permitted. if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty) return false; - if (&S.Context.getFloatTypeSemantics(FromType) != - &S.Context.getFloatTypeSemantics(ToType)) { - bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty && - ToType == S.Context.LongDoubleTy) || - (FromType == S.Context.LongDoubleTy && - ToType == S.Context.Float128Ty)); - if (Float128AndLongDouble && - (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) == - &llvm::APFloat::PPCDoubleDouble())) - return false; - } + + // Conversions between IEEE-quad and IBM-extended semantics are not + // permitted. + const llvm::fltSemantics &FromSem = + S.Context.getFloatTypeSemantics(FromType); + const llvm::fltSemantics &ToSem = S.Context.getFloatTypeSemantics(ToType); + if ((&FromSem == &llvm::APFloat::PPCDoubleDouble() && + &ToSem == &llvm::APFloat::IEEEquad()) || + (&FromSem == &llvm::APFloat::IEEEquad() && + &ToSem == &llvm::APFloat::PPCDoubleDouble())) + return false; + // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); @@ -2237,7 +2238,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { (FromBuiltin->getKind() == BuiltinType::Float || FromBuiltin->getKind() == BuiltinType::Double) && (ToBuiltin->getKind() == BuiltinType::LongDouble || - ToBuiltin->getKind() == BuiltinType::Float128)) + ToBuiltin->getKind() == BuiltinType::Float128 || + ToBuiltin->getKind() == BuiltinType::Ibm128)) return true; // Half can be promoted to float. @@ -3244,6 +3246,19 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, !PreviousToQualsIncludeConst) return false; + // The following wording is from C++20, where the result of the conversion + // is T3, not T2. + // -- if [...] P1,i [...] is "array of unknown bound of", P3,i is + // "array of unknown bound of" + if (FromType->isIncompleteArrayType() && !ToType->isIncompleteArrayType()) + return false; + + // -- if the resulting P3,i is different from P1,i [...], then const is + // added to every cv 3_k for 0 < k < i. + if (!CStyle && FromType->isConstantArrayType() && + ToType->isIncompleteArrayType() && !PreviousToQualsIncludeConst) + return false; + // Keep track of whether all prior cv-qualifiers in the "to" type // include const. PreviousToQualsIncludeConst = @@ -3775,7 +3790,9 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc, if (S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings && hasDeprecatedStringLiteralToCharPtrConversion(ICS1) != - hasDeprecatedStringLiteralToCharPtrConversion(ICS2)) + hasDeprecatedStringLiteralToCharPtrConversion(ICS2) && + // Ill-formedness must not differ + ICS1.isBad() == ICS2.isBad()) return hasDeprecatedStringLiteralToCharPtrConversion(ICS1) ? ImplicitConversionSequence::Worse : ImplicitConversionSequence::Better; @@ -3801,16 +3818,45 @@ CompareImplicitConversionSequences(Sema &S, SourceLocation Loc, // list-initialization sequence L2 if: // - L1 converts to std::initializer_list for some X and L2 does not, or, // if not that, - // - L1 converts to type "array of N1 T", L2 converts to type "array of N2 T", - // and N1 is smaller than N2., + // — L1 and L2 convert to arrays of the same element type, and either the + // number of elements n_1 initialized by L1 is less than the number of + // elements n_2 initialized by L2, or (C++20) n_1 = n_2 and L2 converts to + // an array of unknown bound and L1 does not, // even if one of the other rules in this paragraph would otherwise apply. if (!ICS1.isBad()) { - if (ICS1.isStdInitializerListElement() && - !ICS2.isStdInitializerListElement()) - return ImplicitConversionSequence::Better; - if (!ICS1.isStdInitializerListElement() && - ICS2.isStdInitializerListElement()) - return ImplicitConversionSequence::Worse; + bool StdInit1 = false, StdInit2 = false; + if (ICS1.hasInitializerListContainerType()) + StdInit1 = S.isStdInitializerList(ICS1.getInitializerListContainerType(), + nullptr); + if (ICS2.hasInitializerListContainerType()) + StdInit2 = S.isStdInitializerList(ICS2.getInitializerListContainerType(), + nullptr); + if (StdInit1 != StdInit2) + return StdInit1 ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + + if (ICS1.hasInitializerListContainerType() && + ICS2.hasInitializerListContainerType()) + if (auto *CAT1 = S.Context.getAsConstantArrayType( + ICS1.getInitializerListContainerType())) + if (auto *CAT2 = S.Context.getAsConstantArrayType( + ICS2.getInitializerListContainerType())) { + if (S.Context.hasSameUnqualifiedType(CAT1->getElementType(), + CAT2->getElementType())) { + // Both to arrays of the same element type + if (CAT1->getSize() != CAT2->getSize()) + // Different sized, the smaller wins + return CAT1->getSize().ult(CAT2->getSize()) + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + if (ICS1.isInitializerListOfIncompleteArray() != + ICS2.isInitializerListOfIncompleteArray()) + // One is incomplete, it loses + return ICS2.isInitializerListOfIncompleteArray() + ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + } + } } if (ICS1.isStandard()) @@ -4176,12 +4222,15 @@ static ImplicitConversionSequence::CompareKind CompareQualificationConversions(Sema &S, const StandardConversionSequence& SCS1, const StandardConversionSequence& SCS2) { - // C++ 13.3.3.2p3: + // C++ [over.ics.rank]p3: // -- S1 and S2 differ only in their qualification conversion and - // yield similar types T1 and T2 (C++ 4.4), respectively, and the - // cv-qualification signature of type T1 is a proper subset of - // the cv-qualification signature of type T2, and S1 is not the + // yield similar types T1 and T2 (C++ 4.4), respectively, [...] + // [C++98] + // [...] and the cv-qualification signature of type T1 is a proper subset + // of the cv-qualification signature of type T2, and S1 is not the // deprecated string literal array-to-pointer conversion (4.2). + // [C++2a] + // [...] where T1 can be converted to T2 by a qualification conversion. if (SCS1.First != SCS2.First || SCS1.Second != SCS2.Second || SCS1.Third != SCS2.Third || SCS1.Third != ICK_Qualification) return ImplicitConversionSequence::Indistinguishable; @@ -4202,79 +4251,35 @@ CompareQualificationConversions(Sema &S, if (UnqualT1 == UnqualT2) return ImplicitConversionSequence::Indistinguishable; - ImplicitConversionSequence::CompareKind Result - = ImplicitConversionSequence::Indistinguishable; + // Don't ever prefer a standard conversion sequence that uses the deprecated + // string literal array to pointer conversion. + bool CanPick1 = !SCS1.DeprecatedStringLiteralToCharPtr; + bool CanPick2 = !SCS2.DeprecatedStringLiteralToCharPtr; // Objective-C++ ARC: // Prefer qualification conversions not involving a change in lifetime - // to qualification conversions that do not change lifetime. - if (SCS1.QualificationIncludesObjCLifetime != - SCS2.QualificationIncludesObjCLifetime) { - Result = SCS1.QualificationIncludesObjCLifetime - ? ImplicitConversionSequence::Worse - : ImplicitConversionSequence::Better; - } + // to qualification conversions that do change lifetime. + if (SCS1.QualificationIncludesObjCLifetime && + !SCS2.QualificationIncludesObjCLifetime) + CanPick1 = false; + if (SCS2.QualificationIncludesObjCLifetime && + !SCS1.QualificationIncludesObjCLifetime) + CanPick2 = false; - while (S.Context.UnwrapSimilarTypes(T1, T2)) { - // Within each iteration of the loop, we check the qualifiers to - // determine if this still looks like a qualification - // conversion. Then, if all is well, we unwrap one more level of - // pointers or pointers-to-members and do it all again - // until there are no more pointers or pointers-to-members left - // to unwrap. This essentially mimics what - // IsQualificationConversion does, but here we're checking for a - // strict subset of qualifiers. - if (T1.getQualifiers().withoutObjCLifetime() == - T2.getQualifiers().withoutObjCLifetime()) - // The qualifiers are the same, so this doesn't tell us anything - // about how the sequences rank. - // ObjC ownership quals are omitted above as they interfere with - // the ARC overload rule. - ; - else if (T2.isMoreQualifiedThan(T1)) { - // T1 has fewer qualifiers, so it could be the better sequence. - if (Result == ImplicitConversionSequence::Worse) - // Neither has qualifiers that are a subset of the other's - // qualifiers. - return ImplicitConversionSequence::Indistinguishable; + bool ObjCLifetimeConversion; + if (CanPick1 && + !S.IsQualificationConversion(T1, T2, false, ObjCLifetimeConversion)) + CanPick1 = false; + // FIXME: In Objective-C ARC, we can have qualification conversions in both + // directions, so we can't short-cut this second check in general. + if (CanPick2 && + !S.IsQualificationConversion(T2, T1, false, ObjCLifetimeConversion)) + CanPick2 = false; - Result = ImplicitConversionSequence::Better; - } else if (T1.isMoreQualifiedThan(T2)) { - // T2 has fewer qualifiers, so it could be the better sequence. - if (Result == ImplicitConversionSequence::Better) - // Neither has qualifiers that are a subset of the other's - // qualifiers. - return ImplicitConversionSequence::Indistinguishable; - - Result = ImplicitConversionSequence::Worse; - } else { - // Qualifiers are disjoint. - return ImplicitConversionSequence::Indistinguishable; - } - - // If the types after this point are equivalent, we're done. - if (S.Context.hasSameUnqualifiedType(T1, T2)) - break; - } - - // Check that the winning standard conversion sequence isn't using - // the deprecated string literal array to pointer conversion. - switch (Result) { - case ImplicitConversionSequence::Better: - if (SCS1.DeprecatedStringLiteralToCharPtr) - Result = ImplicitConversionSequence::Indistinguishable; - break; - - case ImplicitConversionSequence::Indistinguishable: - break; - - case ImplicitConversionSequence::Worse: - if (SCS2.DeprecatedStringLiteralToCharPtr) - Result = ImplicitConversionSequence::Indistinguishable; - break; - } - - return Result; + if (CanPick1 != CanPick2) + return CanPick1 ? ImplicitConversionSequence::Better + : ImplicitConversionSequence::Worse; + return ImplicitConversionSequence::Indistinguishable; } /// CompareDerivedToBaseConversions - Compares two standard conversion @@ -5009,9 +5014,15 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, ImplicitConversionSequence Result; Result.setBad(BadConversionSequence::no_conversion, From, ToType); - // We need a complete type for what follows. Incomplete types can never be - // initialized from init lists. - if (!S.isCompleteType(From->getBeginLoc(), ToType)) + // We need a complete type for what follows. With one C++20 exception, + // incomplete types can never be initialized from init lists. + QualType InitTy = ToType; + const ArrayType *AT = S.Context.getAsArrayType(ToType); + if (AT && S.getLangOpts().CPlusPlus20) + if (const auto *IAT = dyn_cast(AT)) + // C++20 allows list initialization of an incomplete array type. + InitTy = IAT->getElementType(); + if (!S.isCompleteType(From->getBeginLoc(), InitTy)) return Result; // Per DR1467: @@ -5035,18 +5046,16 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, AllowObjCWritebackConversion); } - if (const auto *AT = S.Context.getAsArrayType(ToType)) { - if (S.IsStringInit(From->getInit(0), AT)) { - InitializedEntity Entity = + if (AT && S.IsStringInit(From->getInit(0), AT)) { + InitializedEntity Entity = InitializedEntity::InitializeParameter(S.Context, ToType, /*Consumed=*/false); - if (S.CanPerformCopyInitialization(Entity, From)) { - Result.setStandard(); - Result.Standard.setAsIdentityConversion(); - Result.Standard.setFromType(ToType); - Result.Standard.setAllToTypes(ToType); - return Result; - } + if (S.CanPerformCopyInitialization(Entity, From)) { + Result.setStandard(); + Result.Standard.setAsIdentityConversion(); + Result.Standard.setFromType(ToType); + Result.Standard.setAllToTypes(ToType); + return Result; } } } @@ -5064,43 +5073,89 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // default-constructible, and if all the elements of the initializer list // can be implicitly converted to X, the implicit conversion sequence is // the worst conversion necessary to convert an element of the list to X. - // - // FIXME: We're missing a lot of these checks. - bool toStdInitializerList = false; - QualType X; - if (ToType->isArrayType()) - X = S.Context.getAsArrayType(ToType)->getElementType(); - else - toStdInitializerList = S.isStdInitializerList(ToType, &X); - if (!X.isNull()) { - for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) { - Expr *Init = From->getInit(i); - ImplicitConversionSequence ICS = - TryCopyInitialization(S, Init, X, SuppressUserConversions, - InOverloadResolution, - AllowObjCWritebackConversion); - // If a single element isn't convertible, fail. - if (ICS.isBad()) { - Result = ICS; - break; + if (AT || S.isStdInitializerList(ToType, &InitTy)) { + unsigned e = From->getNumInits(); + ImplicitConversionSequence DfltElt; + DfltElt.setBad(BadConversionSequence::no_conversion, QualType(), + QualType()); + QualType ContTy = ToType; + bool IsUnbounded = false; + if (AT) { + InitTy = AT->getElementType(); + if (ConstantArrayType const *CT = dyn_cast(AT)) { + if (CT->getSize().ult(e)) { + // Too many inits, fatally bad + Result.setBad(BadConversionSequence::too_many_initializers, From, + ToType); + Result.setInitializerListContainerType(ContTy, IsUnbounded); + return Result; + } + if (CT->getSize().ugt(e)) { + // Need an init from empty {}, is there one? + InitListExpr EmptyList(S.Context, From->getEndLoc(), None, + From->getEndLoc()); + EmptyList.setType(S.Context.VoidTy); + DfltElt = TryListConversion( + S, &EmptyList, InitTy, SuppressUserConversions, + InOverloadResolution, AllowObjCWritebackConversion); + if (DfltElt.isBad()) { + // No {} init, fatally bad + Result.setBad(BadConversionSequence::too_few_initializers, From, + ToType); + Result.setInitializerListContainerType(ContTy, IsUnbounded); + return Result; + } + } + } else { + assert(isa(AT) && "Expected incomplete array"); + IsUnbounded = true; + if (!e) { + // Cannot convert to zero-sized. + Result.setBad(BadConversionSequence::too_few_initializers, From, + ToType); + Result.setInitializerListContainerType(ContTy, IsUnbounded); + return Result; + } + llvm::APInt Size(S.Context.getTypeSize(S.Context.getSizeType()), e); + ContTy = S.Context.getConstantArrayType(InitTy, Size, nullptr, + ArrayType::Normal, 0); } - // Otherwise, look for the worst conversion. - if (Result.isBad() || CompareImplicitConversionSequences( - S, From->getBeginLoc(), ICS, Result) == - ImplicitConversionSequence::Worse) + } + + Result.setStandard(); + Result.Standard.setAsIdentityConversion(); + Result.Standard.setFromType(InitTy); + Result.Standard.setAllToTypes(InitTy); + for (unsigned i = 0; i < e; ++i) { + Expr *Init = From->getInit(i); + ImplicitConversionSequence ICS = TryCopyInitialization( + S, Init, InitTy, SuppressUserConversions, InOverloadResolution, + AllowObjCWritebackConversion); + + // Keep the worse conversion seen so far. + // FIXME: Sequences are not totally ordered, so 'worse' can be + // ambiguous. CWG has been informed. + if (CompareImplicitConversionSequences(S, From->getBeginLoc(), ICS, + Result) == + ImplicitConversionSequence::Worse) { Result = ICS; + // Bail as soon as we find something unconvertible. + if (Result.isBad()) { + Result.setInitializerListContainerType(ContTy, IsUnbounded); + return Result; + } + } } - // For an empty list, we won't have computed any conversion sequence. - // Introduce the identity conversion sequence. - if (From->getNumInits() == 0) { - Result.setStandard(); - Result.Standard.setAsIdentityConversion(); - Result.Standard.setFromType(ToType); - Result.Standard.setAllToTypes(ToType); - } - - Result.setStdInitializerListElement(toStdInitializerList); + // If we needed any implicit {} initialization, compare that now. + // over.ics.list/6 indicates we should compare that conversion. Again CWG + // has been informed that this might not be the best thing. + if (!DfltElt.isBad() && CompareImplicitConversionSequences( + S, From->getEndLoc(), DfltElt, Result) == + ImplicitConversionSequence::Worse) + Result = DfltElt; + // Record the type being initialized so that we may compare sequences + Result.setInitializerListContainerType(ContTy, IsUnbounded); return Result; } @@ -5479,6 +5534,10 @@ Sema::PerformObjectArgumentInitialization(Expr *From, case BadConversionSequence::no_conversion: case BadConversionSequence::unrelated_class: break; + + case BadConversionSequence::too_few_initializers: + case BadConversionSequence::too_many_initializers: + llvm_unreachable("Lists are not objects"); } return Diag(From->getBeginLoc(), diag::err_member_function_call_bad_type) @@ -5635,7 +5694,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // expression is a constant expression and the implicit conversion // sequence contains only [... list of conversions ...]. ImplicitConversionSequence ICS = - CCE == Sema::CCEK_ExplicitBool + (CCE == Sema::CCEK_ExplicitBool || CCE == Sema::CCEK_Noexcept) ? TryContextuallyConvertToBool(S, From) : TryCopyInitialization(S, From, T, /*SuppressUserConversions=*/false, @@ -6397,7 +6456,8 @@ void Sema::AddOverloadCandidate( // parameters is viable only if it has an ellipsis in its parameter // list (8.3.5). if (TooManyArguments(NumParams, Args.size(), PartialOverloading) && - !Proto->isVariadic()) { + !Proto->isVariadic() && + shouldEnforceArgLimit(PartialOverloading, Function)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_too_many_arguments; return; @@ -6887,7 +6947,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // parameters is viable only if it has an ellipsis in its parameter // list (8.3.5). if (TooManyArguments(NumParams, Args.size(), PartialOverloading) && - !Proto->isVariadic()) { + !Proto->isVariadic() && + shouldEnforceArgLimit(PartialOverloading, Method)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_too_many_arguments; return; @@ -8173,6 +8234,8 @@ class BuiltinOperatorOverloadBuilder { ArithmeticTypes.push_back(S.Context.LongDoubleTy); if (S.Context.getTargetInfo().hasFloat128Type()) ArithmeticTypes.push_back(S.Context.Float128Ty); + if (S.Context.getTargetInfo().hasIbm128Type()) + ArithmeticTypes.push_back(S.Context.Ibm128Ty); // Start of integral types. FirstIntegralType = ArithmeticTypes.size(); @@ -9525,7 +9588,8 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1, for (unsigned I = 0; I != NumParams; ++I) { QualType T1 = NextParam(F1, I1, I == 0); QualType T2 = NextParam(F2, I2, I == 0); - if (!T1.isNull() && !T1.isNull() && !Context.hasSameUnqualifiedType(T1, T2)) + assert(!T1.isNull() && !T2.isNull() && "Unexpected null param types"); + if (!Context.hasSameUnqualifiedType(T1, T2)) return false; } return true; @@ -9798,9 +9862,9 @@ bool clang::isBetterOverloadCandidate( // F1 and F2 have the same type. // FIXME: Implement the "all parameters have the same type" check. bool Cand1IsInherited = - dyn_cast_or_null(Cand1.FoundDecl.getDecl()); + isa_and_nonnull(Cand1.FoundDecl.getDecl()); bool Cand2IsInherited = - dyn_cast_or_null(Cand2.FoundDecl.getDecl()); + isa_and_nonnull(Cand2.FoundDecl.getDecl()); if (Cand1IsInherited != Cand2IsInherited) return Cand2IsInherited; else if (Cand1IsInherited) { @@ -10524,7 +10588,11 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_list_argument) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << ToTy << (unsigned)isObjectArgument << I + 1; + << ToTy << (unsigned)isObjectArgument << I + 1 + << (Conv.Bad.Kind == BadConversionSequence::too_few_initializers ? 1 + : Conv.Bad.Kind == BadConversionSequence::too_many_initializers + ? 2 + : 0); MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -12607,7 +12675,7 @@ static void AddOverloadedCallCandidate(Sema &S, return; } // Prevent ill-formed function decls to be added as overload candidates. - if (!dyn_cast(Func->getType()->getAs())) + if (!isa(Func->getType()->getAs())) return; S.AddOverloadCandidate(Func, FoundDecl, Args, CandidateSet, @@ -14096,7 +14164,8 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, Method->getType()->castAs())) return ExprError(); - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), + FnDecl); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -14166,6 +14235,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, + Expr *ExecConfig, bool IsExecConfig, bool AllowRecovery) { assert(MemExprE->getType() == Context.BoundMemberTy || MemExprE->getType() == Context.OverloadTy); @@ -14361,8 +14431,8 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // If overload resolution picked a static member, build a // non-member call based on that function. if (Method->isStatic()) { - return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, Args, - RParenLoc); + return BuildResolvedCallExpr(MemExprE, Method, LParenLoc, Args, RParenLoc, + ExecConfig, IsExecConfig); } MemExpr = cast(MemExprE->IgnoreParens()); @@ -14850,7 +14920,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, Method->getType()->castAs())) return ExprError(); - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method); } /// BuildLiteralOperatorCall - Build a UserDefinedLiteral by creating a call to @@ -15174,3 +15244,21 @@ ExprResult Sema::FixOverloadedFunctionReference(ExprResult E, FunctionDecl *Fn) { return FixOverloadedFunctionReference(E.get(), Found, Fn); } + +bool clang::shouldEnforceArgLimit(bool PartialOverloading, + FunctionDecl *Function) { + if (!PartialOverloading || !Function) + return true; + if (Function->isVariadic()) + return false; + if (const auto *Proto = + dyn_cast(Function->getFunctionType())) + if (Proto->isTemplateVariadic()) + return false; + if (auto *Pattern = Function->getTemplateInstantiationPattern()) + if (const auto *Proto = + dyn_cast(Pattern->getFunctionType())) + if (Proto->isTemplateVariadic()) + return false; + return true; +} diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 3b48a53efc0..815463307ec 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -38,7 +38,7 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { "Should only be called during SYCL compilation"); assert(Callee && "Callee may not be null."); - // Errors in unevaluated context don't need to be generated, + // Errors in an unevaluated context don't need to be generated, // so we can safely skip them. if (isUnevaluatedContext() || isConstantEvaluated()) return true; @@ -48,35 +48,3 @@ bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { return DiagKind != SemaDiagnosticBuilder::K_Immediate && DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; } - -// The SYCL kernel's 'object type' used for diagnostics and naming/mangling is -// the first parameter to a sycl_kernel labeled function template. In SYCL1.2.1, -// this was passed by value, and in SYCL2020, it is passed by reference. -static QualType GetSYCLKernelObjectType(const FunctionDecl *KernelCaller) { - assert(KernelCaller->getNumParams() > 0 && "Insufficient kernel parameters"); - QualType KernelParamTy = KernelCaller->getParamDecl(0)->getType(); - - // SYCL 2020 kernels are passed by reference. - if (KernelParamTy->isReferenceType()) - return KernelParamTy->getPointeeType(); - - // SYCL 1.2.1 - return KernelParamTy; -} - -void Sema::AddSYCLKernelLambda(const FunctionDecl *FD) { - auto MangleCallback = [](ASTContext &Ctx, - const NamedDecl *ND) -> llvm::Optional { - if (const auto *RD = dyn_cast(ND)) - Ctx.AddSYCLKernelNamingDecl(RD); - // We always want to go into the lambda mangling (skipping the unnamed - // struct version), so make sure we return a value here. - return 1; - }; - - QualType Ty = GetSYCLKernelObjectType(FD); - std::unique_ptr Ctx{ItaniumMangleContext::create( - Context, Context.getDiagnostics(), MangleCallback)}; - llvm::raw_null_ostream Out; - Ctx->mangleTypeName(Ty, Out); -} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 3baccec2d7b..3c820829864 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -216,9 +216,9 @@ static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A, return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2; } -void Sema::DiagnoseUnusedExprResult(const Stmt *S) { +void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) { if (const LabelStmt *Label = dyn_cast_or_null(S)) - return DiagnoseUnusedExprResult(Label->getSubStmt()); + return DiagnoseUnusedExprResult(Label->getSubStmt(), DiagID); const Expr *E = dyn_cast_or_null(S); if (!E) @@ -264,7 +264,6 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // Okay, we have an unused result. Depending on what the base expression is, // we might want to make a more specific diagnostic. Check for one of these // cases now. - unsigned DiagID = diag::warn_unused_expr; if (const FullExpr *Temps = dyn_cast(E)) E = Temps->getSubExpr(); if (const CXXBindTemporaryExpr *TempExpr = dyn_cast(E)) @@ -339,7 +338,7 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { if (LangOpts.OpenMP && isa(Source) && POE->getNumSemanticExprs() == 1 && isa(POE->getSemanticExpr(0))) - return DiagnoseUnusedExprResult(POE->getSemanticExpr(0)); + return DiagnoseUnusedExprResult(POE->getSemanticExpr(0), DiagID); if (isa(Source)) DiagID = diag::warn_unused_container_subscript_expr; else @@ -379,7 +378,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { return; } - DiagRuntimeBehavior(Loc, nullptr, PDiag(DiagID) << R1 << R2); + // Do not diagnose use of a comma operator in a SFINAE context because the + // type of the left operand could be used for SFINAE, so technically it is + // *used*. + if (DiagID != diag::warn_unused_comma_left_operand || !isSFINAEContext()) + DiagIfReachable(Loc, S ? llvm::makeArrayRef(S) : llvm::None, + PDiag(DiagID) << R1 << R2); } void Sema::ActOnStartOfCompoundStmt(bool IsStmtExpr) { @@ -543,7 +547,7 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, } ReservedIdentifierStatus Status = TheDecl->isReserved(getLangOpts()); - if (Status != ReservedIdentifierStatus::NotReserved && + if (isReservedInAllContexts(Status) && !Context.getSourceManager().isInSystemHeader(IdentLoc)) Diag(IdentLoc, diag::warn_reserved_extern_symbol) << TheDecl << static_cast(Status); @@ -858,7 +862,8 @@ public: }; } -StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, +StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, + IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *thenStmt, SourceLocation ElseLoc, @@ -871,25 +876,36 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, IfLoc), false); + bool ConstevalOrNegatedConsteval = + StatementKind == IfStatementKind::ConstevalNonNegated || + StatementKind == IfStatementKind::ConstevalNegated; + Expr *CondExpr = Cond.get().second; + assert((CondExpr || ConstevalOrNegatedConsteval) && + "If statement: missing condition"); // Only call the CommaVisitor when not C89 due to differences in scope flags. - if ((getLangOpts().C99 || getLangOpts().CPlusPlus) && + if (CondExpr && (getLangOpts().C99 || getLangOpts().CPlusPlus) && !Diags.isIgnored(diag::warn_comma_operator, CondExpr->getExprLoc())) CommaVisitor(*this).Visit(CondExpr); - if (!elseStmt) + if (!ConstevalOrNegatedConsteval && !elseStmt) DiagnoseEmptyStmtBody(CondExpr->getEndLoc(), thenStmt, diag::warn_empty_if_body); - if (IsConstexpr) { + if (ConstevalOrNegatedConsteval || + StatementKind == IfStatementKind::Constexpr) { auto DiagnoseLikelihood = [&](const Stmt *S) { if (const Attr *A = Stmt::getLikelihoodAttr(S)) { Diags.Report(A->getLocation(), - diag::warn_attribute_has_no_effect_on_if_constexpr) - << A << A->getRange(); + diag::warn_attribute_has_no_effect_on_compile_time_if) + << A << ConstevalOrNegatedConsteval << A->getRange(); Diags.Report(IfLoc, - diag::note_attribute_has_no_effect_on_if_constexpr_here) - << SourceRange(IfLoc, LParenLoc.getLocWithOffset(-1)); + diag::note_attribute_has_no_effect_on_compile_time_if_here) + << ConstevalOrNegatedConsteval + << SourceRange(IfLoc, (ConstevalOrNegatedConsteval + ? thenStmt->getBeginLoc() + : LParenLoc) + .getLocWithOffset(-1)); } }; DiagnoseLikelihood(thenStmt); @@ -908,11 +924,24 @@ StmtResult Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, } } - return BuildIfStmt(IfLoc, IsConstexpr, LParenLoc, InitStmt, Cond, RParenLoc, + if (ConstevalOrNegatedConsteval) { + bool Immediate = isImmediateFunctionContext(); + if (CurContext->isFunctionOrMethod()) { + const auto *FD = + dyn_cast(Decl::castFromDeclContext(CurContext)); + if (FD && FD->isConsteval()) + Immediate = true; + } + if (isUnevaluatedContext() || Immediate) + Diags.Report(IfLoc, diag::warn_consteval_if_always_true) << Immediate; + } + + return BuildIfStmt(IfLoc, StatementKind, LParenLoc, InitStmt, Cond, RParenLoc, thenStmt, ElseLoc, elseStmt); } -StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, +StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, + IfStatementKind StatementKind, SourceLocation LParenLoc, Stmt *InitStmt, ConditionResult Cond, SourceLocation RParenLoc, Stmt *thenStmt, SourceLocation ElseLoc, @@ -920,12 +949,13 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, if (Cond.isInvalid()) return StmtError(); - if (IsConstexpr || isa(Cond.get().second)) + if (StatementKind != IfStatementKind::Ordinary || + isa(Cond.get().second)) setFunctionHasBranchProtectedScope(); - return IfStmt::Create(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first, - Cond.get().second, LParenLoc, RParenLoc, thenStmt, - ElseLoc, elseStmt); + return IfStmt::Create(Context, IfLoc, StatementKind, InitStmt, + Cond.get().first, Cond.get().second, LParenLoc, + RParenLoc, thenStmt, ElseLoc, elseStmt); } namespace { @@ -1563,7 +1593,7 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, auto DB = Diag(CondExpr->getExprLoc(), TheDefaultStmt ? diag::warn_def_missing_case : diag::warn_missing_case) - << (int)UnhandledNames.size(); + << CondExpr->getSourceRange() << (int)UnhandledNames.size(); for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3); I != E; ++I) @@ -2729,7 +2759,7 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, if (auto *DD = dyn_cast(LoopVar)) for (auto *Binding : DD->bindings()) Binding->setType(Context.DependentTy); - LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); + LoopVar->setType(SubstAutoTypeDependent(LoopVar->getType())); } } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); @@ -3316,7 +3346,7 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// being thrown, or being co_returned from a coroutine. This expression /// might be modified by the implementation. /// -/// \param ForceCXX2b Overrides detection of current language mode +/// \param Mode Overrides detection of current language mode /// and uses the rules for C++2b. /// /// \returns An aggregate which contains the Candidate and isMoveEligible @@ -3453,7 +3483,7 @@ const VarDecl *Sema::getCopyElisionCandidate(NamedReturnInfo &Info, /// Verify that the initialization sequence that was picked for the /// first overload resolution is permissible under C++98. /// -/// Reject (possibly converting) contructors not taking an rvalue reference, +/// Reject (possibly converting) constructors not taking an rvalue reference, /// or user conversion operators which are not ref-qualified. static bool VerifyInitializationSequenceCXX98(const Sema &S, @@ -3481,7 +3511,8 @@ VerifyInitializationSequenceCXX98(const Sema &S, ExprResult Sema::PerformMoveOrCopyInitialization( const InitializedEntity &Entity, const NamedReturnInfo &NRInfo, Expr *Value, bool SupressSimplerImplicitMoves) { - if ((!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) && + if (getLangOpts().CPlusPlus && + (!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) && NRInfo.isMoveEligible()) { ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), CK_NoOp, Value, VK_XValue, FPOptionsOverride()); @@ -3652,8 +3683,8 @@ StmtResult Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, // In C++ the return statement is handled via a copy initialization. // the C version of which boils down to CheckSingleAssignmentConstraints. - InitializedEntity Entity = InitializedEntity::InitializeResult( - ReturnLoc, FnRetType, NRVOCandidate != nullptr); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, FnRetType); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); if (Res.isInvalid()) { @@ -3884,7 +3915,7 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (RetValExp && DiagnoseUnexpandedParameterPack(RetValExp)) return StmtError(); - // HACK: We supress simpler implicit move here in msvc compatibility mode + // HACK: We suppress simpler implicit move here in msvc compatibility mode // just as a temporary work around, as the MSVC STL has issues with // this change. bool SupressSimplerImplicitMoves = @@ -4084,8 +4115,8 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { // the C version of which boils down to CheckSingleAssignmentConstraints. if (!HasDependentReturnType && !RetValExp->isTypeDependent()) { // we have a non-void function with an expression, continue checking - InitializedEntity Entity = InitializedEntity::InitializeResult( - ReturnLoc, RetType, NRVOCandidate != nullptr); + InitializedEntity Entity = + InitializedEntity::InitializeResult(ReturnLoc, RetType); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRInfo, RetValExp, SupressSimplerImplicitMoves); if (Res.isInvalid()) { @@ -4156,7 +4187,14 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, if (!getLangOpts().ObjCExceptions) Diag(AtLoc, diag::err_objc_exceptions_disabled) << "@try"; - setFunctionHasBranchProtectedScope(); + // Objective-C try is incompatible with SEH __try. + sema::FunctionScopeInfo *FSI = getCurFunction(); + if (FSI->FirstSEHTryLoc.isValid()) { + Diag(AtLoc, diag::err_mixing_cxx_try_seh_try) << 1; + Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; + } + + FSI->setHasObjCTry(AtLoc); unsigned NumCatchStmts = CatchStmts.size(); return ObjCAtTryStmt::Create(Context, AtLoc, Try, CatchStmts.data(), NumCatchStmts, Finally); @@ -4392,7 +4430,7 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // C++ try is incompatible with SEH __try. if (!getLangOpts().Borland && FSI->FirstSEHTryLoc.isValid()) { - Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); + Diag(TryLoc, diag::err_mixing_cxx_try_seh_try) << 0; Diag(FSI->FirstSEHTryLoc, diag::note_conflicting_try_here) << "'__try'"; } @@ -4476,9 +4514,12 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, // SEH __try is incompatible with C++ try. Borland appears to support this, // however. if (!getLangOpts().Borland) { - if (FSI->FirstCXXTryLoc.isValid()) { - Diag(TryLoc, diag::err_mixing_cxx_try_seh_try); - Diag(FSI->FirstCXXTryLoc, diag::note_conflicting_try_here) << "'try'"; + if (FSI->FirstCXXOrObjCTryLoc.isValid()) { + Diag(TryLoc, diag::err_mixing_cxx_try_seh_try) << FSI->FirstTryType; + Diag(FSI->FirstCXXOrObjCTryLoc, diag::note_conflicting_try_here) + << (FSI->FirstTryType == sema::FunctionScopeInfo::TryLocIsCXX + ? "'try'" + : "'@try'"); } } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 243d0b921cd..603611b2d86 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -393,30 +393,31 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); - } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { - if (!InputExpr->isValueDependent()) { - Expr::EvalResult EVResult; - if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) { - // For compatibility with GCC, we also allow pointers that would be - // integral constant expressions if they were cast to int. - llvm::APSInt IntResult; - if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), - Context)) - if (!Info.isValidAsmImmediate(IntResult)) - return StmtError(Diag(InputExpr->getBeginLoc(), - diag::err_invalid_asm_value_for_constraint) - << toString(IntResult, 10) - << Info.getConstraintStr() - << InputExpr->getSourceRange()); - } - } - } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) return StmtError(); - Exprs[i] = Result.get(); + InputExpr = Exprs[i] = Result.get(); + + if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { + if (!InputExpr->isValueDependent()) { + Expr::EvalResult EVResult; + if (InputExpr->EvaluateAsRValue(EVResult, Context, true)) { + // For compatibility with GCC, we also allow pointers that would be + // integral constant expressions if they were cast to int. + llvm::APSInt IntResult; + if (EVResult.Val.toIntegralConstant(IntResult, InputExpr->getType(), + Context)) + if (!Info.isValidAsmImmediate(IntResult)) + return StmtError( + Diag(InputExpr->getBeginLoc(), + diag::err_invalid_asm_value_for_constraint) + << toString(IntResult, 10) << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } + } + } } if (Info.allowsRegister()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 17538819832..f4fd2ea5aa8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -485,8 +485,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, // all language modes, and diagnose the empty lookup in ActOnCallExpr if we // successfully form a call to an undeclared template-id. bool AllFunctions = - getLangOpts().CPlusPlus20 && - std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) { + getLangOpts().CPlusPlus20 && llvm::all_of(Found, [](NamedDecl *ND) { return isa(ND->getUnderlyingDecl()); }); if (AllFunctions || (Found.empty() && !IsDependent)) { @@ -744,7 +743,7 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, // Check if the nested name specifier is an enum type. bool IsEnum = false; if (NestedNameSpecifier *NNS = SS.getScopeRep()) - IsEnum = dyn_cast_or_null(NNS->getAsType()); + IsEnum = isa_and_nonnull(NNS->getAsType()); if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && isa(DC) && cast(DC)->isInstance()) { @@ -1079,7 +1078,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; // Check the template argument itself. - if (CheckTemplateArgument(Param, DefaultTInfo)) { + if (CheckTemplateArgument(DefaultTInfo)) { Param->setInvalidDecl(); return Param; } @@ -1206,7 +1205,7 @@ static ExprResult formImmediatelyDeclaredConstraint( } /// Attach a type-constraint to a template parameter. -/// \returns true if an error occured. This can happen if the +/// \returns true if an error occurred. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number /// of arguments for the named concept). bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, @@ -1260,15 +1259,15 @@ bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, BuildDeclRefExpr(NTTP, NTTP->getType(), VK_PRValue, NTTP->getLocation()); if (!Ref) return true; - ExprResult ImmediatelyDeclaredConstraint = - formImmediatelyDeclaredConstraint( - *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), - TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), - BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), - [&] (TemplateArgumentListInfo &ConstraintArgs) { - for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) - ConstraintArgs.addArgument(TL.getArgLoc(I)); - }, EllipsisLoc); + ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref), NTTP->getLocation(), + [&](TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, + EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid() || !ImmediatelyDeclaredConstraint.isUsable()) return true; @@ -1290,7 +1289,7 @@ QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); + TSI = SubstAutoTypeSourceInfoDependent(TSI); } return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); @@ -2267,22 +2266,8 @@ private: TTP->isParameterPack(), TTP->hasTypeConstraint(), TTP->isExpandedParameterPack() ? llvm::Optional(TTP->getNumExpansionParameters()) : None); - if (const auto *TC = TTP->getTypeConstraint()) { - TemplateArgumentListInfo TransformedArgs; - const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); - if (!ArgsAsWritten || - SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), - ArgsAsWritten->NumTemplateArgs, TransformedArgs, - Args)) - SemaRef.AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr, - NewTTP, - NewTTP->isParameterPack() - ? cast(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation()); - } + if (const auto *TC = TTP->getTypeConstraint()) + SemaRef.SubstTypeConstraint(NewTTP, TC, Args); if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -3511,8 +3496,10 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, } /// Determine whether this alias template is "enable_if_t". +/// libc++ >=14 uses "__enable_if_t" in C++11 mode. static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) { - return AliasTemplate->getName().equals("enable_if_t"); + return AliasTemplate->getName().equals("enable_if_t") || + AliasTemplate->getName().equals("__enable_if_t"); } /// Collect all of the separable terms in the given condition, which @@ -5042,7 +5029,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, } } - if (CheckTemplateArgument(Param, TSI)) + if (CheckTemplateArgument(TSI)) return true; // Add the converted template type argument. @@ -5110,7 +5097,11 @@ SubstDefaultTemplateArgument(Sema &SemaRef, for (unsigned i = 0, e = Param->getDepth(); i != e; ++i) TemplateArgLists.addOuterTemplateArguments(None); - Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); + bool ForLambdaCallOperator = false; + if (const auto *Rec = dyn_cast(Template->getDeclContext())) + ForLambdaCallOperator = Rec->isLambda(); + Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext(), + !ForLambdaCallOperator); ArgType = SemaRef.SubstType(ArgType, TemplateArgLists, Param->getDefaultArgumentLoc(), Param->getDeclName()); @@ -5661,7 +5652,7 @@ bool Sema::CheckTemplateArgumentList( TemplateArgumentListInfo NewArgs = TemplateArgs; // Make sure we get the template parameter list from the most - // recentdeclaration, since that is the only one that has is guaranteed to + // recent declaration, since that is the only one that is guaranteed to // have all the default template argument information. TemplateParameterList *Params = cast(Template->getMostRecentDecl()) @@ -6208,8 +6199,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( /// /// This routine implements the semantics of C++ [temp.arg.type]. It /// returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, - TypeSourceInfo *ArgInfo) { +bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) { assert(ArgInfo && "invalid TypeSourceInfo"); QualType Arg = ArgInfo->getType(); SourceRange SR = ArgInfo->getTypeLoc().getSourceRange(); @@ -8703,7 +8693,7 @@ static SourceLocation DiagLocForExplicitInstantiation( /// /// \param PrevTSK the kind of the old explicit specialization or instantiatin. /// -/// \param PrevPointOfInstantiation if valid, indicates where the previus +/// \param PrevPointOfInstantiation if valid, indicates where the previous /// declaration was instantiated (either implicitly or explicitly). /// /// \param HasNoEffect will be set to true to indicate that the new @@ -10883,7 +10873,7 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation( // - an identifier associated by name lookup with a non-type // template-parameter declared with a type that contains a // placeholder type (7.1.7.4), - NewTSI = SubstAutoTypeSourceInfo(NewTSI, Context.DependentTy); + NewTSI = SubstAutoTypeSourceInfoDependent(NewTSI); } if (NewTSI != NTTP->getTypeSourceInfo()) { @@ -10929,9 +10919,9 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } Out << " = "; - Args[I].print( - getPrintingPolicy(), Out, - TemplateParameterList::shouldIncludeTypeForArgument(Params, I)); + Args[I].print(getPrintingPolicy(), Out, + TemplateParameterList::shouldIncludeTypeForArgument( + getPrintingPolicy(), Params, I)); } Out << ']'; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 08e798304b0..81edae10335 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -131,30 +131,16 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } -static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, - const TemplateArgument &Param, - TemplateArgument Arg, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced); - -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsByTypeMatch(Sema &S, - TemplateParameterList *TemplateParams, - QualType Param, - QualType Arg, - TemplateDeductionInfo &Info, - SmallVectorImpl & - Deduced, - unsigned TDF, - bool PartialOrdering = false, - bool DeducedFromArrayBound = false); +static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( + Sema &S, TemplateParameterList *TemplateParams, QualType Param, + QualType Arg, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, unsigned TDF, + bool PartialOrdering = false, bool DeducedFromArrayBound = false); static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Params, - ArrayRef Args, + ArrayRef Ps, + ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch); @@ -559,75 +545,67 @@ DeduceTemplateArguments(Sema &S, /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, - const TemplateSpecializationType *Param, - QualType Arg, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { - assert(Arg.isCanonical() && "Argument type must be canonical"); +DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, + const QualType P, QualType A, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + QualType UP = P; + if (const auto *IP = P->getAs()) + UP = IP->getInjectedSpecializationType(); + // FIXME: Try to preserve type sugar here, which is hard + // because of the unresolved template arguments. + const auto *TP = UP.getCanonicalType()->castAs(); + ArrayRef PResolved = TP->template_arguments(); + QualType UA = A; // Treat an injected-class-name as its underlying template-id. - if (auto *Injected = dyn_cast(Arg)) - Arg = Injected->getInjectedSpecializationType(); + if (const auto *Injected = A->getAs()) + UA = Injected->getInjectedSpecializationType(); // Check whether the template argument is a dependent template-id. - if (const TemplateSpecializationType *SpecArg - = dyn_cast(Arg)) { + // FIXME: Should not lose sugar here. + if (const auto *SA = + dyn_cast(UA.getCanonicalType())) { // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Param->getTemplateName(), - SpecArg->getTemplateName(), - Info, Deduced)) + if (auto Result = + DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), + SA->getTemplateName(), Info, Deduced)) return Result; - - // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, - Param->template_arguments(), - SpecArg->template_arguments(), Info, Deduced, + return DeduceTemplateArguments(S, TemplateParams, PResolved, + SA->template_arguments(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } // If the argument type is a class template specialization, we // perform template argument deduction using its template // arguments. - const RecordType *RecordArg = dyn_cast(Arg); - if (!RecordArg) { - Info.FirstArg = TemplateArgument(QualType(Param, 0)); - Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_NonDeducedMismatch; - } - - ClassTemplateSpecializationDecl *SpecArg - = dyn_cast(RecordArg->getDecl()); - if (!SpecArg) { - Info.FirstArg = TemplateArgument(QualType(Param, 0)); - Info.SecondArg = TemplateArgument(Arg); + const auto *RA = UA->getAs(); + const auto *SA = + RA ? dyn_cast(RA->getDecl()) : nullptr; + if (!SA) { + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); return Sema::TDK_NonDeducedMismatch; } // Perform template argument deduction for the template name. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, - TemplateParams, - Param->getTemplateName(), - TemplateName(SpecArg->getSpecializedTemplate()), - Info, Deduced)) + if (auto Result = DeduceTemplateArguments( + S, TemplateParams, TP->getTemplateName(), + TemplateName(SA->getSpecializedTemplate()), Info, Deduced)) return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(), - SpecArg->getTemplateArgs().asArray(), Info, - Deduced, /*NumberOfArgumentsMustMatch=*/true); + return DeduceTemplateArguments(S, TemplateParams, PResolved, + SA->getTemplateArgs().asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/true); } -/// Determines whether the given type is an opaque type that -/// might be more qualified when instantiated. -static bool IsPossiblyOpaquelyQualifiedType(QualType T) { +static bool IsPossiblyOpaquelyQualifiedTypeInternal(const Type *T) { + assert(T->isCanonicalUnqualified()); + switch (T->getTypeClass()) { case Type::TypeOfExpr: case Type::TypeOf: @@ -641,14 +619,21 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) { case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: - return IsPossiblyOpaquelyQualifiedType( - cast(T)->getElementType()); + return IsPossiblyOpaquelyQualifiedTypeInternal( + cast(T)->getElementType().getTypePtr()); default: return false; } } +/// Determines whether the given type is an opaque type that +/// might be more qualified when instantiated. +static bool IsPossiblyOpaquelyQualifiedType(QualType T) { + return IsPossiblyOpaquelyQualifiedTypeInternal( + T->getCanonicalTypeInternal().getTypePtr()); +} + /// Helper function to build a TemplateParameter when we don't /// know its type statically. static TemplateParameter makeTemplateParameter(Decl *D) { @@ -1047,11 +1032,12 @@ DeduceTemplateArguments(Sema &S, return Sema::TDK_MiscellaneousDeductionFailure; } - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - Params[ParamIdx], Args[ArgIdx], - Info, Deduced, TDF, - PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, + /*DeducedFromArrayBound=*/false)) return Result; ++ArgIdx; @@ -1073,10 +1059,11 @@ DeduceTemplateArguments(Sema &S, if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, - Args[ArgIdx], Info, Deduced, - TDF, PartialOrdering)) + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Pattern.getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, /*DeducedFromArrayBound=*/false)) return Result; PackScope.nextPackElement(); @@ -1155,26 +1142,25 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, /// function types (noreturn adjustment, implicit calling conventions). If any /// of parameter and argument is not a function, just perform type comparison. /// -/// \param Param the template parameter type. +/// \param P the template parameter type. /// -/// \param Arg the argument type. -bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, - CanQualType Arg) { - const FunctionType *ParamFunction = Param->getAs(), - *ArgFunction = Arg->getAs(); +/// \param A the argument type. +bool Sema::isSameOrCompatibleFunctionType(QualType P, QualType A) { + const FunctionType *PF = P->getAs(), + *AF = A->getAs(); // Just compare if not functions. - if (!ParamFunction || !ArgFunction) - return Param == Arg; + if (!PF || !AF) + return Context.hasSameType(P, A); // Noreturn and noexcept adjustment. QualType AdjustedParam; - if (IsFunctionConversion(Param, Arg, AdjustedParam)) - return Arg == Context.getCanonicalType(AdjustedParam); + if (IsFunctionConversion(P, A, AdjustedParam)) + return Context.hasSameType(AdjustedParam, A); // FIXME: Compatible calling conventions. - return Param == Arg; + return Context.hasSameType(P, A); } /// Get the index of the first template parameter that was originally from the @@ -1203,6 +1189,11 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { return false; } +static CXXRecordDecl *getCanonicalRD(QualType T) { + return cast( + T->castAs()->getDecl()->getCanonicalDecl()); +} + /// Attempt to deduce the template arguments by checking the base types /// according to (C++20 [temp.deduct.call] p4b3. /// @@ -1221,10 +1212,11 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) { /// \returns the result of template argument deduction with the bases. "invalid" /// means no matches, "success" found a single item, and the /// "MiscellaneousDeductionFailure" result happens when the match is ambiguous. -static Sema::TemplateDeductionResult DeduceTemplateBases( - Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams, - const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced) { +static Sema::TemplateDeductionResult +DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, + TemplateParameterList *TemplateParams, QualType P, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { // C++14 [temp.deduct.call] p4b3: // If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. Likewise if @@ -1244,45 +1236,44 @@ static Sema::TemplateDeductionResult DeduceTemplateBases( // visited, while ToVisit is our stack of records that we still need to // visit. Matches contains a list of matches that have yet to be // disqualified. - llvm::SmallPtrSet Visited; - SmallVector ToVisit; + llvm::SmallPtrSet Visited; + SmallVector ToVisit; // We iterate over this later, so we have to use MapVector to ensure // determinism. - llvm::MapVector> + llvm::MapVector> Matches; - auto AddBases = [&Visited, &ToVisit](const RecordType *RT) { - CXXRecordDecl *RD = cast(RT->getDecl()); + auto AddBases = [&Visited, &ToVisit](const CXXRecordDecl *RD) { for (const auto &Base : RD->bases()) { - assert(Base.getType()->isRecordType() && - "Base class that isn't a record?"); - const RecordType *RT = Base.getType()->getAs(); - if (Visited.insert(RT).second) - ToVisit.push_back(Base.getType()->getAs()); + QualType T = Base.getType(); + assert(T->isRecordType() && "Base class that isn't a record?"); + if (Visited.insert(::getCanonicalRD(T)).second) + ToVisit.push_back(T); } }; // Set up the loop by adding all the bases. - AddBases(RecordT); + AddBases(RD); // Search each path of bases until we either run into a successful match // (where all bases of it are invalid), or we run out of bases. while (!ToVisit.empty()) { - const RecordType *NextT = ToVisit.pop_back_val(); + QualType NextT = ToVisit.pop_back_val(); SmallVector DeducedCopy(Deduced.begin(), Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = - DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), BaseInfo, DeducedCopy); + Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( + S, TemplateParams, P, NextT, BaseInfo, DeducedCopy); // If this was a successful deduction, add it to the list of matches, // otherwise we need to continue searching its bases. + const CXXRecordDecl *RD = ::getCanonicalRD(NextT); if (BaseResult == Sema::TDK_Success) - Matches.insert({NextT, DeducedCopy}); + Matches.insert({RD, DeducedCopy}); else - AddBases(NextT); + AddBases(RD); } // At this point, 'Matches' contains a list of seemingly valid bases, however @@ -1297,14 +1288,14 @@ static Sema::TemplateDeductionResult DeduceTemplateBases( AddBases(Match.first); // We can give up once we have a single item (or have run out of things to - // search) since cyclical inheritence isn't valid. + // search) since cyclical inheritance isn't valid. while (Matches.size() > 1 && !ToVisit.empty()) { - const RecordType *NextT = ToVisit.pop_back_val(); - Matches.erase(NextT); + const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val()); + Matches.erase(RD); - // Always add all bases, since the inheritence tree can contain + // Always add all bases, since the inheritance tree can contain // disqualifications for multiple matches. - AddBases(NextT); + AddBases(RD); } } @@ -1341,41 +1332,33 @@ static Sema::TemplateDeductionResult DeduceTemplateBases( /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult -DeduceTemplateArgumentsByTypeMatch(Sema &S, - TemplateParameterList *TemplateParams, - QualType ParamIn, QualType ArgIn, - TemplateDeductionInfo &Info, - SmallVectorImpl &Deduced, - unsigned TDF, - bool PartialOrdering, - bool DeducedFromArrayBound) { - // We only want to look at the canonical types, since typedefs and - // sugar are not part of template argument deduction. - QualType Param = S.Context.getCanonicalType(ParamIn); - QualType Arg = S.Context.getCanonicalType(ArgIn); +static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( + Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A, + TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced, unsigned TDF, + bool PartialOrdering, bool DeducedFromArrayBound) { // If the argument type is a pack expansion, look at its pattern. // This isn't explicitly called out - if (const PackExpansionType *ArgExpansion - = dyn_cast(Arg)) - Arg = ArgExpansion->getPattern(); + if (const auto *AExp = dyn_cast(A)) + A = AExp->getPattern(); + assert(!isa(A.getCanonicalType())); if (PartialOrdering) { // C++11 [temp.deduct.partial]p5: // Before the partial ordering is done, certain transformations are // performed on the types used for partial ordering: // - If P is a reference type, P is replaced by the type referred to. - const ReferenceType *ParamRef = Param->getAs(); - if (ParamRef) - Param = ParamRef->getPointeeType(); + const ReferenceType *PRef = P->getAs(); + if (PRef) + P = PRef->getPointeeType(); // - If A is a reference type, A is replaced by the type referred to. - const ReferenceType *ArgRef = Arg->getAs(); - if (ArgRef) - Arg = ArgRef->getPointeeType(); + const ReferenceType *ARef = A->getAs(); + if (ARef) + A = A->getPointeeType(); - if (ParamRef && ArgRef && S.Context.hasSameUnqualifiedType(Param, Arg)) { + if (PRef && ARef && S.Context.hasSameUnqualifiedType(P, A)) { // C++11 [temp.deduct.partial]p9: // If, for a given type, deduction succeeds in both directions (i.e., // the types are identical after the transformations above) and both @@ -1395,29 +1378,26 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // succeeds, so we model this as a deduction failure. Note that // [the first type] is P and [the other type] is A here; the standard // gets this backwards. - Qualifiers ParamQuals = Param.getQualifiers(); - Qualifiers ArgQuals = Arg.getQualifiers(); - if ((ParamRef->isLValueReferenceType() && - !ArgRef->isLValueReferenceType()) || - ParamQuals.isStrictSupersetOf(ArgQuals) || - (ParamQuals.hasNonTrivialObjCLifetime() && - ArgQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone && - ParamQuals.withoutObjCLifetime() == - ArgQuals.withoutObjCLifetime())) { - Info.FirstArg = TemplateArgument(ParamIn); - Info.SecondArg = TemplateArgument(ArgIn); + Qualifiers PQuals = P.getQualifiers(), AQuals = A.getQualifiers(); + if ((PRef->isLValueReferenceType() && !ARef->isLValueReferenceType()) || + PQuals.isStrictSupersetOf(AQuals) || + (PQuals.hasNonTrivialObjCLifetime() && + AQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone && + PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) { + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); return Sema::TDK_NonDeducedMismatch; } } - + Qualifiers DiscardedQuals; // C++11 [temp.deduct.partial]p7: // Remove any top-level cv-qualifiers: // - If P is a cv-qualified type, P is replaced by the cv-unqualified // version of P. - Param = Param.getUnqualifiedType(); + P = S.Context.getUnqualifiedArrayType(P, DiscardedQuals); // - If A is a cv-qualified type, A is replaced by the cv-unqualified // version of A. - Arg = Arg.getUnqualifiedType(); + A = S.Context.getUnqualifiedArrayType(A, DiscardedQuals); } else { // C++0x [temp.deduct.call]p4 bullet 1: // - If the original P is a reference type, the deduced A (i.e., the type @@ -1425,13 +1405,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // transformed A. if (TDF & TDF_ParamWithReferenceType) { Qualifiers Quals; - QualType UnqualParam = S.Context.getUnqualifiedArrayType(Param, Quals); - Quals.setCVRQualifiers(Quals.getCVRQualifiers() & - Arg.getCVRQualifiers()); - Param = S.Context.getQualifiedType(UnqualParam, Quals); + QualType UnqualP = S.Context.getUnqualifiedArrayType(P, Quals); + Quals.setCVRQualifiers(Quals.getCVRQualifiers() & A.getCVRQualifiers()); + P = S.Context.getQualifiedType(UnqualP, Quals); } - if ((TDF & TDF_TopLevelParameterTypeList) && !Param->isFunctionType()) { + if ((TDF & TDF_TopLevelParameterTypeList) && !P->isFunctionType()) { // C++0x [temp.deduct.type]p10: // If P and A are function types that originated from deduction when // taking the address of a function template (14.8.2.2) or when deducing @@ -1444,8 +1423,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // Pi is T&& and Ai is X&, the adjusted Pi will be T, causing T to be // deduced as X&. - end note ] TDF &= ~TDF_TopLevelParameterTypeList; - if (isForwardingReference(Param, 0) && Arg->isLValueReferenceType()) - Param = Param->getPointeeType(); + if (isForwardingReference(P, /*FirstInnerIndex=*/0) && + A->isLValueReferenceType()) + P = P->getPointeeType(); } } @@ -1456,53 +1436,48 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // // T // cv-list T - if (const TemplateTypeParmType *TemplateTypeParm - = Param->getAs()) { + if (const auto *TTP = P->getAs()) { // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. - if (Arg->isPlaceholderType() || - Info.getDeducedDepth() != TemplateTypeParm->getDepth()) + if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) return Sema::TDK_Success; - unsigned Index = TemplateTypeParm->getIndex(); - bool RecanonicalizeArg = false; + unsigned Index = TTP->getIndex(); // If the argument type is an array type, move the qualifiers up to the // top level, so they can be matched with the qualifiers on the parameter. - if (isa(Arg)) { + if (A->isArrayType()) { Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - if (Quals) { - Arg = S.Context.getQualifiedType(Arg, Quals); - RecanonicalizeArg = true; - } + A = S.Context.getUnqualifiedArrayType(A, Quals); + if (Quals) + A = S.Context.getQualifiedType(A, Quals); } // The argument type can not be less qualified than the parameter // type. if (!(TDF & TDF_IgnoreQualifiers) && - hasInconsistentOrSupersetQualifiersOf(Param, Arg)) { + hasInconsistentOrSupersetQualifiersOf(P, A)) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(Param); - Info.SecondArg = TemplateArgument(Arg); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); return Sema::TDK_Underqualified; } // Do not match a function type with a cv-qualified type. // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584 - if (Arg->isFunctionType() && Param.hasQualifiers()) { + if (A->isFunctionType() && P.hasQualifiers()) return Sema::TDK_NonDeducedMismatch; - } - assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && + assert(TTP->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); - assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); - QualType DeducedType = Arg; + assert(A->getCanonicalTypeInternal() != S.Context.OverloadTy && + "Unresolved overloaded function"); + QualType DeducedType = A; // Remove any qualifiers on the parameter from the deduced type. // We checked the qualifiers for consistency above. Qualifiers DeducedQs = DeducedType.getQualifiers(); - Qualifiers ParamQs = Param.getQualifiers(); + Qualifiers ParamQs = P.getQualifiers(); DeducedQs.removeCVRQualifiers(ParamQs.getCVRQualifiers()); if (ParamQs.hasObjCGCAttr()) DeducedQs.removeObjCGCAttr(); @@ -1517,29 +1492,24 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (ParamQs.hasObjCLifetime() && !DeducedType->isObjCLifetimeType() && !DeducedType->isDependentType()) { Info.Param = cast(TemplateParams->getParam(Index)); - Info.FirstArg = TemplateArgument(Param); - Info.SecondArg = TemplateArgument(Arg); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); return Sema::TDK_Underqualified; } // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. - if (S.getLangOpts().ObjCAutoRefCount && - DeducedType->isObjCLifetimeType() && + if (S.getLangOpts().ObjCAutoRefCount && DeducedType->isObjCLifetimeType() && !DeducedQs.hasObjCLifetime()) DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); - DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), - DeducedQs); - - if (RecanonicalizeArg) - DeducedType = S.Context.getCanonicalType(DeducedType); + DeducedType = + S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[Index], - NewDeduced); + DeducedTemplateArgument Result = + checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); if (Result.isNull()) { Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; @@ -1552,69 +1522,57 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, } // Set up the template argument deduction information for a failure. - Info.FirstArg = TemplateArgument(ParamIn); - Info.SecondArg = TemplateArgument(ArgIn); + Info.FirstArg = TemplateArgument(P); + Info.SecondArg = TemplateArgument(A); // If the parameter is an already-substituted template parameter // pack, do nothing: we don't know which of its arguments to look // at, so we have to wait until all of the parameter packs in this // expansion have arguments. - if (isa(Param)) + if (P->getAs()) return Sema::TDK_Success; // Check the cv-qualifiers on the parameter and argument types. - CanQualType CanParam = S.Context.getCanonicalType(Param); - CanQualType CanArg = S.Context.getCanonicalType(Arg); if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { - if (hasInconsistentOrSupersetQualifiersOf(Param, Arg)) + if (hasInconsistentOrSupersetQualifiersOf(P, A)) return Sema::TDK_NonDeducedMismatch; } else if (TDF & TDF_ArgWithReferenceType) { // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A - if (!Arg.getQualifiers().compatiblyIncludes(Param.getQualifiers())) + if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) return Sema::TDK_NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the // type we're converting to, prior to the qualification conversion. Qualifiers Quals; - Arg = S.Context.getUnqualifiedArrayType(Arg, Quals); - Arg = S.Context.getQualifiedType(Arg, Param.getQualifiers()); - } else if (!IsPossiblyOpaquelyQualifiedType(Param)) { - if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + A = S.Context.getUnqualifiedArrayType(A, Quals); + A = S.Context.getQualifiedType(A, P.getQualifiers()); + } else if (!IsPossiblyOpaquelyQualifiedType(P)) { + if (P.getCVRQualifiers() != A.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; } - - // If the parameter type is not dependent, there is nothing to deduce. - if (!Param->isDependentType()) { - if (!(TDF & TDF_SkipNonDependent)) { - bool NonDeduced = - (TDF & TDF_AllowCompatibleFunctionType) - ? !S.isSameOrCompatibleFunctionType(CanParam, CanArg) - : Param != Arg; - if (NonDeduced) { - return Sema::TDK_NonDeducedMismatch; - } - } - return Sema::TDK_Success; - } - } else if (!Param->isDependentType()) { - if (!(TDF & TDF_SkipNonDependent)) { - CanQualType ParamUnqualType = CanParam.getUnqualifiedType(), - ArgUnqualType = CanArg.getUnqualifiedType(); - bool Success = - (TDF & TDF_AllowCompatibleFunctionType) - ? S.isSameOrCompatibleFunctionType(ParamUnqualType, ArgUnqualType) - : ParamUnqualType == ArgUnqualType; - if (Success) - return Sema::TDK_Success; - } else { - return Sema::TDK_Success; - } } - switch (Param->getTypeClass()) { + // If the parameter type is not dependent, there is nothing to deduce. + if (!P->isDependentType()) { + if (TDF & TDF_SkipNonDependent) + return Sema::TDK_Success; + if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A) + : S.Context.hasSameType(P, A)) + return Sema::TDK_Success; + if (TDF & TDF_AllowCompatibleFunctionType && + S.isSameOrCompatibleFunctionType(P, A)) + return Sema::TDK_Success; + if (!(TDF & TDF_IgnoreQualifiers)) + return Sema::TDK_NonDeducedMismatch; + // Otherwise, when ignoring qualifiers, the types not having the same + // unqualified type does not mean they do not match, so in this case we + // must keep going and analyze with a non-dependent parameter type. + } + + switch (P.getCanonicalType()->getTypeClass()) { // Non-canonical types cannot appear here. #define NON_CANONICAL_TYPE(Class, Base) \ case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); @@ -1625,8 +1583,11 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::SubstTemplateTypeParmPack: llvm_unreachable("Type nodes handled above"); - // These types cannot be dependent, so simply check whether the types are - // the same. + case Type::Auto: + // FIXME: Implement deduction in dependent case. + if (P->isDependentType()) + return Sema::TDK_Success; + LLVM_FALLTHROUGH; case Type::Builtin: case Type::VariableArray: case Type::Vector: @@ -1637,134 +1598,115 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::ObjCInterface: case Type::ObjCObjectPointer: case Type::ExtInt: - if (TDF & TDF_SkipNonDependent) - return Sema::TDK_Success; - - if (TDF & TDF_IgnoreQualifiers) { - Param = Param.getUnqualifiedType(); - Arg = Arg.getUnqualifiedType(); - } - - return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; + return (TDF & TDF_SkipNonDependent) || + ((TDF & TDF_IgnoreQualifiers) + ? S.Context.hasSameUnqualifiedType(P, A) + : S.Context.hasSameType(P, A)) + ? Sema::TDK_Success + : Sema::TDK_NonDeducedMismatch; // _Complex T [placeholder extension] - case Type::Complex: - if (const ComplexType *ComplexArg = Arg->getAs()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getElementType(), - ComplexArg->getElementType(), - Info, Deduced, TDF); - - return Sema::TDK_NonDeducedMismatch; + case Type::Complex: { + const auto *CP = P->castAs(), *CA = A->getAs(); + if (!CA) + return Sema::TDK_NonDeducedMismatch; + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, + Deduced, TDF); + } // _Atomic T [extension] - case Type::Atomic: - if (const AtomicType *AtomicArg = Arg->getAs()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getValueType(), - AtomicArg->getValueType(), - Info, Deduced, TDF); - - return Sema::TDK_NonDeducedMismatch; + case Type::Atomic: { + const auto *PA = P->castAs(), *AA = A->getAs(); + if (!AA) + return Sema::TDK_NonDeducedMismatch; + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, + Deduced, TDF); + } // T * case Type::Pointer: { QualType PointeeType; - if (const PointerType *PointerArg = Arg->getAs()) { - PointeeType = PointerArg->getPointeeType(); - } else if (const ObjCObjectPointerType *PointerArg - = Arg->getAs()) { - PointeeType = PointerArg->getPointeeType(); + if (const auto *PA = A->getAs()) { + PointeeType = PA->getPointeeType(); + } else if (const auto *PA = A->getAs()) { + PointeeType = PA->getPointeeType(); } else { return Sema::TDK_NonDeducedMismatch; } - - unsigned SubTDF = TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass); - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - PointeeType, - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, P->castAs()->getPointeeType(), + PointeeType, Info, Deduced, + TDF & (TDF_IgnoreQualifiers | TDF_DerivedClass)); } // T & case Type::LValueReference: { - const LValueReferenceType *ReferenceArg = - Arg->getAs(); - if (!ReferenceArg) + const auto *RP = P->castAs(), + *RA = A->getAs(); + if (!RA) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, + Deduced, 0); } // T && [C++0x] case Type::RValueReference: { - const RValueReferenceType *ReferenceArg = - Arg->getAs(); - if (!ReferenceArg) + const auto *RP = P->castAs(), + *RA = A->getAs(); + if (!RA) return Sema::TDK_NonDeducedMismatch; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast(Param)->getPointeeType(), - ReferenceArg->getPointeeType(), - Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, + Deduced, 0); } // T [] (implied, but not stated explicitly) case Type::IncompleteArray: { - const IncompleteArrayType *IncompleteArrayArg = - S.Context.getAsIncompleteArrayType(Arg); - if (!IncompleteArrayArg) + const auto *IAA = S.Context.getAsIncompleteArrayType(A); + if (!IAA) return Sema::TDK_NonDeducedMismatch; - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - S.Context.getAsIncompleteArrayType(Param)->getElementType(), - IncompleteArrayArg->getElementType(), - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, + S.Context.getAsIncompleteArrayType(P)->getElementType(), + IAA->getElementType(), Info, Deduced, TDF & TDF_IgnoreQualifiers); } // T [integer-constant] case Type::ConstantArray: { - const ConstantArrayType *ConstantArrayArg = - S.Context.getAsConstantArrayType(Arg); - if (!ConstantArrayArg) + const auto *CAA = S.Context.getAsConstantArrayType(A), + *CAP = S.Context.getAsConstantArrayType(P); + assert(CAP); + if (!CAA || CAA->getSize() != CAP->getSize()) return Sema::TDK_NonDeducedMismatch; - const ConstantArrayType *ConstantArrayParm = - S.Context.getAsConstantArrayType(Param); - if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize()) - return Sema::TDK_NonDeducedMismatch; - - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - ConstantArrayParm->getElementType(), - ConstantArrayArg->getElementType(), - Info, Deduced, SubTDF); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, + Deduced, TDF & TDF_IgnoreQualifiers); } // type [i] case Type::DependentSizedArray: { - const ArrayType *ArrayArg = S.Context.getAsArrayType(Arg); - if (!ArrayArg) + const auto *AA = S.Context.getAsArrayType(A); + if (!AA) return Sema::TDK_NonDeducedMismatch; - unsigned SubTDF = TDF & TDF_IgnoreQualifiers; - // Check the element type of the arrays - const DependentSizedArrayType *DependentArrayParm - = S.Context.getAsDependentSizedArrayType(Param); - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - DependentArrayParm->getElementType(), - ArrayArg->getElementType(), - Info, Deduced, SubTDF)) + const auto *DAP = S.Context.getAsDependentSizedArrayType(P); + assert(DAP); + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, DAP->getElementType(), AA->getElementType(), + Info, Deduced, TDF & TDF_IgnoreQualifiers)) return Result; // Determine the array bound is something we can deduce. - const NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; @@ -1772,20 +1714,16 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // template parameter. assert(NTTP->getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); - if (const ConstantArrayType *ConstantArrayArg - = dyn_cast(ArrayArg)) { - llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size, - S.Context.getSizeType(), - /*ArrayBound=*/true, - Info, Deduced); + if (const auto *CAA = dyn_cast(AA)) { + llvm::APSInt Size(CAA->getSize()); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, Size, S.Context.getSizeType(), + /*ArrayBound=*/true, Info, Deduced); } - if (const DependentSizedArrayType *DependentArrayArg - = dyn_cast(ArrayArg)) - if (DependentArrayArg->getSizeExpr()) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - DependentArrayArg->getSizeExpr(), - Info, Deduced); + if (const auto *DAA = dyn_cast(AA)) + if (DAA->getSizeExpr()) + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced); // Incomplete type does not match a dependently-sized array type return Sema::TDK_NonDeducedMismatch; @@ -1795,34 +1733,29 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T(*)() // T(*)(T) case Type::FunctionProto: { - unsigned SubTDF = TDF & TDF_TopLevelParameterTypeList; - const FunctionProtoType *FunctionProtoArg = - dyn_cast(Arg); - if (!FunctionProtoArg) + const auto *FPP = P->castAs(), + *FPA = A->getAs(); + if (!FPA) return Sema::TDK_NonDeducedMismatch; - const FunctionProtoType *FunctionProtoParam = - cast(Param); - - if (FunctionProtoParam->getMethodQuals() - != FunctionProtoArg->getMethodQuals() || - FunctionProtoParam->getRefQualifier() - != FunctionProtoArg->getRefQualifier() || - FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic()) + if (FPP->getMethodQuals() != FPA->getMethodQuals() || + FPP->getRefQualifier() != FPA->getRefQualifier() || + FPP->isVariadic() != FPA->isVariadic()) return Sema::TDK_NonDeducedMismatch; // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, FunctionProtoParam->getReturnType(), - FunctionProtoArg->getReturnType(), Info, Deduced, 0)) + S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), + Info, Deduced, 0, + /*PartialOrdering=*/false, + /*DeducedFromArrayBound=*/false)) return Result; // Check parameter types. if (auto Result = DeduceTemplateArguments( - S, TemplateParams, FunctionProtoParam->param_type_begin(), - FunctionProtoParam->getNumParams(), - FunctionProtoArg->param_type_begin(), - FunctionProtoArg->getNumParams(), Info, Deduced, SubTDF)) + S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), + FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, + TDF & TDF_TopLevelParameterTypeList)) return Result; if (TDF & TDF_AllowCompatibleFunctionType) @@ -1831,15 +1764,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit // deducing through the noexcept-specifier if it's part of the canonical // type. libstdc++ relies on this. - Expr *NoexceptExpr = FunctionProtoParam->getNoexceptExpr(); + Expr *NoexceptExpr = FPP->getNoexceptExpr(); if (const NonTypeTemplateParmDecl *NTTP = - NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) - : nullptr) { + NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) + : nullptr) { assert(NTTP->getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); llvm::APSInt Noexcept(1); - switch (FunctionProtoArg->canThrow()) { + switch (FPA->canThrow()) { case CT_Cannot: Noexcept = 1; LLVM_FALLTHROUGH; @@ -1849,10 +1782,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // FIXME: Should we? return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, Noexcept, S.Context.BoolTy, - /*ArrayBound*/true, Info, Deduced); + /*DeducedFromArrayBound=*/true, Info, Deduced); case CT_Dependent: - if (Expr *ArgNoexceptExpr = FunctionProtoArg->getNoexceptExpr()) + if (Expr *ArgNoexceptExpr = FPA->getNoexceptExpr()) return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgNoexceptExpr, Info, Deduced); // Can't deduce anything from throw(T...). @@ -1870,11 +1803,6 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::InjectedClassName: // Treat a template's injected-class-name as if the template // specialization type had been used. - Param = cast(Param) - ->getInjectedSpecializationType(); - assert(isa(Param) && - "injected class name is not a template specialization type"); - LLVM_FALLTHROUGH; // template-name (where template-name refers to a class template) // template-name @@ -1882,41 +1810,33 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // TT // TT<> case Type::TemplateSpecialization: { - const TemplateSpecializationType *SpecParam = - cast(Param); - // When Arg cannot be a derived class, we can just try to deduce template // arguments from the template-id. - const RecordType *RecordT = Arg->getAs(); - if (!(TDF & TDF_DerivedClass) || !RecordT) - return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, - Deduced); + if (!(TDF & TDF_DerivedClass) || !A->isRecordType()) + return DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, + Deduced); SmallVector DeducedOrig(Deduced.begin(), Deduced.end()); - Sema::TemplateDeductionResult Result = DeduceTemplateArguments( - S, TemplateParams, SpecParam, Arg, Info, Deduced); - + auto Result = + DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced); if (Result == Sema::TDK_Success) return Result; // We cannot inspect base classes as part of deduction when the type // is incomplete, so either instantiate any templates necessary to // complete the type, or skip over it if it cannot be completed. - if (!S.isCompleteType(Info.getLocation(), Arg)) + if (!S.isCompleteType(Info.getLocation(), A)) return Result; // Reset the incorrectly deduced argument from above. Deduced = DeducedOrig; // Check bases according to C++14 [temp.deduct.call] p4b3: - Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases( - S, RecordT, TemplateParams, SpecParam, Info, Deduced); - - if (BaseResult != Sema::TDK_Invalid) - return BaseResult; - return Result; + auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A), + TemplateParams, P, Info, Deduced); + return BaseResult != Sema::TDK_Invalid ? BaseResult : Result; } // T type::* @@ -1929,33 +1849,27 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T (T::*)() // T (T::*)(T) case Type::MemberPointer: { - const MemberPointerType *MemPtrParam = cast(Param); - const MemberPointerType *MemPtrArg = dyn_cast(Arg); - if (!MemPtrArg) + const auto *MPP = P->castAs(), + *MPA = A->getAs(); + if (!MPA) return Sema::TDK_NonDeducedMismatch; - QualType ParamPointeeType = MemPtrParam->getPointeeType(); - if (ParamPointeeType->isFunctionType()) - S.adjustMemberFunctionCC(ParamPointeeType, /*IsStatic=*/true, + QualType PPT = MPP->getPointeeType(); + if (PPT->isFunctionType()) + S.adjustMemberFunctionCC(PPT, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - QualType ArgPointeeType = MemPtrArg->getPointeeType(); - if (ArgPointeeType->isFunctionType()) - S.adjustMemberFunctionCC(ArgPointeeType, /*IsStatic=*/true, + QualType APT = MPA->getPointeeType(); + if (APT->isFunctionType()) + S.adjustMemberFunctionCC(APT, /*IsStatic=*/true, /*IsCtorOrDtor=*/false, Info.getLocation()); - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - ParamPointeeType, - ArgPointeeType, - Info, Deduced, - TDF & TDF_IgnoreQualifiers)) + unsigned SubTDF = TDF & TDF_IgnoreQualifiers; + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, PPT, APT, Info, Deduced, SubTDF)) return Result; - - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - QualType(MemPtrParam->getClass(), 0), - QualType(MemPtrArg->getClass(), 0), - Info, Deduced, - TDF & TDF_IgnoreQualifiers); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, QualType(MPP->getClass(), 0), + QualType(MPA->getClass(), 0), Info, Deduced, SubTDF); } // (clang extension) @@ -1964,70 +1878,58 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T(^)() // T(^)(T) case Type::BlockPointer: { - const BlockPointerType *BlockPtrParam = cast(Param); - const BlockPointerType *BlockPtrArg = dyn_cast(Arg); - - if (!BlockPtrArg) + const auto *BPP = P->castAs(), + *BPA = A->getAs(); + if (!BPA) return Sema::TDK_NonDeducedMismatch; - - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - BlockPtrParam->getPointeeType(), - BlockPtrArg->getPointeeType(), - Info, Deduced, 0); + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, + Deduced, 0); } // (clang extension) // // T __attribute__(((ext_vector_type()))) case Type::ExtVector: { - const ExtVectorType *VectorParam = cast(Param); - if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { + const auto *VP = P->castAs(); + QualType ElementType; + if (const auto *VA = A->getAs()) { // Make sure that the vectors have the same number of elements. - if (VectorParam->getNumElements() != VectorArg->getNumElements()) + if (VP->getNumElements() != VA->getNumElements()) return Sema::TDK_NonDeducedMismatch; - - // Perform deduction on the element types. - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF); - } - - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast(Arg)) { + ElementType = VA->getElementType(); + } else if (const auto *VA = A->getAs()) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial // ordering. - - // Perform deduction on the element types. - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF); + ElementType = VA->getElementType(); + } else { + return Sema::TDK_NonDeducedMismatch; } - - return Sema::TDK_NonDeducedMismatch; + // Perform deduction on the element types. + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), ElementType, Info, Deduced, + TDF); } case Type::DependentVector: { - const auto *VectorParam = cast(Param); + const auto *VP = P->castAs(); - if (const auto *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VectorParam->getElementType(), - VectorArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VectorArg->getNumElements(); + ArgSize = VA->getNumElements(); // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. @@ -2036,22 +1938,21 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, Info, Deduced); } - if (const auto *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, VectorParam->getElementType(), - VectorArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, VectorParam->getSizeExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, VectorArg->getSizeExpr(), Info, Deduced); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + VA->getSizeExpr(), Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -2061,26 +1962,23 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // // T __attribute__(((ext_vector_type(N)))) case Type::DependentSizedExtVector: { - const DependentSizedExtVectorType *VectorParam - = cast(Param); + const auto *VP = P->castAs(); - if (const ExtVectorType *VectorArg = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = VectorArg->getNumElements(); + ArgSize = VA->getNumElements(); // Note that we use the "array bound" rules here; just like in that // case, we don't have any particular type for the vector size, but // we can provide one if necessary. @@ -2089,25 +1987,21 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, Deduced); } - if (const DependentSizedExtVectorType *VectorArg - = dyn_cast(Arg)) { + if (const auto *VA = A->getAs()) { // Perform deduction on the element types. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - VectorParam->getElementType(), - VectorArg->getElementType(), - Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, VP->getElementType(), VA->getElementType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); + getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - VectorArg->getSizeExpr(), - Info, Deduced); + VA->getSizeExpr(), Info, Deduced); } return Sema::TDK_NonDeducedMismatch; @@ -2118,62 +2012,59 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // T __attribute__((matrix_type(, // ))) case Type::ConstantMatrix: { - const ConstantMatrixType *MatrixArg = dyn_cast(Arg); - if (!MatrixArg) + const auto *MP = P->castAs(), + *MA = A->getAs(); + if (!MA) return Sema::TDK_NonDeducedMismatch; - const ConstantMatrixType *MatrixParam = cast(Param); // Check that the dimensions are the same - if (MatrixParam->getNumRows() != MatrixArg->getNumRows() || - MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) { + if (MP->getNumRows() != MA->getNumRows() || + MP->getNumColumns() != MA->getNumColumns()) { return Sema::TDK_NonDeducedMismatch; } // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MatrixParam->getElementType(), - MatrixArg->getElementType(), Info, Deduced, TDF); + S, TemplateParams, MP->getElementType(), MA->getElementType(), Info, + Deduced, TDF); } case Type::DependentSizedMatrix: { - const MatrixType *MatrixArg = dyn_cast(Arg); - if (!MatrixArg) + const auto *MP = P->castAs(); + const auto *MA = A->getAs(); + if (!MA) return Sema::TDK_NonDeducedMismatch; // Check the element type of the matrixes. - const DependentSizedMatrixType *MatrixParam = - cast(Param); - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, MatrixParam->getElementType(), - MatrixArg->getElementType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, MP->getElementType(), MA->getElementType(), + Info, Deduced, TDF)) return Result; // Try to deduce a matrix dimension. auto DeduceMatrixArg = [&S, &Info, &Deduced, &TemplateParams]( - Expr *ParamExpr, const MatrixType *Arg, + Expr *ParamExpr, const MatrixType *A, unsigned (ConstantMatrixType::*GetArgDimension)() const, Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { - const auto *ArgConstMatrix = dyn_cast(Arg); - const auto *ArgDepMatrix = dyn_cast(Arg); + const auto *ACM = dyn_cast(A); + const auto *ADM = dyn_cast(A); if (!ParamExpr->isValueDependent()) { Optional ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) return Sema::TDK_NonDeducedMismatch; - if (ArgConstMatrix) { - if ((ArgConstMatrix->*GetArgDimension)() == *ParamConst) + if (ACM) { + if ((ACM->*GetArgDimension)() == *ParamConst) return Sema::TDK_Success; return Sema::TDK_NonDeducedMismatch; } - Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)(); - if (!ArgExpr->isValueDependent()) - if (Optional ArgConst = - ArgExpr->getIntegerConstantExpr(S.Context)) - if (*ArgConst == *ParamConst) - return Sema::TDK_Success; + Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); + if (Optional ArgConst = + ArgExpr->getIntegerConstantExpr(S.Context)) + if (*ArgConst == *ParamConst) + return Sema::TDK_Success; return Sema::TDK_NonDeducedMismatch; } @@ -2182,27 +2073,26 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (!NTTP) return Sema::TDK_Success; - if (ArgConstMatrix) { + if (ACM) { llvm::APSInt ArgConst( S.Context.getTypeSize(S.Context.getSizeType())); - ArgConst = (ArgConstMatrix->*GetArgDimension)(); + ArgConst = (ACM->*GetArgDimension)(); return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); } - return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(), - Info, Deduced); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + (ADM->*GetArgDimensionExpr)(), + Info, Deduced); }; - auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg, - &ConstantMatrixType::getNumRows, - &DependentSizedMatrixType::getRowExpr); - if (Result) + if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, + &ConstantMatrixType::getNumRows, + &DependentSizedMatrixType::getRowExpr)) return Result; - return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg, + return DeduceMatrixArg(MP->getColumnExpr(), MA, &ConstantMatrixType::getNumColumns, &DependentSizedMatrixType::getColumnExpr); } @@ -2211,44 +2101,39 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // // T __attribute__(((address_space(N)))) case Type::DependentAddressSpace: { - const DependentAddressSpaceType *AddressSpaceParam = - cast(Param); + const auto *ASP = P->castAs(); - if (const DependentAddressSpaceType *AddressSpaceArg = - dyn_cast(Arg)) { + if (const auto *ASA = A->getAs()) { // Perform deduction on the pointer type. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, AddressSpaceParam->getPointeeType(), - AddressSpaceArg->getPointeeType(), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), + Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, AddressSpaceParam->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; return DeduceNonTypeTemplateArgument( - S, TemplateParams, NTTP, AddressSpaceArg->getAddrSpaceExpr(), Info, - Deduced); + S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced); } - if (isTargetAddressSpace(Arg.getAddressSpace())) { + if (isTargetAddressSpace(A.getAddressSpace())) { llvm::APSInt ArgAddressSpace(S.Context.getTypeSize(S.Context.IntTy), false); - ArgAddressSpace = toTargetAddressSpace(Arg.getAddressSpace()); + ArgAddressSpace = toTargetAddressSpace(A.getAddressSpace()); // Perform deduction on the pointer types. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, AddressSpaceParam->getPointeeType(), - S.Context.removeAddrSpaceQualType(Arg), Info, Deduced, TDF)) + if (auto Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, ASP->getPointeeType(), + S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF)) return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr( - Info, AddressSpaceParam->getAddrSpaceExpr()); + const NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return Sema::TDK_Success; @@ -2260,30 +2145,31 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_NonDeducedMismatch; } case Type::DependentExtInt: { - const auto *IntParam = cast(Param); + const auto *IP = P->castAs(); - if (const auto *IntArg = dyn_cast(Arg)){ - if (IntParam->isUnsigned() != IntArg->isUnsigned()) + if (const auto *IA = A->getAs()) { + if (IP->isUnsigned() != IA->isUnsigned()) return Sema::TDK_NonDeducedMismatch; const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr()); + getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); - ArgSize = IntArg->getNumBits(); + ArgSize = IA->getNumBits(); return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info, Deduced); } - if (const auto *IntArg = dyn_cast(Arg)) { - if (IntParam->isUnsigned() != IntArg->isUnsigned()) + if (const auto *IA = A->getAs()) { + if (IP->isUnsigned() != IA->isUnsigned()) return Sema::TDK_NonDeducedMismatch; return Sema::TDK_Success; } + return Sema::TDK_NonDeducedMismatch; } @@ -2293,125 +2179,103 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::UnresolvedUsing: case Type::Decltype: case Type::UnaryTransform: - case Type::Auto: case Type::DeducedTemplateSpecialization: case Type::DependentTemplateSpecialization: case Type::PackExpansion: case Type::Pipe: // No template argument deduction for these types return Sema::TDK_Success; - } + } llvm_unreachable("Invalid Type Class!"); } static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, - const TemplateArgument &Param, - TemplateArgument Arg, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, + const TemplateArgument &P, TemplateArgument A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { // If the template argument is a pack expansion, perform template argument // deduction against the pattern of that expansion. This only occurs during // partial ordering. - if (Arg.isPackExpansion()) - Arg = Arg.getPackExpansionPattern(); + if (A.isPackExpansion()) + A = A.getPackExpansionPattern(); - switch (Param.getKind()) { + switch (P.getKind()) { case TemplateArgument::Null: llvm_unreachable("Null template argument in parameter list"); case TemplateArgument::Type: - if (Arg.getKind() == TemplateArgument::Type) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - Param.getAsType(), - Arg.getAsType(), - Info, Deduced, 0); - Info.FirstArg = Param; - Info.SecondArg = Arg; + if (A.getKind() == TemplateArgument::Type) + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0); + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Template: - if (Arg.getKind() == TemplateArgument::Template) - return DeduceTemplateArguments(S, TemplateParams, - Param.getAsTemplate(), - Arg.getAsTemplate(), Info, Deduced); - Info.FirstArg = Param; - Info.SecondArg = Arg; + if (A.getKind() == TemplateArgument::Template) + return DeduceTemplateArguments(S, TemplateParams, P.getAsTemplate(), + A.getAsTemplate(), Info, Deduced); + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::TemplateExpansion: llvm_unreachable("caller should handle pack expansions"); case TemplateArgument::Declaration: - if (Arg.getKind() == TemplateArgument::Declaration && - isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) + if (A.getKind() == TemplateArgument::Declaration && + isSameDeclaration(P.getAsDecl(), A.getAsDecl())) return Sema::TDK_Success; - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::NullPtr: - if (Arg.getKind() == TemplateArgument::NullPtr && - S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType())) + if (A.getKind() == TemplateArgument::NullPtr && + S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType())) return Sema::TDK_Success; - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Integral: - if (Arg.getKind() == TemplateArgument::Integral) { - if (hasSameExtendedValue(Param.getAsIntegral(), Arg.getAsIntegral())) + if (A.getKind() == TemplateArgument::Integral) { + if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral())) return Sema::TDK_Success; - - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; } - - if (Arg.getKind() == TemplateArgument::Expression) { - Info.FirstArg = Param; - Info.SecondArg = Arg; - return Sema::TDK_NonDeducedMismatch; - } - - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; case TemplateArgument::Expression: if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, Param.getAsExpr())) { - if (Arg.getKind() == TemplateArgument::Integral) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsIntegral(), - Arg.getIntegralType(), - /*ArrayBound=*/false, - Info, Deduced); - if (Arg.getKind() == TemplateArgument::NullPtr) + getDeducedParameterFromExpr(Info, P.getAsExpr())) { + if (A.getKind() == TemplateArgument::Integral) + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, A.getAsIntegral(), A.getIntegralType(), + /*ArrayBound=*/false, Info, Deduced); + if (A.getKind() == TemplateArgument::NullPtr) return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, - Arg.getNullPtrType(), - Info, Deduced); - if (Arg.getKind() == TemplateArgument::Expression) + A.getNullPtrType(), Info, Deduced); + if (A.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsExpr(), Info, Deduced); - if (Arg.getKind() == TemplateArgument::Declaration) - return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, - Arg.getAsDecl(), - Arg.getParamTypeForDecl(), - Info, Deduced); + A.getAsExpr(), Info, Deduced); + if (A.getKind() == TemplateArgument::Declaration) + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, A.getAsDecl(), A.getParamTypeForDecl(), + Info, Deduced); - Info.FirstArg = Param; - Info.SecondArg = Arg; + Info.FirstArg = P; + Info.SecondArg = A; return Sema::TDK_NonDeducedMismatch; } // Can't deduce anything, but that's okay. return Sema::TDK_Success; - case TemplateArgument::Pack: llvm_unreachable("Argument packs should be expanded by the caller!"); } @@ -2464,8 +2328,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef Args) { static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - ArrayRef Params, - ArrayRef Args, + ArrayRef Ps, + ArrayRef As, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, bool NumberOfArgumentsMustMatch) { @@ -2473,7 +2337,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - if (hasPackExpansionBeforeEnd(Params)) + if (hasPackExpansionBeforeEnd(Ps)) return Sema::TDK_Success; // C++0x [temp.deduct.type]p9: @@ -2481,12 +2345,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. unsigned ArgIdx = 0, ParamIdx = 0; - for (; hasTemplateArgumentForDeduction(Params, ParamIdx); ++ParamIdx) { - if (!Params[ParamIdx].isPackExpansion()) { + for (; hasTemplateArgumentForDeduction(Ps, ParamIdx); ++ParamIdx) { + const TemplateArgument &P = Ps[ParamIdx]; + if (!P.isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. - if (!hasTemplateArgumentForDeduction(Args, ArgIdx)) + if (!hasTemplateArgumentForDeduction(As, ArgIdx)) return NumberOfArgumentsMustMatch ? Sema::TDK_MiscellaneousDeductionFailure : Sema::TDK_Success; @@ -2494,14 +2359,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // C++1z [temp.deduct.type]p9: // During partial ordering, if Ai was originally a pack expansion [and] // Pi is not a pack expansion, template argument deduction fails. - if (Args[ArgIdx].isPackExpansion()) + if (As[ArgIdx].isPackExpansion()) return Sema::TDK_MiscellaneousDeductionFailure; // Perform deduction for this Pi/Ai pair. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, - Params[ParamIdx], Args[ArgIdx], - Info, Deduced)) + if (auto Result = DeduceTemplateArguments(S, TemplateParams, P, + As[ArgIdx], Info, Deduced)) return Result; // Move to the next argument. @@ -2516,7 +2379,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // each remaining argument in the template argument list of A. Each // comparison deduces template arguments for subsequent positions in the // template parameter packs expanded by Pi. - TemplateArgument Pattern = Params[ParamIdx].getPackExpansionPattern(); + TemplateArgument Pattern = P.getPackExpansionPattern(); // Prepare to deduce the packs within the pattern. PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); @@ -2524,13 +2387,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Keep track of the deduced template arguments for each parameter pack // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). - for (; hasTemplateArgumentForDeduction(Args, ArgIdx) && + for (; hasTemplateArgumentForDeduction(As, ArgIdx) && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], - Info, Deduced)) + if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern, + As[ArgIdx], Info, Deduced)) return Result; PackScope.nextPackElement(); @@ -2546,15 +2408,14 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgumentList &ParamList, const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(), ArgList.asArray(), Info, Deduced, - /*NumberOfArgumentsMustMatch*/false); + /*NumberOfArgumentsMustMatch=*/false); } /// Determine whether two template arguments are the same. @@ -2858,9 +2719,24 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( return Sema::TDK_Incomplete; } - TemplateArgumentLoc DefArg = S.SubstDefaultTemplateArgumentIfAvailable( - TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, - HasDefaultArg); + TemplateArgumentLoc DefArg; + { + Qualifiers ThisTypeQuals; + CXXRecordDecl *ThisContext = nullptr; + if (auto *Rec = dyn_cast(TD->getDeclContext())) + if (Rec->isLambda()) + if (auto *Method = dyn_cast(Rec->getDeclContext())) { + ThisContext = Method->getParent(); + ThisTypeQuals = Method->getMethodQualifiers(); + } + + Sema::CXXThisScopeRAII ThisScope(S, ThisContext, ThisTypeQuals, + S.getLangOpts().CPlusPlus17); + + DefArg = S.SubstDefaultTemplateArgumentIfAvailable( + TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, + HasDefaultArg); + } // If there was no default argument, deduction is incomplete. if (DefArg.getArgument().isNull()) { @@ -2964,14 +2840,13 @@ FinishTemplateArgumentDeduction( auto *Template = Partial->getSpecializedTemplate(); const ASTTemplateArgumentListInfo *PartialTemplArgInfo = Partial->getTemplateArgsAsWritten(); - const TemplateArgumentLoc *PartialTemplateArgs = - PartialTemplArgInfo->getTemplateArgs(); TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); - if (S.Subst(PartialTemplateArgs, PartialTemplArgInfo->NumTemplateArgs, - InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + if (S.SubstTemplateArguments( + PartialTemplArgInfo->arguments(), + MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) { unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; @@ -2979,7 +2854,7 @@ FinishTemplateArgumentDeduction( Decl *Param = const_cast( Partial->getTemplateParameters()->getParam(ParamIdx)); Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); + Info.FirstArg = (*PartialTemplArgInfo)[ArgIdx].getArgument(); return Sema::TDK_SubstitutionFailure; } @@ -3879,8 +3754,9 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( // "lvalue reference to A" is used in place of A for type deduction. if (isForwardingReference(QualType(ParamRefType, 0), FirstInnerIndex) && Arg->isLValue()) { - if (S.getLangOpts().OpenCL && !ArgType.hasAddressSpace()) - ArgType = S.Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); + if (S.getLangOpts().OpenCL && !ArgType.hasAddressSpace()) + ArgType = S.Context.getAddrSpaceQualType( + ArgType, S.Context.getDefaultOpenCLPointeeAddrSpace()); ArgType = S.Context.getLValueReferenceType(ArgType); } } else { @@ -4342,11 +4218,11 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( bool HasDeducedReturnType = false; if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { - FunctionType = SubstAutoType(FunctionType, Context.DependentTy); + FunctionType = SubstAutoTypeDependent(FunctionType); HasDeducedReturnType = true; } - if (!ArgFunctionType.isNull()) { + if (!ArgFunctionType.isNull() && !FunctionType.isNull()) { unsigned TDF = TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType; // Deduce template arguments from the function type. @@ -4776,12 +4652,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, ExprResult ER = CheckPlaceholderExpr(Init); if (ER.isInvalid()) return DAR_FailedAlreadyDiagnosed; - Init = ER.get(); - QualType Deduced = BuildDecltypeType(Init, Init->getBeginLoc(), false); - if (Deduced.isNull()) - return DAR_FailedAlreadyDiagnosed; - // FIXME: Support a non-canonical deduced type for 'auto'. - Deduced = Context.getCanonicalType(Deduced); + QualType Deduced = getDecltypeForExpr(ER.get()); + assert(!Deduced.isNull()); if (AT->isConstrained() && !IgnoreConstraints) { auto ConstraintsResult = CheckDeducedPlaceholderConstraints(*this, *AT, @@ -4816,7 +4688,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) + SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) .Apply(Type); assert(!FuncParam.isNull() && "substituting template parameter for 'auto' failed"); @@ -4930,27 +4802,29 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } TypeSourceInfo *Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - if (TypeToReplaceAuto->isDependentType()) - return SubstituteDeducedTypeTransform( - *this, - DependentAuto{ - TypeToReplaceAuto->containsUnexpandedParameterPack()}) - .TransformType(TypeWithAuto); + assert(TypeToReplaceAuto != Context.DependentTy); return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto) .TransformType(TypeWithAuto); } +QualType Sema::SubstAutoTypeDependent(QualType TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + +TypeSourceInfo * +Sema::SubstAutoTypeSourceInfoDependent(TypeSourceInfo *TypeWithAuto) { + return SubstituteDeducedTypeTransform(*this, DependentAuto{false}) + .TransformType(TypeWithAuto); +} + QualType Sema::ReplaceAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { return SubstituteDeducedTypeTransform(*this, TypeToReplaceAuto, @@ -5145,6 +5019,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); + if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index f18f77d3442..7d4c000e7e9 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -161,10 +161,9 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) break; - } else if (FunctionTemplateDecl *FunTmpl - = Function->getDescribedFunctionTemplate()) { - // Add the "injected" template arguments. - Result.addOuterTemplateArguments(FunTmpl->getInjectedTemplateArgs()); + } else if (Function->getDescribedFunctionTemplate()) { + assert(Result.getNumSubstitutedLevels() == 0 && + "Outer template not instantiated?"); } // If this is a friend declaration and it declares an entity at @@ -180,11 +179,8 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, } } else if (CXXRecordDecl *Rec = dyn_cast(Ctx)) { if (ClassTemplateDecl *ClassTemplate = Rec->getDescribedClassTemplate()) { - QualType T = ClassTemplate->getInjectedClassNameSpecialization(); - const TemplateSpecializationType *TST = - cast(Context.getCanonicalType(T)); - Result.addOuterTemplateArguments( - llvm::makeArrayRef(TST->getArgs(), TST->getNumArgs())); + assert(Result.getNumSubstitutedLevels() == 0 && + "Outer template not instantiated?"); if (ClassTemplate->isMemberSpecialization()) break; } @@ -1934,25 +1930,23 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { return Req; Sema::SFINAETrap Trap(SemaRef); - TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc()); llvm::PointerUnion TransExpr; if (Req->isExprSubstitutionFailure()) TransExpr = Req->getExprSubstitutionDiagnostic(); else { - Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(), - Req, Info, - Req->getExpr()->getSourceRange()); + Expr *E = Req->getExpr(); + TemplateDeductionInfo Info(E->getBeginLoc()); + Sema::InstantiatingTemplate ExprInst(SemaRef, E->getBeginLoc(), Req, Info, + E->getSourceRange()); if (ExprInst.isInvalid()) return nullptr; - ExprResult TransExprRes = TransformExpr(Req->getExpr()); + ExprResult TransExprRes = TransformExpr(E); if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) - TransExpr = createSubstDiag(SemaRef, Info, - [&] (llvm::raw_ostream& OS) { - Req->getExpr()->printPretty(OS, nullptr, - SemaRef.getPrintingPolicy()); - }); + TransExpr = createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) { + E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); + }); else TransExpr = TransExprRes.get(); } @@ -1966,6 +1960,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { else if (RetReq.isTypeConstraint()) { TemplateParameterList *OrigTPL = RetReq.getTypeConstraintTemplateParameterList(); + TemplateDeductionInfo Info(OrigTPL->getTemplateLoc()); Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), Req, Info, OrigTPL->getSourceRange()); if (TPLInst.isInvalid()) @@ -2309,6 +2304,29 @@ namespace { } // namespace +bool Sema::SubstTypeConstraint( + TemplateTypeParmDecl *Inst, const TypeConstraint *TC, + const MultiLevelTemplateArgumentList &TemplateArgs) { + const ASTTemplateArgumentListInfo *TemplArgInfo = + TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs, + InstArgs)) + return true; + } + return AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + Inst->isParameterPack() + ? cast(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation()); +} + ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -2373,24 +2391,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, if (Inst && !Inst->getTypeConstraint()) { // TODO: Concepts: do not instantiate the constraint (delayed constraint // substitution) - const ASTTemplateArgumentListInfo *TemplArgInfo - = TC->getTemplateArgsAsWritten(); - TemplateArgumentListInfo InstArgs; - - if (TemplArgInfo) { - InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); - InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs)) - return nullptr; - } - if (AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), TemplArgInfo ? &InstArgs : nullptr, Inst, - TTP->isParameterPack() - ? cast(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation())) + if (SubstTypeConstraint(Inst, TC, TemplateArgs)) return nullptr; } } @@ -3538,15 +3539,6 @@ Sema::SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, return Instantiator.TransformTemplateName(SS, Name, Loc); } -bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, - TemplateArgumentListInfo &Result, - const MultiLevelTemplateArgumentList &TemplateArgs) { - TemplateInstantiator Instantiator(*this, TemplateArgs, SourceLocation(), - DeclarationName()); - - return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); -} - static const Decl *getCanonicalParmVarDecl(const Decl *D) { // When storing ParmVarDecls in the local instantiation scope, we always // want to use the ParmVarDecl from the canonical function declaration, @@ -3666,7 +3658,7 @@ void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { bool LocalInstantiationScope::isLocalPackExpansion(const Decl *D) { for (DeclArgumentPack *Pack : ArgumentPacks) - if (std::find(Pack->begin(), Pack->end(), D) != Pack->end()) + if (llvm::is_contained(*Pack, D)) return true; return false; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index be4c5193078..27ac2cd08f2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -436,11 +436,12 @@ static void instantiateOMPDeclareVariantAttr( return; Expr *E = VariantFuncRef.get(); + // Check function/variant ref for `omp declare variant` but not for `omp // begin declare variant` (which use implicit attributes). Optional> DeclVarData = - S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), - VariantFuncRef.get(), TI, + S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI, + Attr.appendArgs_size(), Attr.getRange()); if (!DeclVarData) @@ -481,7 +482,28 @@ static void instantiateOMPDeclareVariantAttr( } } - S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, Attr.getRange()); + SmallVector NothingExprs; + SmallVector NeedDevicePtrExprs; + SmallVector AppendArgs; + + for (Expr *E : Attr.adjustArgsNothing()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NothingExprs.push_back(ER.get()); + } + for (Expr *E : Attr.adjustArgsNeedDevicePtr()) { + ExprResult ER = Subst(E); + if (ER.isInvalid()) + continue; + NeedDevicePtrExprs.push_back(ER.get()); + } + for (auto A : Attr.appendArgs()) + AppendArgs.push_back(A); + + S.ActOnOpenMPDeclareVariantDirective( + FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(), + SourceLocation(), Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( @@ -556,30 +578,10 @@ static void instantiateDependentAMDGPUWavesPerEUAttr( static void instantiateDependentSYCLKernelAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const SYCLKernelAttr &Attr, Decl *New) { - // Functions cannot be partially specialized, so if we are being instantiated, - // we are obviously a complete specialization. Since this attribute is only - // valid on function template declarations, we know that this is a full - // instantiation of a kernel. - S.AddSYCLKernelLambda(cast(New)); - - // Evaluate whether this would change any of the already evaluated - // __builtin_sycl_unique_stable_name values. - for (auto &Itr : S.Context.SYCLUniqueStableNameEvaluatedValues) { - const std::string &CurName = Itr.first->ComputeName(S.Context); - if (Itr.second != CurName) { - S.Diag(New->getLocation(), - diag::err_kernel_invalidates_sycl_unique_stable_name); - S.Diag(Itr.first->getLocation(), - diag::note_sycl_unique_stable_name_evaluated_here); - // Update this so future diagnostics work correctly. - Itr.second = CurName; - } - } - New->addAttr(Attr.clone(S.getASTContext())); } -/// Determine whether the attribute A might be relevent to the declaration D. +/// Determine whether the attribute A might be relevant to the declaration D. /// If not, we can skip instantiating it. The attribute may or may not have /// been instantiated yet. static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { @@ -1087,7 +1089,7 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, Owner, StartingScope, InstantiatingVarTemplate); - if (D->isNRVOVariable()) { + if (D->isNRVOVariable() && !Var->isInvalidDecl()) { QualType RT; if (auto *F = dyn_cast(DC)) RT = F->getReturnType(); @@ -1816,9 +1818,7 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = nullptr; - if (D->isInjectedClassName()) - PrevDecl = cast(Owner); - else if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) { + if (CXXRecordDecl *PatternPrev = getPreviousDeclForInstantiation(D)) { NamedDecl *Prev = SemaRef.FindInstantiatedDecl(D->getLocation(), PatternPrev, TemplateArgs); @@ -1827,6 +1827,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { } CXXRecordDecl *Record = nullptr; + bool IsInjectedClassName = D->isInjectedClassName(); if (D->isLambda()) Record = CXXRecordDecl::CreateLambda( SemaRef.Context, Owner, D->getLambdaTypeInfo(), D->getLocation(), @@ -1835,7 +1836,11 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { else Record = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, D->getBeginLoc(), D->getLocation(), - D->getIdentifier(), PrevDecl); + D->getIdentifier(), PrevDecl, + /*DelayTypeCreation=*/IsInjectedClassName); + // Link the type of the injected-class-name to that of the outer class. + if (IsInjectedClassName) + (void)SemaRef.Context.getTypeDeclType(Record, cast(Owner)); // Substitute the nested name specifier, if any. if (SubstQualifier(D, Record)) @@ -1850,7 +1855,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { // specifier. Remove once this area of the code gets sorted out. if (D->getAccess() != AS_none) Record->setAccess(D->getAccess()); - if (!D->isInjectedClassName()) + if (!IsInjectedClassName) Record->setInstantiationOfMemberClass(D, TSK_ImplicitInstantiation); // If the original function was part of a friend declaration, @@ -1903,6 +1908,9 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { SemaRef.DiagnoseUnusedNestedTypedefs(Record); + if (IsInjectedClassName) + assert(Record->isInjectedClassName() && "Broken injected-class-name"); + return Record; } @@ -2051,8 +2059,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( } else { Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, - D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->getConstexprKind(), + D->getCanonicalDecl()->getStorageClass(), D->UsesFPIntrin(), + D->isInlineSpecified(), D->hasWrittenPrototype(), D->getConstexprKind(), TrailingRequiresClause); Function->setRangeEnd(D->getSourceRange().getEnd()); } @@ -2149,8 +2157,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Instantiate the explicit template arguments. TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), Info->getRAngleLoc()); - if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), - ExplicitArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + ExplicitArgs)) return nullptr; // Map the candidate templates to their instantiations. @@ -2177,8 +2185,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Instantiate the explicit template arguments. TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), Info->getRAngleLoc()); - if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), - ExplicitArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + ExplicitArgs)) return nullptr; if (SemaRef.CheckFunctionTemplateSpecialization(Function, @@ -2407,15 +2415,16 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (CXXConstructorDecl *Constructor = dyn_cast(D)) { Method = CXXConstructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false, + InstantiatedExplicitSpecifier, Constructor->UsesFPIntrin(), + Constructor->isInlineSpecified(), false, Constructor->getConstexprKind(), InheritedConstructor(), TrailingRequiresClause); Method->setRangeEnd(Constructor->getEndLoc()); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Destructor->isInlineSpecified(), false, Destructor->getConstexprKind(), - TrailingRequiresClause); + Destructor->UsesFPIntrin(), Destructor->isInlineSpecified(), false, + Destructor->getConstexprKind(), TrailingRequiresClause); Method->setRangeEnd(Destructor->getEndLoc()); Method->setDeclName(SemaRef.Context.DeclarationNames.getCXXDestructorName( SemaRef.Context.getCanonicalType( @@ -2423,15 +2432,15 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( } else if (CXXConversionDecl *Conversion = dyn_cast(D)) { Method = CXXConversionDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier, - Conversion->getConstexprKind(), Conversion->getEndLoc(), - TrailingRequiresClause); + Conversion->UsesFPIntrin(), Conversion->isInlineSpecified(), + InstantiatedExplicitSpecifier, Conversion->getConstexprKind(), + Conversion->getEndLoc(), TrailingRequiresClause); } else { StorageClass SC = D->isStatic() ? SC_Static : SC_None; - Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, - T, TInfo, SC, D->isInlineSpecified(), - D->getConstexprKind(), D->getEndLoc(), - TrailingRequiresClause); + Method = CXXMethodDecl::Create( + SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, + D->UsesFPIntrin(), D->isInlineSpecified(), D->getConstexprKind(), + D->getEndLoc(), TrailingRequiresClause); } if (D->isInlined()) @@ -2512,8 +2521,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // Instantiate the explicit template arguments. TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), Info->getRAngleLoc()); - if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), - ExplicitArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + ExplicitArgs)) return nullptr; // Map the candidate templates to their instantiations. @@ -2539,8 +2548,8 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), Info->getRAngleLoc()); - if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(), - ExplicitArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + ExplicitArgs)) return nullptr; if (SemaRef.CheckFunctionTemplateSpecialization(Method, @@ -2708,25 +2717,7 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( // TODO: Concepts: do not instantiate the constraint (delayed constraint // substitution) - const ASTTemplateArgumentListInfo *TemplArgInfo - = TC->getTemplateArgsAsWritten(); - TemplateArgumentListInfo InstArgs; - - if (TemplArgInfo) { - InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); - InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, - InstArgs, TemplateArgs)) - return nullptr; - } - if (SemaRef.AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &InstArgs, Inst, - D->isParameterPack() - ? cast(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation())) + if (SemaRef.SubstTypeConstraint(Inst, TC, TemplateArgs)) return nullptr; } } @@ -3380,12 +3371,23 @@ Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) { SmallVector Clauses; // Copy map clauses from the original mapper. for (OMPClause *C : D->clauselists()) { - auto *AC = cast(C); - ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); - if (!NewE.isUsable()) - continue; - OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause( - NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + OMPClause *IC = nullptr; + if (auto *AC = dyn_cast(C)) { + ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs); + if (!NewE.isUsable()) + continue; + IC = SemaRef.ActOnOpenMPAllocatorClause( + NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc()); + } else if (auto *AC = dyn_cast(C)) { + ExprResult NewE = SemaRef.SubstExpr(AC->getAlignment(), TemplateArgs); + if (!NewE.isUsable()) + continue; + IC = SemaRef.ActOnOpenMPAlignClause(NewE.get(), AC->getBeginLoc(), + AC->getLParenLoc(), AC->getEndLoc()); + // If align clause value ends up being invalid, this can end up null. + if (!IC) + continue; + } Clauses.push_back(IC); } @@ -3624,8 +3626,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( SmallVector ArgLocs; for (unsigned I = 0; I != Loc.getNumArgs(); ++I) ArgLocs.push_back(Loc.getArgLoc(I)); - if (SemaRef.Subst(ArgLocs.data(), ArgLocs.size(), - InstTemplateArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(ArgLocs, TemplateArgs, InstTemplateArgs)) return nullptr; // Check that the template argument list is well-formed for this @@ -3750,8 +3751,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc()); - if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(), - TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(TemplateArgsInfo.arguments(), TemplateArgs, + VarTemplateArgsInfo)) return nullptr; // Check that the template argument list is well-formed for this template. @@ -4018,9 +4019,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( = PartialSpec->getTemplateArgsAsWritten(); TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc, TemplArgInfo->RAngleLoc); - if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, - InstTemplateArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs, + InstTemplateArgs)) return nullptr; // Check that the template argument list is well-formed for this @@ -4146,9 +4146,8 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( = PartialSpec->getTemplateArgsAsWritten(); TemplateArgumentListInfo InstTemplateArgs(TemplArgInfo->LAngleLoc, TemplArgInfo->RAngleLoc); - if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, - InstTemplateArgs, TemplateArgs)) + if (SemaRef.SubstTemplateArguments(TemplArgInfo->arguments(), TemplateArgs, + InstTemplateArgs)) return nullptr; // Check that the template argument list is well-formed for this @@ -5985,11 +5984,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext) { DeclContext *ParentDC = D->getDeclContext(); - // Determine whether our parent context depends on any of the tempalte + // Determine whether our parent context depends on any of the template // arguments we're currently substituting. bool ParentDependsOnArgs = isDependentContextAtLevel( ParentDC, TemplateArgs.getNumRetainedOuterLevels()); - // FIXME: Parmeters of pointer to functions (y below) that are themselves + // FIXME: Parameters of pointer to functions (y below) that are themselves // parameters (p below) can have their ParentDC set to the translation-unit // - thus we can not consistently check if the ParentDC of such a parameter // is Dependent or/and a FunctionOrMethod. diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 1951aec3d17..c0bb310e64f 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -308,8 +308,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, } return declaresSameEntity(Pack.first.get(), LocalPack); }; - if (std::find_if(LSI->LocalPacks.begin(), LSI->LocalPacks.end(), - DeclaresThisPack) != LSI->LocalPacks.end()) + if (llvm::any_of(LSI->LocalPacks, DeclaresThisPack)) LambdaParamPackReferences.push_back(Pack); } @@ -328,8 +327,8 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc, bool EnclosingStmtExpr = false; for (unsigned N = FunctionScopes.size(); N; --N) { sema::FunctionScopeInfo *Func = FunctionScopes[N-1]; - if (std::any_of( - Func->CompoundScopes.begin(), Func->CompoundScopes.end(), + if (llvm::any_of( + Func->CompoundScopes, [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) { EnclosingStmtExpr = true; break; @@ -893,6 +892,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_Fract: case TST_Float16: case TST_float128: + case TST_ibm128: case TST_bool: case TST_decimal32: case TST_decimal64: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index b78331cdfe9..d2ee669debd 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1369,8 +1369,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // value being declared, poison it as invalid so we don't get chains of // errors. declarator.setInvalidType(true); - } else if ((S.getLangOpts().OpenCLVersion >= 200 || - S.getLangOpts().OpenCLCPlusPlus) && + } else if (S.getLangOpts().getOpenCLCompatibleVersion() >= 200 && DS.isTypeSpecPipe()) { S.Diag(DeclLoc, diag::err_missing_actual_pipe_type) << DS.getSourceRange(); @@ -1525,18 +1524,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: - if (S.getLangOpts().OpenCL) { - if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts())) - S.Diag(DS.getTypeSpecTypeLoc(), - diag::err_opencl_double_requires_extension) - << (S.getLangOpts().OpenCLVersion >= 300); - else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts())) - S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma); - } if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long) Result = Context.LongDoubleTy; else Result = Context.DoubleTy; + if (S.getLangOpts().OpenCL) { + if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts())) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) + << 0 << Result + << (S.getLangOpts().getOpenCLCompatibleVersion() == 300 + ? "cl_khr_fp64 and __opencl_c_fp64" + : "cl_khr_fp64"); + else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts())) + S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma); + } break; case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type() && @@ -1546,6 +1547,13 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { << "__float128"; Result = Context.Float128Ty; break; + case DeclSpec::TST_ibm128: + if (!S.Context.getTargetInfo().hasIbm128Type() && + !S.getLangOpts().SYCLIsDevice && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__ibm128"; + Result = Context.Ibm128Ty; + break; case DeclSpec::TST_bool: Result = Context.BoolTy; // _Bool or bool break; @@ -1614,7 +1622,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for typeof?"); // TypeQuals handled by caller. - Result = S.BuildTypeofExprType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildTypeofExprType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1625,7 +1633,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Expr *E = DS.getRepAsExpr(); assert(E && "Didn't get an expression for decltype?"); // TypeQuals handled by caller. - Result = S.BuildDecltypeType(E, DS.getTypeSpecTypeLoc()); + Result = S.BuildDecltypeType(E); if (Result.isNull()) { Result = Context.IntTy; declarator.setInvalidType(true); @@ -1724,21 +1732,29 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (S.getLangOpts().OpenCL) { const auto &OpenCLOptions = S.getOpenCLOptions(); - StringRef OptName; + bool IsOpenCLC30Compatible = + S.getLangOpts().getOpenCLCompatibleVersion() == 300; // OpenCL C v3.0 s6.3.3 - OpenCL image types require __opencl_c_images - // support + // support. + // OpenCL C v3.0 s6.2.1 - OpenCL 3d image write types requires support + // for OpenCL C 2.0, or OpenCL C 3.0 or newer and the + // __opencl_c_3d_image_writes feature. OpenCL C v3.0 API s4.2 - For devices + // that support OpenCL 3.0, cl_khr_3d_image_writes must be returned when and + // only when the optional feature is supported if ((Result->isImageType() || Result->isSamplerT()) && - (S.getLangOpts().OpenCLVersion >= 300 && - !OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts()))) - OptName = "__opencl_c_images"; - else if (Result->isOCLImage3dWOType() && - !OpenCLOptions.isSupported("cl_khr_3d_image_writes", - S.getLangOpts())) - OptName = "cl_khr_3d_image_writes"; - - if (!OptName.empty()) { + (IsOpenCLC30Compatible && + !OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts()))) { S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) - << 0 << Result << OptName; + << 0 << Result << "__opencl_c_images"; + declarator.setInvalidType(); + } else if (Result->isOCLImage3dWOType() && + !OpenCLOptions.isSupported("cl_khr_3d_image_writes", + S.getLangOpts())) { + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension) + << 0 << Result + << (IsOpenCLC30Compatible + ? "cl_khr_3d_image_writes and __opencl_c_3d_image_writes" + : "cl_khr_3d_image_writes"); declarator.setInvalidType(); } } @@ -2076,9 +2092,7 @@ static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) { !PointeeType->isSamplerT() && !PointeeType.hasAddressSpace()) PointeeType = S.getASTContext().getAddrSpaceQualType( - PointeeType, S.getLangOpts().OpenCLGenericAddressSpace - ? LangAS::opencl_generic - : LangAS::opencl_private); + PointeeType, S.getASTContext().getDefaultOpenCLPointeeAddrSpace()); return PointeeType; } @@ -4245,8 +4259,8 @@ static void fixItNullability(Sema &S, DiagBuilderT &Diag, InsertionText = InsertionText.drop_back().drop_front(); else InsertionText = InsertionText.drop_front(); - } else if (!isIdentifierBody(NextChar[0], /*allow dollar*/true) && - !isIdentifierBody(NextChar[-1], /*allow dollar*/true)) { + } else if (!isAsciiIdentifierContinue(NextChar[0], /*allow dollar*/ true) && + !isAsciiIdentifierContinue(NextChar[-1], /*allow dollar*/ true)) { InsertionText = InsertionText.drop_back().drop_front(); } @@ -5084,7 +5098,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, "__cl_clang_variadic_functions", S.getLangOpts()) && !(D.getIdentifier() && ((D.getIdentifier()->getName() == "printf" && - (LangOpts.OpenCLCPlusPlus || LangOpts.OpenCLVersion >= 120)) || + LangOpts.getOpenCLCompatibleVersion() >= 120) || D.getIdentifier()->getName().startswith("__")))) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function); D.setInvalidType(true); @@ -5414,7 +5428,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Avoid emitting extra errors if we already errored on the scope. D.setInvalidType(true); } else if (S.isDependentScopeSpecifier(SS) || - dyn_cast_or_null(S.computeDeclContext(SS))) { + isa_and_nonnull(S.computeDeclContext(SS))) { NestedNameSpecifier *NNS = SS.getScopeRep(); NestedNameSpecifier *NNSPrefix = NNS->getPrefix(); switch (NNS->getKind()) { @@ -5507,7 +5521,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorChunk::Function: { const DeclaratorChunk::FunctionTypeInfo &FTI = DeclType.Fun; - // We supress the warning when there's no LParen location, as this + // We suppress the warning when there's no LParen location, as this // indicates the declaration was an implicit declaration, which gets // warned about separately via -Wimplicit-function-declaration. if (FTI.NumParams == 0 && !FTI.isVariadic && FTI.getLParenLoc().isValid()) @@ -5886,13 +5900,16 @@ namespace { void VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { Visit(TL.getUnqualifiedLoc()); } + // Allow to fill pointee's type locations, e.g., + // int __attr * __attr * __attr *p; + void VisitPointerTypeLoc(PointerTypeLoc TL) { Visit(TL.getNextTypeLoc()); } void VisitTypedefTypeLoc(TypedefTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); } void VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeLoc()); // FIXME. We should have DS.getTypeSpecTypeEndLoc(). But, it requires - // addition field. What we have is good enough for dispay of location + // addition field. What we have is good enough for display of location // of 'fixit' on interface name. TL.setNameEndLoc(DS.getEndLoc()); } @@ -6486,6 +6503,34 @@ QualType Sema::BuildAddressSpaceAttr(QualType &T, Expr *AddrSpace, return BuildAddressSpaceAttr(T, ASIdx, AddrSpace, AttrLoc); } +static void HandleBTFTypeTagAttribute(QualType &Type, const ParsedAttr &Attr, + TypeProcessingState &State) { + Sema &S = State.getSema(); + + // Check the number of attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 1; + Attr.setInvalid(); + return; + } + + // Ensure the argument is a string. + auto *StrLiteral = dyn_cast(Attr.getArgAsExpr(0)); + if (!StrLiteral) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_type) + << Attr << AANT_ArgumentString; + Attr.setInvalid(); + return; + } + + ASTContext &Ctx = S.Context; + StringRef BTFTypeTag = StrLiteral->getString(); + Type = State.getAttributedType( + ::new (Ctx) BTFTypeTagAttr(Ctx, Attr, BTFTypeTag), Type, Type); + return; +} + /// HandleAddressSpaceTypeAttribute - Process an address_space attribute on the /// specified type. The attribute contains 1 argument, the id of the address /// space for the type. @@ -7800,7 +7845,7 @@ static bool isPermittedNeonBaseType(QualType &Ty, static bool verifyValidIntegerConstantExpr(Sema &S, const ParsedAttr &Attr, llvm::APSInt &Result) { const auto *AttrExpr = Attr.getArgAsExpr(0); - if (!AttrExpr->isTypeDependent() && !AttrExpr->isValueDependent()) { + if (!AttrExpr->isTypeDependent()) { if (Optional Res = AttrExpr->getIntegerConstantExpr(S.Context)) { Result = *Res; @@ -7875,8 +7920,10 @@ static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, return; } - // Attribute is unsupported if '-msve-vector-bits=' isn't specified. - if (!S.getLangOpts().ArmSveVectorBits) { + // Attribute is unsupported if '-msve-vector-bits=' isn't specified, or + // if + syntax is used. + if (!S.getLangOpts().VScaleMin || + S.getLangOpts().VScaleMin != S.getLangOpts().VScaleMax) { S.Diag(Attr.getLoc(), diag::err_attribute_arm_feature_sve_bits_unsupported) << Attr; Attr.setInvalid(); @@ -7899,9 +7946,9 @@ static void HandleArmSveVectorBitsTypeAttr(QualType &CurType, ParsedAttr &Attr, unsigned VecSize = static_cast(SveVectorSizeInBits.getZExtValue()); // The attribute vector size must match -msve-vector-bits. - if (VecSize != S.getLangOpts().ArmSveVectorBits) { + if (VecSize != S.getLangOpts().VScaleMin * 128) { S.Diag(Attr.getLoc(), diag::err_attribute_bad_sve_vector_size) - << VecSize << S.getLangOpts().ArmSveVectorBits; + << VecSize << S.getLangOpts().VScaleMin * 128; Attr.setInvalid(); return; } @@ -8113,6 +8160,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::IgnoredAttribute: break; + case ParsedAttr::AT_BTFTypeTag: + HandleBTFTypeTagAttribute(type, attr, state); + attr.setUsedAsTypeAttr(); + break; + case ParsedAttr::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore // it it breaks large amounts of Linux software. @@ -8294,10 +8346,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, attr.getMacroExpansionLoc()); } } - - if (!state.getSema().getLangOpts().OpenCL || - type.getAddressSpace() != LangAS::Default) - return; } void Sema::completeExprArrayBound(Expr *E) { @@ -8877,7 +8925,7 @@ QualType Sema::getElaboratedType(ElaboratedTypeKeyword Keyword, return Context.getElaboratedType(Keyword, NNS, T, OwnedTagDecl); } -QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { +QualType Sema::BuildTypeofExprType(Expr *E) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (!getLangOpts().CPlusPlus && E->refersToBitField()) @@ -8891,35 +8939,12 @@ QualType Sema::BuildTypeofExprType(Expr *E, SourceLocation Loc) { return Context.getTypeOfExprType(E); } -/// getDecltypeForParenthesizedExpr - Given an expr, will return the type for -/// that expression, as in [dcl.type.simple]p4 but without taking id-expressions -/// and class member access into account. -QualType Sema::getDecltypeForParenthesizedExpr(Expr *E) { - // C++11 [dcl.type.simple]p4: - // [...] - QualType T = E->getType(); - switch (E->getValueKind()) { - // - otherwise, if e is an xvalue, decltype(e) is T&&, where T is the - // type of e; - case VK_XValue: - return Context.getRValueReferenceType(T); - // - otherwise, if e is an lvalue, decltype(e) is T&, where T is the - // type of e; - case VK_LValue: - return Context.getLValueReferenceType(T); - // - otherwise, decltype(e) is the type of e. - case VK_PRValue: - return T; - } - llvm_unreachable("Unknown value kind"); -} - /// getDecltypeForExpr - Given an expr, will return the decltype for /// that expression, according to the rules in C++11 /// [dcl.type.simple]p4 and C++11 [expr.lambda.prim]p18. -static QualType getDecltypeForExpr(Sema &S, Expr *E) { +QualType Sema::getDecltypeForExpr(Expr *E) { if (E->isTypeDependent()) - return S.Context.DependentTy; + return Context.DependentTy; Expr *IDExpr = E; if (auto *ImplCastExpr = dyn_cast(E)) @@ -8936,7 +8961,7 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // parameter object. This rule makes no difference before C++20 so we apply // it unconditionally. if (const auto *SNTTPE = dyn_cast(IDExpr)) - return SNTTPE->getParameterType(S.Context); + return SNTTPE->getParameterType(Context); // - if e is an unparenthesized id-expression or an unparenthesized class // member access (5.2.5), decltype(e) is the type of the entity named @@ -8944,22 +8969,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // functions, the program is ill-formed; // // We apply the same rules for Objective-C ivar and property references. - if (const DeclRefExpr *DRE = dyn_cast(IDExpr)) { + if (const auto *DRE = dyn_cast(IDExpr)) { const ValueDecl *VD = DRE->getDecl(); - if (auto *TPO = dyn_cast(VD)) - return TPO->getType().getUnqualifiedType(); - return VD->getType(); - } else if (const MemberExpr *ME = dyn_cast(IDExpr)) { - if (const ValueDecl *VD = ME->getMemberDecl()) + QualType T = VD->getType(); + return isa(VD) ? T.getUnqualifiedType() : T; + } + if (const auto *ME = dyn_cast(IDExpr)) { + if (const auto *VD = ME->getMemberDecl()) if (isa(VD) || isa(VD)) return VD->getType(); - } else if (const ObjCIvarRefExpr *IR = dyn_cast(IDExpr)) { + } else if (const auto *IR = dyn_cast(IDExpr)) { return IR->getDecl()->getType(); - } else if (const ObjCPropertyRefExpr *PR = - dyn_cast(IDExpr)) { + } else if (const auto *PR = dyn_cast(IDExpr)) { if (PR->isExplicitProperty()) return PR->getExplicitProperty()->getType(); - } else if (auto *PE = dyn_cast(IDExpr)) { + } else if (const auto *PE = dyn_cast(IDExpr)) { return PE->getType(); } @@ -8970,24 +8994,20 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // access to a corresponding data member of the closure type that // would have been declared if x were an odr-use of the denoted // entity. - using namespace sema; - if (S.getCurLambda()) { - if (isa(IDExpr)) { - if (DeclRefExpr *DRE = dyn_cast(IDExpr->IgnoreParens())) { - if (VarDecl *Var = dyn_cast(DRE->getDecl())) { - QualType T = S.getCapturedDeclRefType(Var, DRE->getLocation()); - if (!T.isNull()) - return S.Context.getLValueReferenceType(T); - } + if (getCurLambda() && isa(IDExpr)) { + if (auto *DRE = dyn_cast(IDExpr->IgnoreParens())) { + if (auto *Var = dyn_cast(DRE->getDecl())) { + QualType T = getCapturedDeclRefType(Var, DRE->getLocation()); + if (!T.isNull()) + return Context.getLValueReferenceType(T); } } } - return S.getDecltypeForParenthesizedExpr(E); + return Context.getReferenceQualifiedType(E); } -QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, - bool AsUnevaluated) { +QualType Sema::BuildDecltypeType(Expr *E, bool AsUnevaluated) { assert(!E->hasPlaceholderType() && "unexpected placeholder"); if (AsUnevaluated && CodeSynthesisContexts.empty() && @@ -8998,8 +9018,7 @@ QualType Sema::BuildDecltypeType(Expr *E, SourceLocation Loc, // used to build SFINAE gadgets. Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); } - - return Context.getDecltypeType(E, getDecltypeForExpr(*this, E)); + return Context.getDecltypeType(E, getDecltypeForExpr(E)); } QualType Sema::BuildUnaryTransformType(QualType BaseType, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 70ba631dbfc..7f3326c1326 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -161,7 +161,7 @@ public: /// Wether CXXConstructExpr can be skipped when they are implicit. /// They will be reconstructed when used if needed. - /// This is usefull when the user that cause rebuilding of the + /// This is useful when the user that cause rebuilding of the /// CXXConstructExpr is outside of the expression at which the TreeTransform /// started. bool AllowSkippingCXXConstructExpr() { return true; } @@ -522,7 +522,7 @@ public: /// /// By default, transforms the types of conversion function, constructor, /// and destructor names and then (if needed) rebuilds the declaration name. - /// Identifiers and selectors are returned unmodified. Sublcasses may + /// Identifiers and selectors are returned unmodified. Subclasses may /// override this function to provide alternate behavior. DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); @@ -1320,12 +1320,12 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, + StmtResult RebuildIfStmt(SourceLocation IfLoc, IfStatementKind Kind, SourceLocation LParenLoc, Sema::ConditionResult Cond, SourceLocation RParenLoc, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { - return getSema().ActOnIfStmt(IfLoc, IsConstexpr, LParenLoc, Init, Cond, - RParenLoc, Then, ElseLoc, Else); + return getSema().ActOnIfStmt(IfLoc, Kind, LParenLoc, Init, Cond, RParenLoc, + Then, ElseLoc, Else); } /// Start building a new switch statement. @@ -1929,10 +1929,10 @@ public: OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, const OMPVarListLocTy &Locs, ArrayRef UnresolvedMappers) { - return getSema().ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, - MapperIdScopeSpec, MapperId, MapType, - IsMapTypeImplicit, MapLoc, ColonLoc, - VarList, Locs, UnresolvedMappers); + return getSema().ActOnOpenMPMapClause( + MapTypeModifiers, MapTypeModifiersLoc, MapperIdScopeSpec, MapperId, + MapType, IsMapTypeImplicit, MapLoc, ColonLoc, VarList, Locs, + /*NoDiagnose=*/false, UnresolvedMappers); } /// Build a new OpenMP 'allocate' clause. @@ -2256,6 +2256,29 @@ public: EndLoc); } + /// Build a new OpenMP 'bind' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPBindClause(OpenMPBindClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPBindClause(Kind, KindLoc, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'align' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAlignClause(Expr *A, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -3840,8 +3863,10 @@ ExprResult TreeTransform::TransformInitializer(Expr *Init, if (auto *FE = dyn_cast(Init)) Init = FE->getSubExpr(); - if (auto *AIL = dyn_cast(Init)) - Init = AIL->getCommonExpr(); + if (auto *AIL = dyn_cast(Init)) { + OpaqueValueExpr *OVE = AIL->getCommonExpr(); + Init = OVE->getSourceExpr(); + } if (MaterializeTemporaryExpr *MTE = dyn_cast(Init)) Init = MTE->getSubExpr(); @@ -4745,8 +4770,8 @@ QualType TreeTransform::RebuildQualifiedType(QualType T, SourceLocation Loc = TL.getBeginLoc(); Qualifiers Quals = TL.getType().getLocalQualifiers(); - if (((T.getAddressSpace() != LangAS::Default && - Quals.getAddressSpace() != LangAS::Default)) && + if ((T.getAddressSpace() != LangAS::Default && + Quals.getAddressSpace() != LangAS::Default) && T.getAddressSpace() != Quals.getAddressSpace()) { SemaRef.Diag(Loc, diag::err_address_space_mismatch_templ_inst) << TL.getType() << T; @@ -5945,7 +5970,7 @@ bool TreeTransform::TransformExceptionSpec( ExceptionSpecificationType EST = ESI.Type; NoexceptExpr = - getSema().ActOnNoexceptSpec(Loc, NoexceptExpr.get(), EST); + getSema().ActOnNoexceptSpec(NoexceptExpr.get(), EST); if (NoexceptExpr.isInvalid()) return true; @@ -6561,7 +6586,7 @@ QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, T->isDependentType() || T->isConstrained()) { // FIXME: Maybe don't rebuild if all template arguments are the same. llvm::SmallVector NewArgList; - NewArgList.reserve(NewArgList.size()); + NewArgList.reserve(NewTemplateArgs.size()); for (const auto &ArgLoc : NewTemplateArgs.arguments()) NewArgList.push_back(ArgLoc.getArgument()); Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, @@ -6578,7 +6603,7 @@ QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, NewTL.setFoundDecl(TL.getFoundDecl()); NewTL.setLAngleLoc(TL.getLAngleLoc()); NewTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned I = 0; I < TL.getNumArgs(); ++I) + for (unsigned I = 0; I < NewTL.getNumArgs(); ++I) NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); return Result; @@ -7371,13 +7396,16 @@ TreeTransform::TransformIfStmt(IfStmt *S) { if (Init.isInvalid()) return StmtError(); - // Transform the condition - Sema::ConditionResult Cond = getDerived().TransformCondition( - S->getIfLoc(), S->getConditionVariable(), S->getCond(), - S->isConstexpr() ? Sema::ConditionKind::ConstexprIf - : Sema::ConditionKind::Boolean); - if (Cond.isInvalid()) - return StmtError(); + Sema::ConditionResult Cond; + if (!S->isConsteval()) { + // Transform the condition + Cond = getDerived().TransformCondition( + S->getIfLoc(), S->getConditionVariable(), S->getCond(), + S->isConstexpr() ? Sema::ConditionKind::ConstexprIf + : Sema::ConditionKind::Boolean); + if (Cond.isInvalid()) + return StmtError(); + } // If this is a constexpr if, determine which arm we should instantiate. llvm::Optional ConstexprConditionValue; @@ -7410,7 +7438,7 @@ TreeTransform::TransformIfStmt(IfStmt *S) { return S; return getDerived().RebuildIfStmt( - S->getIfLoc(), S->isConstexpr(), S->getLParenLoc(), Cond, + S->getIfLoc(), S->getStatementKind(), S->getLParenLoc(), Cond, S->getRParenLoc(), Init.get(), Then.get(), S->getElseLoc(), Else.get()); } @@ -8504,6 +8532,15 @@ StmtResult TreeTransform::TransformOMPExecutableDirective( AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc()); } +template +StmtResult +TreeTransform::TransformOMPMetaDirective(OMPMetaDirective *D) { + // TODO: Fix This + SemaRef.Diag(D->getBeginLoc(), diag::err_omp_instantiation_not_supported) + << getOpenMPDirectiveName(D->getDirectiveKind()); + return StmtError(); +} + template StmtResult TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { @@ -9160,6 +9197,17 @@ TreeTransform::TransformOMPMaskedDirective(OMPMaskedDirective *D) { return Res; } +template +StmtResult TreeTransform::TransformOMPGenericLoopDirective( + OMPGenericLoopDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_loop, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -9509,6 +9557,15 @@ TreeTransform::TransformOMPFilterClause(OMPFilterClause *C) { C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause *TreeTransform::TransformOMPAlignClause(OMPAlignClause *C) { + ExprResult E = getDerived().TransformExpr(C->getAlignment()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPAlignClause(E.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause *TreeTransform::TransformOMPUnifiedAddressClause( OMPUnifiedAddressClause *C) { @@ -10219,6 +10276,13 @@ OMPClause *TreeTransform::TransformOMPOrderClause(OMPOrderClause *C) { C->getEndLoc()); } +template +OMPClause *TreeTransform::TransformOMPBindClause(OMPBindClause *C) { + return getDerived().RebuildOMPBindClause( + C->getBindKind(), C->getBindKindLoc(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -10944,14 +11008,10 @@ ExprResult TreeTransform::TransformCXXRewrittenBinaryOperator( if (RHS.isInvalid()) return ExprError(); - if (!getDerived().AlwaysRebuild() && - LHS.get() == Decomp.LHS && - RHS.get() == Decomp.RHS) - return E; - // Extract the already-resolved callee declarations so that we can restrict // ourselves to using them as the unqualified lookup results when rebuilding. UnresolvedSet<2> UnqualLookups; + bool ChangedAnyLookups = false; Expr *PossibleBinOps[] = {E->getSemanticForm(), const_cast(Decomp.InnerBinOp)}; for (Expr *PossibleBinOp : PossibleBinOps) { @@ -10968,9 +11028,23 @@ ExprResult TreeTransform::TransformCXXRewrittenBinaryOperator( E->getOperatorLoc(), Callee->getFoundDecl())); if (!Found) return ExprError(); + if (Found != Callee->getFoundDecl()) + ChangedAnyLookups = true; UnqualLookups.addDecl(Found); } + if (!getDerived().AlwaysRebuild() && !ChangedAnyLookups && + LHS.get() == Decomp.LHS && RHS.get() == Decomp.RHS) { + // Mark all functions used in the rewrite as referenced. Note that when + // a < b is rewritten to (a <=> b) < 0, both the <=> and the < might be + // function calls, and/or there might be a user-defined conversion sequence + // applied to the operands of the <. + // FIXME: this is a bit instantiation-specific. + const Expr *StopAt[] = {Decomp.LHS, Decomp.RHS}; + SemaRef.MarkDeclarationsReferencedInExpr(E, false, StopAt); + return E; + } + return getDerived().RebuildCXXRewrittenBinaryOperator( E->getOperatorLoc(), Decomp.Opcode, UnqualLookups, LHS.get(), RHS.get()); } @@ -14437,10 +14511,10 @@ QualType TreeTransform::RebuildUnresolvedUsingType(SourceLocation Loc, return SemaRef.Context.getTypeDeclType(Ty); } -template +template QualType TreeTransform::RebuildTypeOfExprType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildTypeofExprType(E, Loc); + SourceLocation) { + return SemaRef.BuildTypeofExprType(E); } template @@ -14448,10 +14522,9 @@ QualType TreeTransform::RebuildTypeOfType(QualType Underlying) { return SemaRef.Context.getTypeOfType(Underlying); } -template -QualType TreeTransform::RebuildDecltypeType(Expr *E, - SourceLocation Loc) { - return SemaRef.BuildDecltypeType(E, Loc); +template +QualType TreeTransform::RebuildDecltypeType(Expr *E, SourceLocation) { + return SemaRef.BuildDecltypeType(E); } template diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h index c33d30478e2..24b7342b3fb 100644 --- a/clang/lib/Sema/UsedDeclVisitor.h +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -72,7 +72,8 @@ public: QualType Destroyed = S.Context.getBaseElementType(DestroyedOrNull); if (const RecordType *DestroyedRec = Destroyed->getAs()) { CXXRecordDecl *Record = cast(DestroyedRec->getDecl()); - asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); + if (Record->getDefinition()) + asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); } } diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 5fe1f96327d..c60f87a2398 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -168,6 +168,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::Float128: ID = PREDEF_TYPE_FLOAT128_ID; break; + case BuiltinType::Ibm128: + ID = PREDEF_TYPE_IBM128_ID; + break; case BuiltinType::NullPtr: ID = PREDEF_TYPE_NULLPTR_ID; break; @@ -474,7 +477,7 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) { // Otherwise, we only care about anonymous class members / block-scope decls. // FIXME: We need to handle lambdas and blocks within inline / templated // variables too. - if (D->getDeclName() || !isa(D->getLexicalDeclContext())) + if (D->getDeclName() || !isa(D->getLexicalDeclContext())) return false; return isa(D) || isa(D); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 83bade9941b..a033bccbe50 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -10,15 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/OpenMPKinds.h" -#include "clang/Serialization/ASTRecordReader.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" -#include "clang/AST/AbstractTypeReader.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/AbstractTypeReader.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -31,8 +29,8 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" -#include "clang/AST/OpenMPClause.h" #include "clang/AST/ODRHash.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" @@ -42,6 +40,7 @@ #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/CommentOptions.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticError.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" @@ -51,6 +50,7 @@ #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Sanitizers.h" @@ -76,6 +76,7 @@ #include "clang/Sema/Weak.h" #include "clang/Serialization/ASTBitCodes.h" #include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Serialization/ASTRecordReader.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" @@ -555,7 +556,8 @@ static Module *getTopImportImplicitModule(ModuleManager &ModuleMgr, StringRef ModuleName = TopImport->ModuleName; assert(!ModuleName.empty() && "diagnostic options read before module name"); - Module *M = PP.getHeaderSearchInfo().lookupModule(ModuleName); + Module *M = + PP.getHeaderSearchInfo().lookupModule(ModuleName, TopImport->ImportLoc); assert(M && "missing module"); return M; } @@ -726,8 +728,7 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, if (File == ExistingPPOpts.ImplicitPCHInclude) continue; - if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File) - != PPOpts.Includes.end()) + if (llvm::is_contained(PPOpts.Includes, File)) continue; SuggestedPredefines += "#include \""; @@ -737,9 +738,7 @@ static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { StringRef File = ExistingPPOpts.MacroIncludes[I]; - if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(), - File) - != PPOpts.MacroIncludes.end()) + if (llvm::is_contained(PPOpts.MacroIncludes, File)) continue; SuggestedPredefines += "#__include_macros \""; @@ -1263,7 +1262,29 @@ void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2, } void ASTReader::Error(llvm::Error &&Err) const { - Error(toString(std::move(Err))); + llvm::Error RemainingErr = + handleErrors(std::move(Err), [this](const DiagnosticError &E) { + auto Diag = E.getDiagnostic().second; + + // Ideally we'd just emit it, but have to handle a possible in-flight + // diagnostic. Note that the location is currently ignored as well. + auto NumArgs = Diag.getStorage()->NumDiagArgs; + assert(NumArgs <= 3 && "Can only have up to 3 arguments"); + StringRef Arg1, Arg2, Arg3; + switch (NumArgs) { + case 3: + Arg3 = Diag.getStringArg(2); + LLVM_FALLTHROUGH; + case 2: + Arg2 = Diag.getStringArg(1); + LLVM_FALLTHROUGH; + case 1: + Arg1 = Diag.getStringArg(0); + } + Error(Diag.getDiagID(), Arg1, Arg2, Arg3); + }); + if (RemainingErr) + Error(toString(std::move(RemainingErr))); } //===----------------------------------------------------------------------===// @@ -1271,9 +1292,7 @@ void ASTReader::Error(llvm::Error &&Err) const { //===----------------------------------------------------------------------===// /// Read the line table in the source manager block. -/// \returns true if there was an error. -bool ASTReader::ParseLineTable(ModuleFile &F, - const RecordData &Record) { +void ASTReader::ParseLineTable(ModuleFile &F, const RecordData &Record) { unsigned Idx = 0; LineTableInfo &LineTable = SourceMgr.getLineTable(); @@ -1312,12 +1331,10 @@ bool ASTReader::ParseLineTable(ModuleFile &F, } LineTable.AddEntry(FileID::get(FID), Entries); } - - return false; } /// Read a source manager block -bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { +llvm::Error ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; @@ -1329,36 +1346,29 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { SLocEntryCursor = F.Stream; // The stream itself is going to skip over the source manager block. - if (llvm::Error Err = F.Stream.SkipBlock()) { - Error(std::move(Err)); - return true; - } + if (llvm::Error Err = F.Stream.SkipBlock()) + return Err; // Enter the source manager block. - if (llvm::Error Err = - SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) { - Error(std::move(Err)); - return true; - } + if (llvm::Error Err = SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) + return Err; F.SourceManagerBlockStartOffset = SLocEntryCursor.GetCurrentBitNo(); RecordData Record; while (true) { Expected MaybeE = SLocEntryCursor.advanceSkippingSubblocks(); - if (!MaybeE) { - Error(MaybeE.takeError()); - return true; - } + if (!MaybeE) + return MaybeE.takeError(); llvm::BitstreamEntry E = MaybeE.get(); switch (E.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: - Error("malformed block record in AST file"); - return true; + return llvm::createStringError(std::errc::illegal_byte_sequence, + "malformed block record in AST file"); case llvm::BitstreamEntry::EndBlock: - return false; + return llvm::Error::success(); case llvm::BitstreamEntry::Record: // The interesting case. break; @@ -1369,10 +1379,8 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { StringRef Blob; Expected MaybeRecord = SLocEntryCursor.readRecord(E.ID, Record, &Blob); - if (!MaybeRecord) { - Error(MaybeRecord.takeError()); - return true; - } + if (!MaybeRecord) + return MaybeRecord.takeError(); switch (MaybeRecord.get()) { default: // Default behavior: ignore. break; @@ -1381,7 +1389,7 @@ bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: // Once we hit one of the source location entries, we're done. - return false; + return llvm::Error::success(); } } } @@ -1632,13 +1640,11 @@ SourceLocation ASTReader::getImportLocation(ModuleFile *F) { /// Enter a subblock of the specified BlockID with the specified cursor. Read /// the abbreviations that are at the top of the block and then leave the cursor /// pointing into the block. -bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID, - uint64_t *StartOfBlockOffset) { - if (llvm::Error Err = Cursor.EnterSubBlock(BlockID)) { - // FIXME this drops errors on the floor. - consumeError(std::move(Err)); - return true; - } +llvm::Error ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, + unsigned BlockID, + uint64_t *StartOfBlockOffset) { + if (llvm::Error Err = Cursor.EnterSubBlock(BlockID)) + return Err; if (StartOfBlockOffset) *StartOfBlockOffset = Cursor.GetCurrentBitNo(); @@ -1646,27 +1652,18 @@ bool ASTReader::ReadBlockAbbrevs(BitstreamCursor &Cursor, unsigned BlockID, while (true) { uint64_t Offset = Cursor.GetCurrentBitNo(); Expected MaybeCode = Cursor.ReadCode(); - if (!MaybeCode) { - // FIXME this drops errors on the floor. - consumeError(MaybeCode.takeError()); - return true; - } + if (!MaybeCode) + return MaybeCode.takeError(); unsigned Code = MaybeCode.get(); // We expect all abbrevs to be at the start of the block. if (Code != llvm::bitc::DEFINE_ABBREV) { - if (llvm::Error Err = Cursor.JumpToBit(Offset)) { - // FIXME this drops errors on the floor. - consumeError(std::move(Err)); - return true; - } - return false; - } - if (llvm::Error Err = Cursor.ReadAbbrevRecord()) { - // FIXME this drops errors on the floor. - consumeError(std::move(Err)); - return true; + if (llvm::Error Err = Cursor.JumpToBit(Offset)) + return Err; + return llvm::Error::success(); } + if (llvm::Error Err = Cursor.ReadAbbrevRecord()) + return Err; } } @@ -2380,17 +2377,24 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { } } - enum ModificationType { - Size, - ModTime, - Content, - None, + struct Change { + enum ModificationKind { + Size, + ModTime, + Content, + None, + } Kind; + llvm::Optional Old = llvm::None; + llvm::Optional New = llvm::None; }; auto HasInputFileChanged = [&]() { if (StoredSize != File->getSize()) - return ModificationType::Size; + return Change{Change::Size, StoredSize, File->getSize()}; if (!shouldDisableValidationForFile(F) && StoredTime && StoredTime != File->getModificationTime()) { + Change MTimeChange = {Change::ModTime, StoredTime, + File->getModificationTime()}; + // In case the modification time changes but not the content, // accept the cached file as legit. if (ValidateASTInputFilesContent && @@ -2398,28 +2402,30 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { auto MemBuffOrError = FileMgr.getBufferForFile(File); if (!MemBuffOrError) { if (!Complain) - return ModificationType::ModTime; + return MTimeChange; std::string ErrorStr = "could not get buffer for file '"; ErrorStr += File->getName(); ErrorStr += "'"; Error(ErrorStr); - return ModificationType::ModTime; + return MTimeChange; } + // FIXME: hash_value is not guaranteed to be stable! auto ContentHash = hash_value(MemBuffOrError.get()->getBuffer()); if (StoredContentHash == static_cast(ContentHash)) - return ModificationType::None; - return ModificationType::Content; + return Change{Change::None}; + + return Change{Change::Content}; } - return ModificationType::ModTime; + return MTimeChange; } - return ModificationType::None; + return Change{Change::None}; }; bool IsOutOfDate = false; auto FileChange = HasInputFileChanged(); // For an overridden file, there is nothing to validate. - if (!Overridden && FileChange != ModificationType::None) { + if (!Overridden && FileChange.Kind != Change::None) { if (Complain && !Diags.isDiagnosticInFlight()) { // Build a list of the PCH imports that got us here (in reverse). SmallVector ImportStack(1, &F); @@ -2430,7 +2436,10 @@ InputFile ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { StringRef TopLevelPCHName(ImportStack.back()->FileName); Diag(diag::err_fe_ast_file_modified) << Filename << moduleKindForDiagnostic(ImportStack.back()->Kind) - << TopLevelPCHName << FileChange; + << TopLevelPCHName << FileChange.Kind + << (FileChange.Old && FileChange.New) + << llvm::itostr(FileChange.Old.getValueOr(0)) + << llvm::itostr(FileChange.New.getValueOr(0)); // Print the import stack. if (ImportStack.size() > 1) { @@ -2912,7 +2921,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, // If we've already loaded a module map file covering this module, we may // have a better path for it (relative to the current build). Module *M = PP.getHeaderSearchInfo().lookupModule( - F.ModuleName, /*AllowSearch*/ true, + F.ModuleName, SourceLocation(), /*AllowSearch*/ true, /*AllowExtraModuleMapSearch*/ true); if (M && M->Directory) { // If we're implicitly loading a module, the base directory can't @@ -2954,30 +2963,27 @@ ASTReader::ReadControlBlock(ModuleFile &F, } } -ASTReader::ASTReadResult -ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { +llvm::Error ASTReader::ReadASTBlock(ModuleFile &F, + unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; - if (llvm::Error Err = Stream.EnterSubBlock(AST_BLOCK_ID)) { - Error(std::move(Err)); - return Failure; - } + if (llvm::Error Err = Stream.EnterSubBlock(AST_BLOCK_ID)) + return Err; F.ASTBlockStartOffset = Stream.GetCurrentBitNo(); // Read all of the records and blocks for the AST file. RecordData Record; while (true) { Expected MaybeEntry = Stream.advance(); - if (!MaybeEntry) { - Error(MaybeEntry.takeError()); - return Failure; - } + if (!MaybeEntry) + return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::Error: - Error("error at end of module block in AST file"); - return Failure; + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "error at end of module block in AST file"); case llvm::BitstreamEntry::EndBlock: // Outside of C++, we do not store a lookup map for the translation unit. // Instead, mark it as needing a lookup map to be built if this module @@ -2990,7 +2996,7 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { DC->setMustBuildLookupTable(); } - return Success; + return llvm::Error::success(); case llvm::BitstreamEntry::SubBlock: switch (Entry.ID) { case DECLTYPES_BLOCK_ID: @@ -2999,15 +3005,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // cursor to it, enter the block and read the abbrevs in that block. // With the main cursor, we just skip over it. F.DeclsCursor = Stream; - if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } - if (ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID, - &F.DeclsBlockStartOffset)) { - Error("malformed block record in AST file"); - return Failure; - } + if (llvm::Error Err = Stream.SkipBlock()) + return Err; + if (llvm::Error Err = ReadBlockAbbrevs( + F.DeclsCursor, DECLTYPES_BLOCK_ID, &F.DeclsBlockStartOffset)) + return Err; break; case PREPROCESSOR_BLOCK_ID: @@ -3015,14 +3017,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { if (!PP.getExternalSource()) PP.setExternalSource(this); - if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } - if (ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { - Error("malformed block record in AST file"); - return Failure; - } + if (llvm::Error Err = Stream.SkipBlock()) + return Err; + if (llvm::Error Err = + ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) + return Err; F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); break; @@ -3030,14 +3029,11 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { F.PreprocessorDetailCursor = Stream; if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } - if (ReadBlockAbbrevs(F.PreprocessorDetailCursor, - PREPROCESSOR_DETAIL_BLOCK_ID)) { - Error("malformed preprocessor detail record in AST file"); - return Failure; + return Err; } + if (llvm::Error Err = ReadBlockAbbrevs(F.PreprocessorDetailCursor, + PREPROCESSOR_DETAIL_BLOCK_ID)) + return Err; F.PreprocessorDetailStartOffset = F.PreprocessorDetailCursor.GetCurrentBitNo(); @@ -3048,36 +3044,29 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SOURCE_MANAGER_BLOCK_ID: - if (ReadSourceManagerBlock(F)) - return Failure; + if (llvm::Error Err = ReadSourceManagerBlock(F)) + return Err; break; case SUBMODULE_BLOCK_ID: - if (ASTReadResult Result = - ReadSubmoduleBlock(F, ClientLoadCapabilities)) - return Result; + if (llvm::Error Err = ReadSubmoduleBlock(F, ClientLoadCapabilities)) + return Err; break; case COMMENTS_BLOCK_ID: { BitstreamCursor C = Stream; - if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } - if (ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { - Error("malformed comments block in AST file"); - return Failure; - } + if (llvm::Error Err = Stream.SkipBlock()) + return Err; + if (llvm::Error Err = ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) + return Err; CommentsCursors.push_back(std::make_pair(C, &F)); break; } default: - if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } + if (llvm::Error Err = Stream.SkipBlock()) + return Err; break; } continue; @@ -3092,10 +3081,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { StringRef Blob; Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record, &Blob); - if (!MaybeRecordType) { - Error(MaybeRecordType.takeError()); - return Failure; - } + if (!MaybeRecordType) + return MaybeRecordType.takeError(); ASTRecordTypes RecordType = (ASTRecordTypes)MaybeRecordType.get(); // If we're not loading an AST context, we don't care about most records. @@ -3126,10 +3113,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case TYPE_OFFSET: { - if (F.LocalNumTypes != 0) { - Error("duplicate TYPE_OFFSET record in AST file"); - return Failure; - } + if (F.LocalNumTypes != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "duplicate TYPE_OFFSET record in AST file"); F.TypeOffsets = reinterpret_cast(Blob.data()); F.LocalNumTypes = Record[0]; unsigned LocalBaseTypeIndex = Record[1]; @@ -3150,10 +3137,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case DECL_OFFSET: { - if (F.LocalNumDecls != 0) { - Error("duplicate DECL_OFFSET record in AST file"); - return Failure; - } + if (F.LocalNumDecls != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "duplicate DECL_OFFSET record in AST file"); F.DeclOffsets = (const DeclOffset *)Blob.data(); F.LocalNumDecls = Record[0]; unsigned LocalBaseDeclID = Record[1]; @@ -3218,10 +3205,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case IDENTIFIER_OFFSET: { - if (F.LocalNumIdentifiers != 0) { - Error("duplicate IDENTIFIER_OFFSET record in AST file"); - return Failure; - } + if (F.LocalNumIdentifiers != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "duplicate IDENTIFIER_OFFSET record in AST file"); F.IdentifierOffsets = (const uint32_t *)Blob.data(); F.LocalNumIdentifiers = Record[0]; unsigned LocalBaseIdentifierID = Record[1]; @@ -3272,10 +3259,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; } - if (SpecialTypes.size() != Record.size()) { - Error("invalid special-types record"); - return Failure; - } + if (SpecialTypes.size() != Record.size()) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid special-types record"); for (unsigned I = 0, N = Record.size(); I != N; ++I) { serialization::TypeID ID = getGlobalTypeID(F, Record[I]); @@ -3304,10 +3290,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case WEAK_UNDECLARED_IDENTIFIERS: - if (Record.size() % 4 != 0) { - Error("invalid weak identifiers record"); - return Failure; - } + if (Record.size() % 4 != 0) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid weak identifiers record"); // FIXME: Ignore weak undeclared identifiers from non-original PCH // files. This isn't the way to do it :) @@ -3414,10 +3399,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { std::tie(F.SLocEntryBaseID, F.SLocEntryBaseOffset) = SourceMgr.AllocateLoadedSLocEntries(F.LocalNumSLocEntries, SLocSpaceSize); - if (!F.SLocEntryBaseID) { - Error("ran out of source locations"); - break; - } + if (!F.SLocEntryBaseID) + return llvm::createStringError(std::errc::invalid_argument, + "ran out of source locations"); // Make our entry in the range map. BaseID is negative and growing, so // we invert it. Because we invert it, though, we need the other end of // the range. @@ -3448,19 +3432,16 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SOURCE_MANAGER_LINE_TABLE: - if (ParseLineTable(F, Record)) { - Error("malformed SOURCE_MANAGER_LINE_TABLE in AST file"); - return Failure; - } + ParseLineTable(F, Record); break; case SOURCE_LOCATION_PRELOADS: { // Need to transform from the local view (1-based IDs) to the global view, // which is based off F.SLocEntryBaseID. - if (!F.PreloadSLocEntries.empty()) { - Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); - return Failure; - } + if (!F.PreloadSLocEntries.empty()) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "Multiple SOURCE_LOCATION_PRELOADS records in AST file"); F.PreloadSLocEntries.swap(Record); break; @@ -3472,10 +3453,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case VTABLE_USES: - if (Record.size() % 3 != 0) { - Error("Invalid VTABLE_USES record"); - return Failure; - } + if (Record.size() % 3 != 0) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "Invalid VTABLE_USES record"); // Later tables overwrite earlier ones. // FIXME: Modules will have some trouble with this. This is clearly not @@ -3491,15 +3471,15 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case PENDING_IMPLICIT_INSTANTIATIONS: - if (PendingInstantiations.size() % 2 != 0) { - Error("Invalid existing PendingInstantiations"); - return Failure; - } + if (PendingInstantiations.size() % 2 != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "Invalid existing PendingInstantiations"); - if (Record.size() % 2 != 0) { - Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); - return Failure; - } + if (Record.size() % 2 != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); @@ -3509,10 +3489,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SEMA_DECL_REFS: - if (Record.size() != 3) { - Error("Invalid SEMA_DECL_REFS block"); - return Failure; - } + if (Record.size() != 3) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "Invalid SEMA_DECL_REFS block"); for (unsigned I = 0, N = Record.size(); I != N; ++I) SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; @@ -3568,10 +3547,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case DECL_UPDATE_OFFSETS: - if (Record.size() % 2 != 0) { - Error("invalid DECL_UPDATE_OFFSETS block in AST file"); - return Failure; - } + if (Record.size() % 2 != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "invalid DECL_UPDATE_OFFSETS block in AST file"); for (unsigned I = 0, N = Record.size(); I != N; I += 2) { GlobalDeclID ID = getGlobalDeclID(F, Record[I]); DeclUpdateOffsets[ID].push_back(std::make_pair(&F, Record[I + 1])); @@ -3585,10 +3564,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case OBJC_CATEGORIES_MAP: - if (F.LocalNumObjCCategoriesInMap != 0) { - Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); - return Failure; - } + if (F.LocalNumObjCCategoriesInMap != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "duplicate OBJC_CATEGORIES_MAP record in AST file"); F.LocalNumObjCCategoriesInMap = Record[0]; F.ObjCCategoriesMap = (const ObjCCategoriesInfo *)Blob.data(); @@ -3653,15 +3632,13 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case UNDEFINED_BUT_USED: - if (UndefinedButUsed.size() % 2 != 0) { - Error("Invalid existing UndefinedButUsed"); - return Failure; - } + if (UndefinedButUsed.size() % 2 != 0) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "Invalid existing UndefinedButUsed"); - if (Record.size() % 2 != 0) { - Error("invalid undefined-but-used record"); - return Failure; - } + if (Record.size() % 2 != 0) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid undefined-but-used record"); for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { UndefinedButUsed.push_back(getGlobalDeclID(F, Record[I++])); UndefinedButUsed.push_back( @@ -3700,10 +3677,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case MACRO_OFFSET: { - if (F.LocalNumMacros != 0) { - Error("duplicate MACRO_OFFSET record in AST file"); - return Failure; - } + if (F.LocalNumMacros != 0) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "duplicate MACRO_OFFSET record in AST file"); F.MacroOffsets = (const uint32_t *)Blob.data(); F.LocalNumMacros = Record[0]; unsigned LocalBaseMacroID = Record[1]; @@ -3731,26 +3708,24 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case OPTIMIZE_PRAGMA_OPTIONS: - if (Record.size() != 1) { - Error("invalid pragma optimize record"); - return Failure; - } + if (Record.size() != 1) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid pragma optimize record"); OptimizeOffPragmaLocation = ReadSourceLocation(F, Record[0]); break; case MSSTRUCT_PRAGMA_OPTIONS: - if (Record.size() != 1) { - Error("invalid pragma ms_struct record"); - return Failure; - } + if (Record.size() != 1) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid pragma ms_struct record"); PragmaMSStructState = Record[0]; break; case POINTERS_TO_MEMBERS_PRAGMA_OPTIONS: - if (Record.size() != 2) { - Error("invalid pragma ms_struct record"); - return Failure; - } + if (Record.size() != 2) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "invalid pragma pointers to members record"); PragmaMSPointersToMembersState = Record[0]; PointersToMembersPragmaLocation = ReadSourceLocation(F, Record[1]); break; @@ -3762,18 +3737,16 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case CUDA_PRAGMA_FORCE_HOST_DEVICE_DEPTH: - if (Record.size() != 1) { - Error("invalid cuda pragma options record"); - return Failure; - } + if (Record.size() != 1) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid cuda pragma options record"); ForceCUDAHostDeviceDepth = Record[0]; break; case ALIGN_PACK_PRAGMA_OPTIONS: { - if (Record.size() < 3) { - Error("invalid pragma pack record"); - return Failure; - } + if (Record.size() < 3) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid pragma pack record"); PragmaAlignPackCurrentValue = ReadAlignPackInfo(Record[0]); PragmaAlignPackCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; @@ -3793,10 +3766,9 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case FLOAT_CONTROL_PRAGMA_OPTIONS: { - if (Record.size() < 3) { - Error("invalid pragma pack record"); - return Failure; - } + if (Record.size() < 3) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "invalid pragma float control record"); FpPragmaCurrentValue = FPOptionsOverride::getFromOpaqueInt(Record[0]); FpPragmaCurrentLocation = ReadSourceLocation(F, Record[1]); unsigned NumStackEntries = Record[2]; @@ -3935,7 +3907,8 @@ ASTReader::ReadModuleMapFileBlock(RecordData &Record, ModuleFile &F, if (F.Kind == MK_ImplicitModule && ModuleMgr.begin()->Kind != MK_MainFile) { // An implicitly-loaded module file should have its module listed in some // module map file that we've already loaded. - Module *M = PP.getHeaderSearchInfo().lookupModule(F.ModuleName); + Module *M = + PP.getHeaderSearchInfo().lookupModule(F.ModuleName, F.ImportLoc); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); const FileEntry *ModMap = M ? Map.getModuleMapFileForUniquing(M) : nullptr; // Don't emit module relocation error if we have -fno-validate-pch @@ -4240,8 +4213,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, PreviousGeneration = incrementGeneration(*ContextObj); unsigned NumModules = ModuleMgr.size(); - auto removeModulesAndReturn = [&](ASTReadResult ReadResult) { - assert(ReadResult && "expected to return error"); + SmallVector Loaded; + if (ASTReadResult ReadResult = + ReadASTCore(FileName, Type, ImportLoc, + /*ImportedBy=*/nullptr, Loaded, 0, 0, ASTFileSignature(), + ClientLoadCapabilities)) { ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, PP.getLangOpts().Modules ? &PP.getHeaderSearchInfo().getModuleMap() @@ -4252,45 +4228,38 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, GlobalIndex.reset(); ModuleMgr.setGlobalIndex(nullptr); return ReadResult; - }; - - SmallVector Loaded; - switch (ASTReadResult ReadResult = - ReadASTCore(FileName, Type, ImportLoc, - /*ImportedBy=*/nullptr, Loaded, 0, 0, - ASTFileSignature(), ClientLoadCapabilities)) { - case Failure: - case Missing: - case OutOfDate: - case VersionMismatch: - case ConfigurationMismatch: - case HadErrors: - return removeModulesAndReturn(ReadResult); - case Success: - break; } - // Here comes stuff that we only do once the entire chain is loaded. + // Here comes stuff that we only do once the entire chain is loaded. Do *not* + // remove modules from this point. Various fields are updated during reading + // the AST block and removing the modules would result in dangling pointers. + // They are generally only incidentally dereferenced, ie. a binary search + // runs over `GlobalSLocEntryMap`, which could cause an invalid module to + // be dereferenced but it wouldn't actually be used. - // Load the AST blocks of all of the modules that we loaded. We can still + // Load the AST blocks of all of the modules that we loaded. We can still // hit errors parsing the ASTs at this point. for (ImportedModule &M : Loaded) { ModuleFile &F = *M.Mod; // Read the AST block. - if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities)) - return removeModulesAndReturn(Result); + if (llvm::Error Err = ReadASTBlock(F, ClientLoadCapabilities)) { + Error(std::move(Err)); + return Failure; + } // The AST block should always have a definition for the main module. if (F.isModule() && !F.DidReadTopLevelSubmodule) { Error(diag::err_module_file_missing_top_level_submodule, F.FileName); - return removeModulesAndReturn(Failure); + return Failure; } // Read the extension blocks. while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { - if (ASTReadResult Result = ReadExtensionBlock(F)) - return removeModulesAndReturn(Result); + if (llvm::Error Err = ReadExtensionBlock(F)) { + Error(std::move(Err)); + return Failure; + } } // Once read, set the ModuleFile bit base offset and update the size in @@ -4754,7 +4723,9 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( // Read and process a record. Record.clear(); - Expected MaybeRecordType = Stream.readRecord(Entry.ID, Record); + StringRef Blob; + Expected MaybeRecordType = + Stream.readRecord(Entry.ID, Record, &Blob); if (!MaybeRecordType) { // FIXME this drops the error. return Failure; @@ -4786,6 +4757,17 @@ ASTReader::ASTReadResult ASTReader::readUnhashedControlBlockImpl( F->PragmaDiagMappings.insert(F->PragmaDiagMappings.end(), Record.begin(), Record.end()); break; + case HEADER_SEARCH_ENTRY_USAGE: + if (!F) + break; + unsigned Count = Record[0]; + const char *Byte = Blob.data(); + F->SearchPathUsage = llvm::BitVector(Count, 0); + for (unsigned I = 0; I < Count; ++Byte) + for (unsigned Bit = 0; Bit < 8 && I < Count; ++Bit, ++I) + if (*Byte & (1 << Bit)) + F->SearchPathUsage[I] = 1; + break; } } } @@ -4811,32 +4793,26 @@ static bool parseModuleFileExtensionMetadata( return false; } -ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { +llvm::Error ASTReader::ReadExtensionBlock(ModuleFile &F) { BitstreamCursor &Stream = F.Stream; RecordData Record; while (true) { Expected MaybeEntry = Stream.advance(); - if (!MaybeEntry) { - Error(MaybeEntry.takeError()); - return Failure; - } + if (!MaybeEntry) + return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: - if (llvm::Error Err = Stream.SkipBlock()) { - Error(std::move(Err)); - return Failure; - } + if (llvm::Error Err = Stream.SkipBlock()) + return Err; continue; - case llvm::BitstreamEntry::EndBlock: - return Success; - + return llvm::Error::success(); case llvm::BitstreamEntry::Error: - return HadErrors; - + return llvm::createStringError(std::errc::illegal_byte_sequence, + "malformed block record in AST file"); case llvm::BitstreamEntry::Record: break; } @@ -4845,17 +4821,15 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { StringRef Blob; Expected MaybeRecCode = Stream.readRecord(Entry.ID, Record, &Blob); - if (!MaybeRecCode) { - Error(MaybeRecCode.takeError()); - return Failure; - } + if (!MaybeRecCode) + return MaybeRecCode.takeError(); switch (MaybeRecCode.get()) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; - if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) { - Error("malformed EXTENSION_METADATA in AST file"); - return Failure; - } + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "malformed EXTENSION_METADATA in AST file"); // Find a module file extension with this block name. auto Known = ModuleFileExtensions.find(Metadata.BlockName); @@ -4872,7 +4846,7 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { } } - return Success; + return llvm::Error::success(); } void ASTReader::InitializeContext() { @@ -5452,13 +5426,11 @@ bool ASTReader::isAcceptableASTFile(StringRef Filename, FileManager &FileMgr, /*ValidateDiagnosticOptions=*/true); } -ASTReader::ASTReadResult -ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { +llvm::Error ASTReader::ReadSubmoduleBlock(ModuleFile &F, + unsigned ClientLoadCapabilities) { // Enter the submodule block. - if (llvm::Error Err = F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) { - Error(std::move(Err)); - return Failure; - } + if (llvm::Error Err = F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) + return Err; ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); bool First = true; @@ -5467,19 +5439,17 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { while (true) { Expected MaybeEntry = F.Stream.advanceSkippingSubblocks(); - if (!MaybeEntry) { - Error(MaybeEntry.takeError()); - return Failure; - } + if (!MaybeEntry) + return MaybeEntry.takeError(); llvm::BitstreamEntry Entry = MaybeEntry.get(); switch (Entry.Kind) { case llvm::BitstreamEntry::SubBlock: // Handled for us already. case llvm::BitstreamEntry::Error: - Error("malformed block record in AST file"); - return Failure; + return llvm::createStringError(std::errc::illegal_byte_sequence, + "malformed block record in AST file"); case llvm::BitstreamEntry::EndBlock: - return Success; + return llvm::Error::success(); case llvm::BitstreamEntry::Record: // The interesting case. break; @@ -5489,16 +5459,14 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { StringRef Blob; Record.clear(); Expected MaybeKind = F.Stream.readRecord(Entry.ID, Record, &Blob); - if (!MaybeKind) { - Error(MaybeKind.takeError()); - return Failure; - } + if (!MaybeKind) + return MaybeKind.takeError(); unsigned Kind = MaybeKind.get(); - if ((Kind == SUBMODULE_METADATA) != First) { - Error("submodule metadata record should be at beginning of block"); - return Failure; - } + if ((Kind == SUBMODULE_METADATA) != First) + return llvm::createStringError( + std::errc::illegal_byte_sequence, + "submodule metadata record should be at beginning of block"); First = false; // Submodule information is only valid if we have a current module. @@ -5512,10 +5480,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SUBMODULE_DEFINITION: { - if (Record.size() < 12) { - Error("malformed module definition"); - return Failure; - } + if (Record.size() < 12) + return llvm::createStringError(std::errc::illegal_byte_sequence, + "malformed module definition"); StringRef Name = Blob; unsigned Idx = 0; @@ -5547,10 +5514,9 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { SubmoduleID GlobalIndex = GlobalID - NUM_PREDEF_SUBMODULE_IDS; if (GlobalIndex >= SubmodulesLoaded.size() || - SubmodulesLoaded[GlobalIndex]) { - Error("too many submodules"); - return Failure; - } + SubmodulesLoaded[GlobalIndex]) + return llvm::createStringError(std::errc::invalid_argument, + "too many submodules"); if (!ParentModule) { if (const FileEntry *CurFile = CurrentModule->getASTFile()) { @@ -5558,10 +5524,12 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { if (!bool(PP.getPreprocessorOpts().DisablePCHOrModuleValidation & DisableValidationForModuleKind::Module) && CurFile != F.File) { - Error(diag::err_module_file_conflict, - CurrentModule->getTopLevelModuleName(), CurFile->getName(), - F.File->getName()); - return Failure; + auto ConflictError = + PartialDiagnostic(diag::err_module_file_conflict, + ContextObj->DiagAllocator) + << CurrentModule->getTopLevelModuleName() << CurFile->getName() + << F.File->getName(); + return DiagnosticError::create(CurrentImportLoc, ConflictError); } } @@ -5605,17 +5573,20 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { } case SUBMODULE_UMBRELLA_HEADER: { + // FIXME: This doesn't work for framework modules as `Filename` is the + // name as written in the module file and does not include + // `Headers/`, so this path will never exist. std::string Filename = std::string(Blob); ResolveImportedPath(F, Filename); if (auto Umbrella = PP.getFileManager().getFile(Filename)) { - if (!CurrentModule->getUmbrellaHeader()) + if (!CurrentModule->getUmbrellaHeader()) { // FIXME: NameAsWritten ModMap.setUmbrellaHeader(CurrentModule, *Umbrella, Blob, ""); - else if (CurrentModule->getUmbrellaHeader().Entry != *Umbrella) { - if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) - Error("mismatched umbrella headers in submodule"); - return OutOfDate; } + // Note that it's too late at this point to return out of date if the + // name from the PCM doesn't match up with the one in the module map, + // but also quite unlikely since we will have already checked the + // modification time and size of the module map file itself. } break; } @@ -5639,16 +5610,13 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SUBMODULE_UMBRELLA_DIR: { + // See comments in SUBMODULE_UMBRELLA_HEADER std::string Dirname = std::string(Blob); ResolveImportedPath(F, Dirname); if (auto Umbrella = PP.getFileManager().getDirectory(Dirname)) { - if (!CurrentModule->getUmbrellaDir()) + if (!CurrentModule->getUmbrellaDir()) { // FIXME: NameAsWritten ModMap.setUmbrellaDir(CurrentModule, *Umbrella, Blob, ""); - else if (CurrentModule->getUmbrellaDir().Entry != *Umbrella) { - if ((ClientLoadCapabilities & ARR_OutOfDate) == 0) - Error("mismatched umbrella directories in submodule"); - return OutOfDate; } } break; @@ -6984,6 +6952,9 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_FLOAT128_ID: T = Context.Float128Ty; break; + case PREDEF_TYPE_IBM128_ID: + T = Context.Ibm128Ty; + break; case PREDEF_TYPE_OVERLOAD_ID: T = Context.OverloadTy; break; @@ -7730,24 +7701,17 @@ void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) { void ASTReader::PrintStats() { std::fprintf(stderr, "*** AST File Statistics:\n"); - unsigned NumTypesLoaded - = TypesLoaded.size() - std::count(TypesLoaded.begin(), TypesLoaded.end(), - QualType()); - unsigned NumDeclsLoaded - = DeclsLoaded.size() - std::count(DeclsLoaded.begin(), DeclsLoaded.end(), - (Decl *)nullptr); - unsigned NumIdentifiersLoaded - = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), - IdentifiersLoaded.end(), - (IdentifierInfo *)nullptr); - unsigned NumMacrosLoaded - = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), - MacrosLoaded.end(), - (MacroInfo *)nullptr); - unsigned NumSelectorsLoaded - = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), - SelectorsLoaded.end(), - Selector()); + unsigned NumTypesLoaded = + TypesLoaded.size() - llvm::count(TypesLoaded, QualType()); + unsigned NumDeclsLoaded = + DeclsLoaded.size() - llvm::count(DeclsLoaded, (Decl *)nullptr); + unsigned NumIdentifiersLoaded = + IdentifiersLoaded.size() - + llvm::count(IdentifiersLoaded, (IdentifierInfo *)nullptr); + unsigned NumMacrosLoaded = + MacrosLoaded.size() - llvm::count(MacrosLoaded, (MacroInfo *)nullptr); + unsigned NumSelectorsLoaded = + SelectorsLoaded.size() - llvm::count(SelectorsLoaded, Selector()); if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", @@ -8187,13 +8151,16 @@ namespace serialization { if (Reader.DeserializationListener) Reader.DeserializationListener->SelectorRead(Data.ID, Sel); - InstanceMethods.append(Data.Instance.begin(), Data.Instance.end()); - FactoryMethods.append(Data.Factory.begin(), Data.Factory.end()); + // Append methods in the reverse order, so that later we can process them + // in the order they appear in the source code by iterating through + // the vector in the reverse order. + InstanceMethods.append(Data.Instance.rbegin(), Data.Instance.rend()); + FactoryMethods.append(Data.Factory.rbegin(), Data.Factory.rend()); InstanceBits = Data.InstanceBits; FactoryBits = Data.FactoryBits; InstanceHasMoreThanOneDecl = Data.InstanceHasMoreThanOneDecl; FactoryHasMoreThanOneDecl = Data.FactoryHasMoreThanOneDecl; - return true; + return false; } /// Retrieve the instance methods found by this visitor. @@ -8222,9 +8189,8 @@ namespace serialization { /// Add the given set of methods to the method list. static void addMethodsToPool(Sema &S, ArrayRef Methods, ObjCMethodList &List) { - for (unsigned I = 0, N = Methods.size(); I != N; ++I) { - S.addMethodToGlobalList(&List, Methods[I]); - } + for (auto I = Methods.rbegin(), E = Methods.rend(); I != E; ++I) + S.addMethodToGlobalList(&List, *I); } void ASTReader::ReadMethodPool(Selector Sel) { @@ -8249,8 +8215,9 @@ void ASTReader::ReadMethodPool(Selector Sel) { return; Sema &S = *getSema(); - Sema::GlobalMethodPool::iterator Pos - = S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethods())).first; + Sema::GlobalMethodPool::iterator Pos = + S.MethodPool.insert(std::make_pair(Sel, Sema::GlobalMethodPool::Lists())) + .first; Pos->second.first.setBits(Visitor.getInstanceBits()); Pos->second.first.setHasMoreThanOneDecl(Visitor.instanceHasMoreThanOneDecl()); @@ -8456,6 +8423,8 @@ void ASTReader::ReadLateParsedTemplates( LPTMap.insert(std::make_pair(FD, std::move(LT))); } } + + LateParsedTemplates.clear(); } void ASTReader::LoadSelector(Selector Sel) { @@ -12002,6 +11971,12 @@ OMPClause *OMPClauseReader::readClause() { case llvm::omp::OMPC_filter: C = new (Context) OMPFilterClause(); break; + case llvm::omp::OMPC_bind: + C = OMPBindClause::CreateEmpty(Context); + break; + case llvm::omp::OMPC_align: + C = new (Context) OMPAlignClause(); + break; #define OMP_CLAUSE_NO_CLASS(Enum, Str) \ case llvm::omp::Enum: \ break; @@ -12986,6 +12961,17 @@ void OMPClauseReader::VisitOMPFilterClause(OMPFilterClause *C) { C->setLParenLoc(Record.readSourceLocation()); } +void OMPClauseReader::VisitOMPBindClause(OMPBindClause *C) { + C->setBindKind(Record.readEnum()); + C->setLParenLoc(Record.readSourceLocation()); + C->setBindKindLoc(Record.readSourceLocation()); +} + +void OMPClauseReader::VisitOMPAlignClause(OMPAlignClause *C) { + C->setAlignment(Record.readExpr()); + C->setLParenLoc(Record.readSourceLocation()); +} + OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index ff79f91e5db..62a31f299d6 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -332,7 +332,7 @@ namespace clang { RedeclarableResult VisitTagDecl(TagDecl *TD); void VisitEnumDecl(EnumDecl *ED); RedeclarableResult VisitRecordDeclImpl(RecordDecl *RD); - void VisitRecordDecl(RecordDecl *RD) { VisitRecordDeclImpl(RD); } + void VisitRecordDecl(RecordDecl *RD); RedeclarableResult VisitCXXRecordDeclImpl(CXXRecordDecl *D); void VisitCXXRecordDecl(CXXRecordDecl *D) { VisitCXXRecordDeclImpl(D); } RedeclarableResult VisitClassTemplateSpecializationDeclImpl( @@ -808,6 +808,34 @@ ASTDeclReader::VisitRecordDeclImpl(RecordDecl *RD) { return Redecl; } +void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) { + VisitRecordDeclImpl(RD); + + // Maintain the invariant of a redeclaration chain containing only + // a single definition. + if (RD->isCompleteDefinition()) { + RecordDecl *Canon = static_cast(RD->getCanonicalDecl()); + RecordDecl *&OldDef = Reader.RecordDefinitions[Canon]; + if (!OldDef) { + // This is the first time we've seen an imported definition. Look for a + // local definition before deciding that we are the first definition. + for (auto *D : merged_redecls(Canon)) { + if (!D->isFromASTFile() && D->isCompleteDefinition()) { + OldDef = D; + break; + } + } + } + if (OldDef) { + Reader.MergedDeclContexts.insert(std::make_pair(RD, OldDef)); + RD->setCompleteDefinition(false); + Reader.mergeDefinitionVisibility(OldDef, RD); + } else { + OldDef = RD; + } + } +} + void ASTDeclReader::VisitValueDecl(ValueDecl *VD) { VisitNamedDecl(VD); // For function declarations, defer reading the type in case the function has @@ -1149,6 +1177,13 @@ void ASTDeclReader::ReadObjCDefinitionData( void ASTDeclReader::MergeDefinitionData(ObjCInterfaceDecl *D, struct ObjCInterfaceDecl::DefinitionData &&NewDD) { + struct ObjCInterfaceDecl::DefinitionData &DD = D->data(); + if (DD.Definition != NewDD.Definition) { + Reader.MergedDeclContexts.insert( + std::make_pair(NewDD.Definition, DD.Definition)); + Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition); + } + // FIXME: odr checking? } @@ -1215,6 +1250,13 @@ void ASTDeclReader::ReadObjCDefinitionData( void ASTDeclReader::MergeDefinitionData(ObjCProtocolDecl *D, struct ObjCProtocolDecl::DefinitionData &&NewDD) { + struct ObjCProtocolDecl::DefinitionData &DD = D->data(); + if (DD.Definition != NewDD.Definition) { + Reader.MergedDeclContexts.insert( + std::make_pair(NewDD.Definition, DD.Definition)); + Reader.mergeDefinitionVisibility(DD.Definition, NewDD.Definition); + } + // FIXME: odr checking? } @@ -1736,7 +1778,7 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.HasODRHash = true; if (Record.readInt()) { - Reader.DefinitionSource[D] = + Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile || Reader.getContext().getLangOpts().BuildingPCHWithObjectFile; } @@ -2645,7 +2687,7 @@ static bool allowODRLikeMergeInC(NamedDecl *ND) { if (!ND) return false; // TODO: implement merge for other necessary decls. - if (isa(ND)) + if (isa(ND)) return true; return false; } @@ -3315,10 +3357,16 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader, return DD->Definition; } + if (auto *RD = dyn_cast(DC)) + return RD->getDefinition(); + if (auto *ED = dyn_cast(DC)) return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition() : nullptr; + if (auto *OID = dyn_cast(DC)) + return OID->getDefinition(); + // We can see the TU here only if we have no Sema object. In that case, // there's no TU scope to look in, so using the DC alone is sufficient. if (auto *TU = dyn_cast(DC)) @@ -3398,6 +3446,9 @@ ASTDeclReader::getPrimaryDCForAnonymousDecl(DeclContext *LexicalDC) { if (auto *MD = dyn_cast(D)) if (MD->isThisDeclarationADefinition()) return MD; + if (auto *RD = dyn_cast(D)) + if (RD->isThisDeclarationADefinition()) + return RD; } // No merged definition yet. @@ -3817,7 +3868,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { Expected MaybeDeclCode = Record.readRecord(DeclsCursor, Code); if (!MaybeDeclCode) llvm::report_fatal_error( - "ASTReader::readDeclRecord failed reading decl code: " + + Twine("ASTReader::readDeclRecord failed reading decl code: ") + toString(MaybeDeclCode.takeError())); switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: @@ -4202,12 +4253,12 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { if (llvm::Error JumpFailed = Cursor.JumpToBit(Offset)) // FIXME don't do a fatal error. llvm::report_fatal_error( - "ASTReader::loadDeclUpdateRecords failed jumping: " + + Twine("ASTReader::loadDeclUpdateRecords failed jumping: ") + toString(std::move(JumpFailed))); Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) llvm::report_fatal_error( - "ASTReader::loadDeclUpdateRecords failed reading code: " + + Twine("ASTReader::loadDeclUpdateRecords failed reading code: ") + toString(MaybeCode.takeError())); unsigned Code = MaybeCode.get(); ASTRecordReader Record(*this, *F); @@ -4216,7 +4267,7 @@ void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) { "Expected DECL_UPDATES record!"); else llvm::report_fatal_error( - "ASTReader::loadDeclUpdateRecords failed reading rec code: " + + Twine("ASTReader::loadDeclUpdateRecords failed reading rec code: ") + toString(MaybeCode.takeError())); ASTDeclReader Reader(*this, Record, RecordLocation(F, Offset), ID, @@ -4283,14 +4334,14 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { SavedStreamPosition SavedPosition(Cursor); if (llvm::Error JumpFailed = Cursor.JumpToBit(LocalOffset)) llvm::report_fatal_error( - "ASTReader::loadPendingDeclChain failed jumping: " + + Twine("ASTReader::loadPendingDeclChain failed jumping: ") + toString(std::move(JumpFailed))); RecordData Record; Expected MaybeCode = Cursor.ReadCode(); if (!MaybeCode) llvm::report_fatal_error( - "ASTReader::loadPendingDeclChain failed reading code: " + + Twine("ASTReader::loadPendingDeclChain failed reading code: ") + toString(MaybeCode.takeError())); unsigned Code = MaybeCode.get(); if (Expected MaybeRecCode = Cursor.readRecord(Code, Record)) @@ -4298,7 +4349,7 @@ void ASTReader::loadPendingDeclChain(Decl *FirstLocal, uint64_t LocalOffset) { "expected LOCAL_REDECLARATIONS record!"); else llvm::report_fatal_error( - "ASTReader::loadPendingDeclChain failed reading rec code: " + + Twine("ASTReader::loadPendingDeclChain failed reading rec code: ") + toString(MaybeCode.takeError())); // FIXME: We have several different dispatches on decl kind here; maybe @@ -4706,9 +4757,10 @@ void ASTDeclReader::UpdateDecl(Decl *D, auto AllocatorKind = static_cast(Record.readInt()); Expr *Allocator = Record.readExpr(); + Expr *Alignment = Record.readExpr(); SourceRange SR = readSourceRange(); D->addAttr(OMPAllocateDeclAttr::CreateImplicit( - Reader.getContext(), AllocatorKind, Allocator, SR, + Reader.getContext(), AllocatorKind, Allocator, Alignment, SR, AttributeCommonInfo::AS_Pragma)); break; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index b100f946f55..b82a334b763 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -213,11 +213,11 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { void ASTStmtReader::VisitIfStmt(IfStmt *S) { VisitStmt(S); - S->setConstexpr(Record.readInt()); bool HasElse = Record.readInt(); bool HasVar = Record.readInt(); bool HasInit = Record.readInt(); + S->setStatementKind(static_cast(Record.readInt())); S->setCond(Record.readSubExpr()); S->setThen(Record.readSubStmt()); if (HasElse) @@ -2307,6 +2307,13 @@ void ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) { VisitOMPLoopBasedDirective(D); } +void ASTStmtReader::VisitOMPMetaDirective(OMPMetaDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); @@ -2317,12 +2324,18 @@ void ASTStmtReader::VisitOMPSimdDirective(OMPSimdDirective *D) { VisitOMPLoopDirective(D); } -void ASTStmtReader::VisitOMPTileDirective(OMPTileDirective *D) { +void ASTStmtReader::VisitOMPLoopTransformationDirective( + OMPLoopTransformationDirective *D) { VisitOMPLoopBasedDirective(D); + D->setNumGeneratedLoops(Record.readUInt32()); +} + +void ASTStmtReader::VisitOMPTileDirective(OMPTileDirective *D) { + VisitOMPLoopTransformationDirective(D); } void ASTStmtReader::VisitOMPUnrollDirective(OMPUnrollDirective *D) { - VisitOMPLoopBasedDirective(D); + VisitOMPLoopTransformationDirective(D); } void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) { @@ -2403,6 +2416,8 @@ void ASTStmtReader::VisitOMPBarrierDirective(OMPBarrierDirective *D) { void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) { VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); VisitOMPExecutableDirective(D); } @@ -2619,6 +2634,10 @@ void ASTStmtReader::VisitOMPMaskedDirective(OMPMaskedDirective *D) { VisitOMPExecutableDirective(D); } +void ASTStmtReader::VisitOMPGenericLoopDirective(OMPGenericLoopDirective *D) { + VisitOMPLoopDirective(D); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -2746,9 +2765,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case STMT_IF: S = IfStmt::CreateEmpty( Context, - /* HasElse=*/Record[ASTStmtReader::NumStmtFields + 1], - /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 2], - /* HasInit=*/Record[ASTStmtReader::NumStmtFields + 3]); + /* HasElse=*/Record[ASTStmtReader::NumStmtFields], + /* HasVar=*/Record[ASTStmtReader::NumStmtFields + 1], + /* HasInit=*/Record[ASTStmtReader::NumStmtFields + 2]); break; case STMT_SWITCH: @@ -3183,6 +3202,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = OMPCanonicalLoop::createEmpty(Context); break; + case STMT_OMP_META_DIRECTIVE: + S = OMPMetaDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_PARALLEL_DIRECTIVE: S = OMPParallelDirective::CreateEmpty(Context, @@ -3291,7 +3315,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; case STMT_OMP_TASKWAIT_DIRECTIVE: - S = OMPTaskwaitDirective::CreateEmpty(Context, Empty); + S = OMPTaskwaitDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); break; case STMT_OMP_TASKGROUP_DIRECTIVE: @@ -3560,6 +3585,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { Context, Record[ASTStmtReader::NumStmtFields], Empty); break; + case STMT_OMP_GENERIC_LOOP_DIRECTIVE: { + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields]; + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPGenericLoopDirective::CreateEmpty(Context, NumClauses, + CollapsedNum, Empty); + break; + } + case EXPR_CXX_OPERATOR_CALL: S = CXXOperatorCallExpr::CreateEmpty( Context, /*NumArgs=*/Record[ASTStmtReader::NumExprFields], diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 66c207ad924..a1972f5c649 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -132,6 +132,18 @@ static StringRef bytes(const SmallVectorImpl &v) { sizeof(T) * v.size()); } +static std::string bytes(const std::vector &V) { + std::string Str; + Str.reserve(V.size() / 8); + for (unsigned I = 0, E = V.size(); I < E;) { + char Byte = 0; + for (unsigned Bit = 0; Bit < 8 && I < E; ++Bit, ++I) + Byte |= V[I] << Bit; + Str += Byte; + } + return Str; +} + //===----------------------------------------------------------------------===// // Type serialization //===----------------------------------------------------------------------===// @@ -149,6 +161,59 @@ static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) { namespace { +std::set GetAllModuleMaps(const HeaderSearch &HS, + Module *RootModule) { + std::set ModuleMaps{}; + std::set ProcessedModules; + SmallVector ModulesToProcess{RootModule}; + + SmallVector FilesByUID; + HS.getFileMgr().GetUniqueIDMapping(FilesByUID); + + if (FilesByUID.size() > HS.header_file_size()) + FilesByUID.resize(HS.header_file_size()); + + for (unsigned UID = 0, LastUID = FilesByUID.size(); UID != LastUID; ++UID) { + const FileEntry *File = FilesByUID[UID]; + if (!File) + continue; + + const HeaderFileInfo *HFI = + HS.getExistingFileInfo(File, /*WantExternal*/ false); + if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader)) + continue; + + for (const auto &KH : HS.findAllModulesForHeader(File)) { + if (!KH.getModule()) + continue; + ModulesToProcess.push_back(KH.getModule()); + } + } + + while (!ModulesToProcess.empty()) { + auto *CurrentModule = ModulesToProcess.pop_back_val(); + ProcessedModules.insert(CurrentModule); + + auto *ModuleMapFile = + HS.getModuleMap().getModuleMapFileForUniquing(CurrentModule); + if (!ModuleMapFile) { + continue; + } + + ModuleMaps.insert(ModuleMapFile); + + for (auto *ImportedModule : (CurrentModule)->Imports) { + if (!ImportedModule || + ProcessedModules.find(ImportedModule) != ProcessedModules.end()) { + continue; + } + ModulesToProcess.push_back(ImportedModule); + } + } + + return ModuleMaps; +} + class ASTTypeWriter { ASTWriter &Writer; ASTWriter::RecordData Record; @@ -1050,6 +1115,8 @@ ASTWriter::createSignature(StringRef AllBytes, StringRef ASTBlockBytes) { ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, ASTContext &Context) { + using namespace llvm; + // Flush first to prepare the PCM hash (signature). Stream.FlushToWord(); auto StartOfUnhashedControl = Stream.GetCurrentBitNo() >> 3; @@ -1093,10 +1160,24 @@ ASTFileSignature ASTWriter::writeUnhashedControlBlock(Preprocessor &PP, // Note: we don't serialize the log or serialization file names, because they // are generally transient files and will almost always be overridden. Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); + Record.clear(); // Write out the diagnostic/pragma mappings. WritePragmaDiagnosticMappings(Diags, /* isModule = */ WritingModule); + // Header search entry usage. + auto HSEntryUsage = PP.getHeaderSearchInfo().computeUserEntryUsage(); + auto Abbrev = std::make_shared(); + Abbrev->Add(BitCodeAbbrevOp(HEADER_SEARCH_ENTRY_USAGE)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Number of bits. + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Bit vector. + unsigned HSUsageAbbrevCode = Stream.EmitAbbrev(std::move(Abbrev)); + { + RecordData::value_type Record[] = {HEADER_SEARCH_ENTRY_USAGE, + HSEntryUsage.size()}; + Stream.EmitRecordWithBlob(HSUsageAbbrevCode, Record, bytes(HSEntryUsage)); + } + // Leave the options block. Stream.ExitBlock(); return Signature; @@ -1396,9 +1477,15 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } + std::set AffectingModuleMaps; + if (WritingModule) { + AffectingModuleMaps = + GetAllModuleMaps(PP.getHeaderSearchInfo(), WritingModule); + } + WriteInputFiles(Context.SourceMgr, PP.getHeaderSearchInfo().getHeaderSearchOpts(), - PP.getLangOpts().Modules); + AffectingModuleMaps); Stream.ExitBlock(); } @@ -1416,9 +1503,9 @@ struct InputFileEntry { } // namespace -void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, - HeaderSearchOptions &HSOpts, - bool Modules) { +void ASTWriter::WriteInputFiles( + SourceManager &SourceMgr, HeaderSearchOptions &HSOpts, + std::set &AffectingModuleMaps) { using namespace llvm; Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); @@ -1458,6 +1545,16 @@ void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, if (!Cache->OrigEntry) continue; + if (isModuleMap(File.getFileCharacteristic()) && + !isSystem(File.getFileCharacteristic()) && + !AffectingModuleMaps.empty() && + AffectingModuleMaps.find(Cache->OrigEntry) == + AffectingModuleMaps.end()) { + SkippedModuleMaps.insert(Cache->OrigEntry); + // Do not emit modulemaps that do not affect current module. + continue; + } + InputFileEntry Entry; Entry.File = Cache->OrigEntry; Entry.IsSystemFile = isSystem(File.getFileCharacteristic()); @@ -1971,11 +2068,17 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(SLoc->getOffset() - 2); if (SLoc->isFile()) { const SrcMgr::FileInfo &File = SLoc->getFile(); + const SrcMgr::ContentCache *Content = &File.getContentCache(); + if (Content->OrigEntry && !SkippedModuleMaps.empty() && + SkippedModuleMaps.find(Content->OrigEntry) != + SkippedModuleMaps.end()) { + // Do not emit files that were not listed as inputs. + continue; + } AddSourceLocation(File.getIncludeLoc(), Record); Record.push_back(File.getFileCharacteristic()); // FIXME: stable encoding Record.push_back(File.hasLineDirectives()); - const SrcMgr::ContentCache *Content = &File.getContentCache(); bool EmitBlob = false; if (Content->OrigEntry) { assert(Content->OrigEntry == Content->ContentsEntry && @@ -3017,11 +3120,11 @@ public: unsigned DataLen = 4 + 2 + 2; // 2 bytes for each of the method counts for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) DataLen += 4; for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) DataLen += 4; return emitULEBKeyDataLength(KeyLen, DataLen, Out); } @@ -3052,13 +3155,13 @@ public: unsigned NumInstanceMethods = 0; for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) ++NumInstanceMethods; unsigned NumFactoryMethods = 0; for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) ++NumFactoryMethods; unsigned InstanceBits = Methods.Instance.getBits(); @@ -3079,15 +3182,20 @@ public: LE.write(FullFactoryBits); for (const ObjCMethodList *Method = &Methods.Instance; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) LE.write(Writer.getDeclID(Method->getMethod())); for (const ObjCMethodList *Method = &Methods.Factory; Method; Method = Method->getNext()) - if (Method->getMethod()) + if (ShouldWriteMethodListNode(Method)) LE.write(Writer.getDeclID(Method->getMethod())); assert(Out.tell() - Start == DataLen && "Data length is wrong"); } + +private: + static bool ShouldWriteMethodListNode(const ObjCMethodList *Node) { + return (Node->getMethod() && !Node->getMethod()->isFromASTFile()); + } }; } // namespace @@ -3130,15 +3238,21 @@ void ASTWriter::WriteSelectors(Sema &SemaRef) { if (Chain && ID < FirstSelectorID) { // Selector already exists. Did it change? bool changed = false; - for (ObjCMethodList *M = &Data.Instance; - !changed && M && M->getMethod(); M = M->getNext()) { - if (!M->getMethod()->isFromASTFile()) - changed = true; - } - for (ObjCMethodList *M = &Data.Factory; !changed && M && M->getMethod(); + for (ObjCMethodList *M = &Data.Instance; M && M->getMethod(); M = M->getNext()) { - if (!M->getMethod()->isFromASTFile()) + if (!M->getMethod()->isFromASTFile()) { changed = true; + Data.Instance = *M; + break; + } + } + for (ObjCMethodList *M = &Data.Factory; M && M->getMethod(); + M = M->getNext()) { + if (!M->getMethod()->isFromASTFile()) { + changed = true; + Data.Factory = *M; + break; + } } if (!changed) continue; @@ -3390,11 +3504,9 @@ public: // Only emit declarations that aren't from a chained PCH, though. SmallVector Decls(IdResolver.begin(II), IdResolver.end()); - for (SmallVectorImpl::reverse_iterator D = Decls.rbegin(), - DEnd = Decls.rend(); - D != DEnd; ++D) + for (NamedDecl *D : llvm::reverse(Decls)) LE.write( - Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), *D))); + Writer.getDeclID(getDeclForLocalLookup(PP.getLangOpts(), D))); } } }; @@ -4987,6 +5099,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { auto *A = D->getAttr(); Record.push_back(A->getAllocatorType()); Record.AddStmt(A->getAllocator()); + Record.AddStmt(A->getAlignment()); Record.AddSourceRange(A->getRange()); break; } @@ -6191,6 +6304,11 @@ void OMPClauseWriter::VisitOMPFilterClause(OMPFilterClause *C) { Record.AddSourceLocation(C->getLParenLoc()); } +void OMPClauseWriter::VisitOMPAlignClause(OMPAlignClause *C) { + Record.AddStmt(C->getAlignment()); + Record.AddSourceLocation(C->getLParenLoc()); +} + void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); @@ -6693,6 +6811,12 @@ void OMPClauseWriter::VisitOMPAffinityClause(OMPAffinityClause *C) { Record.AddStmt(E); } +void OMPClauseWriter::VisitOMPBindClause(OMPBindClause *C) { + Record.writeEnum(C->getBindKind()); + Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getBindKindLoc()); +} + void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { writeUInt32(TI->Sets.size()); for (const auto &Set : TI->Sets) { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index e9315f67d55..06cb60823db 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -2260,7 +2260,7 @@ void ASTWriter::WriteDeclAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Defaulted Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitlyDefaulted Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ImplicitReturnZero - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Constexpr + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Constexpr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // UsesSEHTry Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // SkippedBody Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // MultiVersion diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 2bb5e4f3563..2d92dec76dc 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -138,11 +138,10 @@ void ASTStmtWriter::VisitIfStmt(IfStmt *S) { bool HasVar = S->getConditionVariableDeclStmt() != nullptr; bool HasInit = S->getInit() != nullptr; - Record.push_back(S->isConstexpr()); Record.push_back(HasElse); Record.push_back(HasVar); Record.push_back(HasInit); - + Record.push_back(static_cast(S->getStatementKind())); Record.AddStmt(S->getCond()); Record.AddStmt(S->getThen()); if (HasElse) @@ -1483,8 +1482,8 @@ void ASTStmtWriter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { Record.push_back(S->getNumCatchStmts()); Record.push_back(S->getFinallyStmt() != nullptr); Record.AddStmt(S->getTryBody()); - for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) - Record.AddStmt(S->getCatchStmt(I)); + for (ObjCAtCatchStmt *C : S->catch_stmts()) + Record.AddStmt(C); if (S->getFinallyStmt()) Record.AddStmt(S->getFinallyStmt()); Record.AddSourceLocation(S->getAtTryLoc()); @@ -2205,6 +2204,13 @@ void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) { VisitOMPLoopBasedDirective(D); } +void ASTStmtWriter::VisitOMPMetaDirective(OMPMetaDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_META_DIRECTIVE; +} + void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); @@ -2217,13 +2223,19 @@ void ASTStmtWriter::VisitOMPSimdDirective(OMPSimdDirective *D) { Code = serialization::STMT_OMP_SIMD_DIRECTIVE; } -void ASTStmtWriter::VisitOMPTileDirective(OMPTileDirective *D) { +void ASTStmtWriter::VisitOMPLoopTransformationDirective( + OMPLoopTransformationDirective *D) { VisitOMPLoopBasedDirective(D); + Record.writeUInt32(D->getNumGeneratedLoops()); +} + +void ASTStmtWriter::VisitOMPTileDirective(OMPTileDirective *D) { + VisitOMPLoopTransformationDirective(D); Code = serialization::STMT_OMP_TILE_DIRECTIVE; } void ASTStmtWriter::VisitOMPUnrollDirective(OMPUnrollDirective *D) { - VisitOMPLoopBasedDirective(D); + VisitOMPLoopTransformationDirective(D); Code = serialization::STMT_OMP_UNROLL_DIRECTIVE; } @@ -2368,6 +2380,7 @@ void ASTStmtWriter::VisitOMPBarrierDirective(OMPBarrierDirective *D) { void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) { VisitStmt(D); + Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE; } @@ -2577,6 +2590,11 @@ void ASTStmtWriter::VisitOMPMaskedDirective(OMPMaskedDirective *D) { Code = serialization::STMT_OMP_MASKED_DIRECTIVE; } +void ASTStmtWriter::VisitOMPGenericLoopDirective(OMPGenericLoopDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_GENERIC_LOOP_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/Serialization/GeneratePCH.cpp b/clang/lib/Serialization/GeneratePCH.cpp index d869796b82c..6ec5c42e8b8 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -50,7 +50,8 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Module *Module = nullptr; if (PP.getLangOpts().isCompilingModule()) { Module = PP.getHeaderSearchInfo().lookupModule( - PP.getLangOpts().CurrentModule, /*AllowSearch*/ false); + PP.getLangOpts().CurrentModule, SourceLocation(), + /*AllowSearch*/ false); if (!Module) { assert(hasErrors && "emitting module but current module doesn't exist"); return; diff --git a/clang/lib/Serialization/ModuleFileExtension.cpp b/clang/lib/Serialization/ModuleFileExtension.cpp index 6b7fd1d5434..95fff41e0d7 100644 --- a/clang/lib/Serialization/ModuleFileExtension.cpp +++ b/clang/lib/Serialization/ModuleFileExtension.cpp @@ -11,12 +11,10 @@ using namespace clang; char ModuleFileExtension::ID = 0; -ModuleFileExtension::~ModuleFileExtension() { } +ModuleFileExtension::~ModuleFileExtension() {} -llvm::hash_code ModuleFileExtension::hashExtension(llvm::hash_code Code) const { - return Code; -} +void ModuleFileExtension::hashExtension(ExtensionHashBuilder &HBuilder) const {} -ModuleFileExtensionWriter::~ModuleFileExtensionWriter() { } +ModuleFileExtensionWriter::~ModuleFileExtensionWriter() {} -ModuleFileExtensionReader::~ModuleFileExtensionReader() { } +ModuleFileExtensionReader::~ModuleFileExtensionReader() {} diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index 40ffa6cfee8..f4882c7be3f 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -270,8 +270,7 @@ void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) { I->Imports.remove_if(IsVictim); I->ImportedBy.remove_if(IsVictim); } - Roots.erase(std::remove_if(Roots.begin(), Roots.end(), IsVictim), - Roots.end()); + llvm::erase_if(Roots, IsVictim); // Remove the modules from the PCH chain. for (auto I = First; I != Last; ++I) { @@ -384,16 +383,14 @@ void ModuleManager::visit(llvm::function_ref Visitor, // For any module that this module depends on, push it on the // stack (if it hasn't already been marked as visited). - for (auto M = CurrentModule->Imports.rbegin(), - MEnd = CurrentModule->Imports.rend(); - M != MEnd; ++M) { + for (ModuleFile *M : llvm::reverse(CurrentModule->Imports)) { // Remove our current module as an impediment to visiting the // module we depend on. If we were the last unvisited module // that depends on this particular module, push it into the // queue to be visited. - unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index]; + unsigned &NumUnusedEdges = UnusedIncomingEdges[M->Index]; if (NumUnusedEdges && (--NumUnusedEdges == 0)) - Queue.push_back(*M); + Queue.push_back(M); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp index c06604b6cff..6154eeb3419 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp @@ -93,11 +93,10 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, if (!Loc.isValid()) return; - if (isa(D) || isa(D)) { + if (isa(D)) { const NamedDecl *ND = cast(D); output << *ND; - } - else if (isa(D)) { + } else if (isa(D)) { output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); } diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index a86a410ebcb..2c210fb6cdb 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -20,9 +19,11 @@ #include "clang/AST/StmtObjC.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" #include "clang/Analysis/SelectorExtras.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" @@ -533,10 +534,12 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE, namespace { class CFRetainReleaseChecker : public Checker { mutable APIMisuse BT{this, "null passed to CF memory management function"}; - CallDescription CFRetain{"CFRetain", 1}, - CFRelease{"CFRelease", 1}, - CFMakeCollectable{"CFMakeCollectable", 1}, - CFAutorelease{"CFAutorelease", 1}; + const CallDescriptionSet ModelledCalls = { + {"CFRetain", 1}, + {"CFRelease", 1}, + {"CFMakeCollectable", 1}, + {"CFAutorelease", 1}, + }; public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; @@ -550,8 +553,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call, return; // Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease. - if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) || - Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease))) + if (!ModelledCalls.contains(Call)) return; // Get the argument's value. diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp index 2752b37f9b3..8416ab39e19 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -96,14 +97,7 @@ void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const { } bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const { - if (Call.isCalled(SleepFn) - || Call.isCalled(GetcFn) - || Call.isCalled(FgetsFn) - || Call.isCalled(ReadFn) - || Call.isCalled(RecvFn)) { - return true; - } - return false; + return matchesAny(Call, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn); } bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const { @@ -113,15 +107,8 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const return true; } - if (Call.isCalled(LockFn) - || Call.isCalled(PthreadLockFn) - || Call.isCalled(PthreadTryLockFn) - || Call.isCalled(MtxLock) - || Call.isCalled(MtxTimedLock) - || Call.isCalled(MtxTryLock)) { - return true; - } - return false; + return matchesAny(Call, LockFn, PthreadLockFn, PthreadTryLockFn, MtxLock, + MtxTimedLock, MtxTryLock); } bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const { @@ -132,12 +119,7 @@ bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) cons return true; } - if (Call.isCalled(UnlockFn) - || Call.isCalled(PthreadUnlockFn) - || Call.isCalled(MtxUnlock)) { - return true; - } - return false; + return matchesAny(Call, UnlockFn, PthreadUnlockFn, MtxUnlock); } void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call, diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 69b90be9aa7..475cee9ce04 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" @@ -2271,11 +2272,10 @@ CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, if (!FD) return nullptr; - if (Call.isCalled(StdCopy)) { + if (StdCopy.matches(Call)) return &CStringChecker::evalStdCopy; - } else if (Call.isCalled(StdCopyBackward)) { + if (StdCopyBackward.matches(Call)) return &CStringChecker::evalStdCopyBackward; - } // Pro-actively check that argument types are safe to do arithmetic upon. // We do not want to crash if someone accidentally passes a structure diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp index 131c1345af9..4235c0c1382 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp @@ -20,6 +20,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp index 175dfcef0df..a13de306eac 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a CheckObjCInstMethSignature, a flow-insenstive check +// This file defines a CheckObjCInstMethSignature, a flow-insensitive check // that determines if an Objective-C class interface incorrectly redefines // the method signature in a subclass. // diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index d06c87631bf..61ff5e59f06 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -785,9 +785,8 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE, // real flow analysis. auto FormatString = dyn_cast(CE->getArg(ArgIndex)->IgnoreParenImpCasts()); - if (FormatString && - FormatString->getString().find("%s") == StringRef::npos && - FormatString->getString().find("%[") == StringRef::npos) + if (FormatString && !FormatString->getString().contains("%s") && + !FormatString->getString().contains("%[")) BoundsProvided = true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index fd53c04f4bb..ce8d6c87987 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -63,11 +64,11 @@ private: } // end anonymous namespace bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { - if (Call.isCalled(Chroot)) { + if (Chroot.matches(Call)) { evalChroot(Call, C); return true; } - if (Call.isCalled(Chdir)) { + if (Chdir.matches(Call)) { evalChdir(Call, C); return true; } @@ -115,7 +116,7 @@ void ChrootChecker::evalChdir(const CallEvent &Call, CheckerContext &C) const { void ChrootChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // Ignore chroot and chdir. - if (Call.isCalled(Chroot) || Call.isCalled(Chdir)) + if (matchesAny(Call, Chroot, Chdir)) return; // If jail state is ROOT_CHANGED, generate BugReport. diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp index 1a7f0d5ab74..77a3218f55f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp @@ -10,11 +10,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/DeclTemplate.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" @@ -71,42 +72,27 @@ public: SVal) const; CallDescriptionMap NoIterParamFunctions = { - {{0, "clear", 0}, - &ContainerModeling::handleClear}, - {{0, "assign", 2}, - &ContainerModeling::handleAssign}, - {{0, "push_back", 1}, - &ContainerModeling::handlePushBack}, - {{0, "emplace_back", 1}, - &ContainerModeling::handlePushBack}, - {{0, "pop_back", 0}, - &ContainerModeling::handlePopBack}, - {{0, "push_front", 1}, - &ContainerModeling::handlePushFront}, - {{0, "emplace_front", 1}, - &ContainerModeling::handlePushFront}, - {{0, "pop_front", 0}, - &ContainerModeling::handlePopFront}, + {{"clear", 0}, &ContainerModeling::handleClear}, + {{"assign", 2}, &ContainerModeling::handleAssign}, + {{"push_back", 1}, &ContainerModeling::handlePushBack}, + {{"emplace_back", 1}, &ContainerModeling::handlePushBack}, + {{"pop_back", 0}, &ContainerModeling::handlePopBack}, + {{"push_front", 1}, &ContainerModeling::handlePushFront}, + {{"emplace_front", 1}, &ContainerModeling::handlePushFront}, + {{"pop_front", 0}, &ContainerModeling::handlePopFront}, }; - + CallDescriptionMap OneIterParamFunctions = { - {{0, "insert", 2}, - &ContainerModeling::handleInsert}, - {{0, "emplace", 2}, - &ContainerModeling::handleInsert}, - {{0, "erase", 1}, - &ContainerModeling::handleErase}, - {{0, "erase_after", 1}, - &ContainerModeling::handleEraseAfter}, + {{"insert", 2}, &ContainerModeling::handleInsert}, + {{"emplace", 2}, &ContainerModeling::handleInsert}, + {{"erase", 1}, &ContainerModeling::handleErase}, + {{"erase_after", 1}, &ContainerModeling::handleEraseAfter}, }; - + CallDescriptionMap TwoIterParamFunctions = { - {{0, "erase", 2}, - &ContainerModeling::handleErase}, - {{0, "erase_after", 2}, - &ContainerModeling::handleEraseAfter}, + {{"erase", 2}, &ContainerModeling::handleErase}, + {{"erase_after", 2}, &ContainerModeling::handleEraseAfter}, }; - }; bool isBeginCall(const FunctionDecl *Func); diff --git a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp index 4216a688311..8da482a2aec 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp @@ -49,7 +49,8 @@ private: bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const; - void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const; + void reportBug(ExplodedNode *N, const Expr *E, CheckerContext &C, + const char Msg[]) const; }; } @@ -108,20 +109,21 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast, if (!N) return; if (LossOfSign) - reportBug(N, C, "Loss of sign in implicit conversion"); + reportBug(N, Cast, C, "Loss of sign in implicit conversion"); if (LossOfPrecision) - reportBug(N, C, "Loss of precision in implicit conversion"); + reportBug(N, Cast, C, "Loss of precision in implicit conversion"); } } -void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C, - const char Msg[]) const { +void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E, + CheckerContext &C, const char Msg[]) const { if (!BT) BT.reset( new BuiltinBug(this, "Conversion", "Possible loss of sign/precision.")); // Generate a report for this bug. auto R = std::make_unique(*BT, Msg, N); + bugreporter::trackExpressionValue(N, E, *R); C.emitReport(std::move(R)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp index 6fed999ffc8..47fd57c7db9 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -40,10 +41,10 @@ class DebugContainerModeling CheckerContext &) const; CallDescriptionMap Callbacks = { - {{0, "clang_analyzer_container_begin", 1}, - &DebugContainerModeling::analyzerContainerBegin}, - {{0, "clang_analyzer_container_end", 1}, - &DebugContainerModeling::analyzerContainerEnd}, + {{"clang_analyzer_container_begin", 1}, + &DebugContainerModeling::analyzerContainerBegin}, + {{"clang_analyzer_container_end", 1}, + &DebugContainerModeling::analyzerContainerEnd}, }; public: diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp index 5833eea56da..6add9a007a8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp @@ -13,6 +13,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -41,12 +42,12 @@ class DebugIteratorModeling CheckerContext &) const; CallDescriptionMap Callbacks = { - {{0, "clang_analyzer_iterator_position", 1}, - &DebugIteratorModeling::analyzerIteratorPosition}, - {{0, "clang_analyzer_iterator_container", 1}, - &DebugIteratorModeling::analyzerIteratorContainer}, - {{0, "clang_analyzer_iterator_validity", 1}, - &DebugIteratorModeling::analyzerIteratorValidity}, + {{"clang_analyzer_iterator_position", 1}, + &DebugIteratorModeling::analyzerIteratorPosition}, + {{"clang_analyzer_iterator_container", 1}, + &DebugIteratorModeling::analyzerIteratorContainer}, + {{"clang_analyzer_iterator_validity", 1}, + &DebugIteratorModeling::analyzerIteratorValidity}, }; public: diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index df88b71ff06..49486ea796c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -44,8 +44,8 @@ static bool DefaultMethodFilter(const ObjCMethodDecl *M) { M->getMethodFamily() == OMF_dealloc || M->getMethodFamily() == OMF_copy || M->getMethodFamily() == OMF_mutableCopy || - M->getSelector().getNameForSlot(0).find("init") != StringRef::npos || - M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos; + M->getSelector().getNameForSlot(0).contains("init") || + M->getSelector().getNameForSlot(0).contains("Init"); } class DirectIvarAssignment : diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index 14ba5d76996..b07f59125a8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -384,7 +384,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, // FIXME: Instead of relying on the ParentMap, we should have the // trigger-statement (InitListExpr in this case) available in this // callback, ideally as part of CallEvent. - if (dyn_cast_or_null( + if (isa_and_nonnull( LCtx->getParentMap().getParent(Ctor->getOriginExpr()))) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp index 0e94b915a46..e5088fb266b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp @@ -94,10 +94,10 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE, // Only perform enum range check on casts where such checks are valid. For // all other cast kinds (where enum range checks are unnecessary or invalid), - // just return immediately. TODO: The set of casts whitelisted for enum - // range checking may be incomplete. Better to add a missing cast kind to - // enable a missing check than to generate false negatives and have to remove - // those later. + // just return immediately. TODO: The set of casts allowed for enum range + // checking may be incomplete. Better to add a missing cast kind to enable a + // missing check than to generate false negatives and have to remove those + // later. switch (CE->getCastKind()) { case CK_IntegralCast: break; diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index 42c777eb2c5..66ef781871e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -260,7 +260,7 @@ private: } bool isDestinationArgument(unsigned ArgNum) const { - return (llvm::find(DstArgs, ArgNum) != DstArgs.end()); + return llvm::is_contained(DstArgs, ArgNum); } static bool isTaintedOrPointsToTainted(const Expr *E, @@ -435,7 +435,6 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( .Case("getch", {{}, {ReturnValueIndex}}) .Case("getchar", {{}, {ReturnValueIndex}}) .Case("getchar_unlocked", {{}, {ReturnValueIndex}}) - .Case("getenv", {{}, {ReturnValueIndex}}) .Case("gets", {{}, {0, ReturnValueIndex}}) .Case("scanf", {{}, {}, VariadicType::Dst, 1}) .Case("socket", {{}, @@ -468,6 +467,16 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( if (!Rule.isNull()) return Rule; + + // `getenv` returns taint only in untrusted environments. + if (FData.FullName == "getenv") { + if (C.getAnalysisManager() + .getAnalyzerOptions() + .ShouldAssumeControlledEnvironment) + return {}; + return {{}, {ReturnValueIndex}}; + } + assert(FData.FDecl); // Check if it's one of the memory setting/copying functions. @@ -505,7 +514,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( if (OneOf("snprintf")) return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3}; if (OneOf("sprintf")) - return {{}, {0, ReturnValueIndex}, VariadicType::Src, 2}; + return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 2}; if (OneOf("strcpy", "stpcpy", "strcat")) return {{1}, {0, ReturnValueIndex}}; if (OneOf("bcopy")) @@ -780,7 +789,7 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) { // variable named stdin with the proper type. if (const auto *D = dyn_cast_or_null(DeclReg->getDecl())) { D = D->getCanonicalDecl(); - if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC()) { + if (D->getName().contains("stdin") && D->isExternC()) { const auto *PtrTy = dyn_cast(D->getType().getTypePtr()); if (PtrTy && PtrTy->getPointeeType().getCanonicalType() == C.getASTContext().getFILEType().getCanonicalType()) @@ -807,7 +816,7 @@ static bool getPrintfFormatArgumentNum(const CallEvent &Call, } // Or if a function is named setproctitle (this is a heuristic). - if (C.getCalleeName(FDecl).find("setproctitle") != StringRef::npos) { + if (C.getCalleeName(FDecl).contains("setproctitle")) { ArgNum = 0; return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp index bcae7337802..6f9867b9607 100644 --- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp @@ -13,11 +13,12 @@ //===----------------------------------------------------------------------===// #include "AllocationState.h" -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "InterCheckerAPI.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -125,19 +126,15 @@ bool InnerPointerChecker::isInvalidatingMemberFunction( return true; return false; } - return (isa(Call) || Call.isCalled(AppendFn) || - Call.isCalled(AssignFn) || Call.isCalled(ClearFn) || - Call.isCalled(EraseFn) || Call.isCalled(InsertFn) || - Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) || - Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) || - Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) || - Call.isCalled(SwapFn)); + return isa(Call) || + matchesAny(Call, AppendFn, AssignFn, ClearFn, EraseFn, InsertFn, + PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn, + ShrinkToFitFn, SwapFn); } bool InnerPointerChecker::isInnerPointerAccessFunction( const CallEvent &Call) const { - return (Call.isCalled(CStrFn) || Call.isCalled(DataFn) || - Call.isCalled(DataMemberFn)); + return matchesAny(Call, CStrFn, DataFn, DataMemberFn); } void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call, @@ -184,7 +181,7 @@ void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call, // std::addressof function accepts a non-const reference as an argument, // but doesn't modify it. - if (Call.isCalled(AddressofFn)) + if (AddressofFn.matches(Call)) continue; markPtrSymbolsReleased(Call, State, ArgRegion, C); diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index ab5e6a1c999..235c9010412 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -64,10 +64,11 @@ // making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as // a constraint which we later retrieve when doing an actual comparison. -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/DeclTemplate.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp index a4748449777..c682449921a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp @@ -14,10 +14,10 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" - #include "Iterator.h" using namespace clang; diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index 28d3e058fee..b57c5dc6de5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -949,7 +949,7 @@ void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call, const IdentifierInfo *Identifier = Call.getCalleeIdentifier(); SVal sv = Call.getReturnValue(); - if (isAnnotatedAsReturningLocalized(D) || LSF.count(Identifier) != 0) { + if (isAnnotatedAsReturningLocalized(D) || LSF.contains(Identifier)) { setLocalizedState(sv, C); } else if (isNSStringType(RT, C.getASTContext()) && !hasLocalizedState(sv, C)) { @@ -1339,7 +1339,10 @@ bool PluralMisuseChecker::MethodCrawler::EndVisitIfStmt(IfStmt *I) { } bool PluralMisuseChecker::MethodCrawler::VisitIfStmt(const IfStmt *I) { - const Expr *Condition = I->getCond()->IgnoreParenImpCasts(); + const Expr *Condition = I->getCond(); + if (!Condition) + return true; + Condition = Condition->IgnoreParenImpCasts(); if (isCheckingPlurality(Condition)) { MatchingStatements.push_back(I); InMatchingStatement = true; diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp index b72d72580c2..5bf96acc046 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp @@ -27,6 +27,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -180,7 +181,7 @@ static bool isInMIGCall(CheckerContext &C) { } void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { - if (Call.isCalled(OsRefRetain)) { + if (OsRefRetain.matches(Call)) { // If the code is doing reference counting over the parameter, // it opens up an opportunity for safely calling a destructor function. // TODO: We should still check for over-releases. @@ -198,7 +199,7 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { auto I = llvm::find_if(Deallocators, [&](const std::pair &Item) { - return Call.isCalled(Item.first); + return Item.first.matches(Call); }); if (I == Deallocators.end()) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index a157ee2da5d..635eb00e4ca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -160,7 +160,7 @@ static bool isEnclosingFunctionParam(const Expr *E) { E = E->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast(E)) { const ValueDecl *VD = DRE->getDecl(); - if (isa(VD) || isa(VD)) + if (isa(VD)) return true; } return false; @@ -199,8 +199,7 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, static bool isBadDeallocationArgument(const MemRegion *Arg) { if (!Arg) return false; - return isa(Arg) || isa(Arg) || - isa(Arg); + return isa(Arg); } /// Given the address expression, retrieve the value it's pointing to. Assume diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a6470da09c4..10ed6149528 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -48,9 +48,13 @@ #include "InterCheckerAPI.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ParentMap.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -60,20 +64,26 @@ #include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -298,6 +308,8 @@ public: /// which might free a pointer are annotated. DefaultBool ShouldIncludeOwnershipAnnotatedFunctions; + DefaultBool ShouldRegisterNoOwnershipChangeVisitor; + /// Many checkers are essentially built into this one, so enabling them will /// make MallocChecker perform additional modeling and reporting. enum CheckKind { @@ -722,11 +734,169 @@ private: bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, SVal ArgVal) const; }; +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Definition of NoOwnershipChangeVisitor. +//===----------------------------------------------------------------------===// + +namespace { +class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor { + SymbolRef Sym; + using OwnerSet = llvm::SmallPtrSet; + + // Collect which entities point to the allocated memory, and could be + // responsible for deallocating it. + class OwnershipBindingsHandler : public StoreManager::BindingsHandler { + SymbolRef Sym; + OwnerSet &Owners; + + public: + OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners) + : Sym(Sym), Owners(Owners) {} + + bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region, + SVal Val) override { + if (Val.getAsSymbol() == Sym) + Owners.insert(Region); + return true; + } + + LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); } + LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const { + out << "Owners: {\n"; + for (const MemRegion *Owner : Owners) { + out << " "; + Owner->dumpToStream(out); + out << ",\n"; + } + out << "}\n"; + } + }; + +protected: + OwnerSet getOwnersAtNode(const ExplodedNode *N) { + OwnerSet Ret; + + ProgramStateRef State = N->getState(); + OwnershipBindingsHandler Handler{Sym, Ret}; + State->getStateManager().getStoreManager().iterBindings(State->getStore(), + Handler); + return Ret; + } + + LLVM_DUMP_METHOD static std::string + getFunctionName(const ExplodedNode *CallEnterN) { + if (const CallExpr *CE = llvm::dyn_cast_or_null( + CallEnterN->getLocationAs()->getCallExpr())) + if (const FunctionDecl *FD = CE->getDirectCallee()) + return FD->getQualifiedNameAsString(); + return ""; + } + + bool doesFnIntendToHandleOwnership(const Decl *Callee, ASTContext &ACtx) { + using namespace clang::ast_matchers; + const FunctionDecl *FD = dyn_cast(Callee); + if (!FD) + return false; + // TODO: Operator delete is hardly the only deallocator -- Can we reuse + // isFreeingCall() or something thats already here? + auto Deallocations = match( + stmt(hasDescendant(cxxDeleteExpr().bind("delete")) + ), *FD->getBody(), ACtx); + // TODO: Ownership my change with an attempt to store the allocated memory. + return !Deallocations.empty(); + } + + virtual bool + wasModifiedInFunction(const ExplodedNode *CallEnterN, + const ExplodedNode *CallExitEndN) override { + if (!doesFnIntendToHandleOwnership( + CallExitEndN->getFirstPred()->getLocationContext()->getDecl(), + CallExitEndN->getState()->getAnalysisManager().getASTContext())) + return true; + + if (CallEnterN->getState()->get(Sym) != + CallExitEndN->getState()->get(Sym)) + return true; + + OwnerSet CurrOwners = getOwnersAtNode(CallEnterN); + OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN); + + // Owners in the current set may be purged from the analyzer later on. + // If a variable is dead (is not referenced directly or indirectly after + // some point), it will be removed from the Store before the end of its + // actual lifetime. + // This means that that if the ownership status didn't change, CurrOwners + // must be a superset of, but not necessarily equal to ExitOwners. + return !llvm::set_is_subset(ExitOwners, CurrOwners); + } + + static PathDiagnosticPieceRef emitNote(const ExplodedNode *N) { + PathDiagnosticLocation L = PathDiagnosticLocation::create( + N->getLocation(), + N->getState()->getStateManager().getContext().getSourceManager()); + return std::make_shared( + L, "Returning without deallocating memory or storing the pointer for " + "later deallocation"); + } + + virtual PathDiagnosticPieceRef + maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, + const ObjCMethodCall &Call, + const ExplodedNode *N) override { + // TODO: Implement. + return nullptr; + } + + virtual PathDiagnosticPieceRef + maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, + const CXXConstructorCall &Call, + const ExplodedNode *N) override { + // TODO: Implement. + return nullptr; + } + + virtual PathDiagnosticPieceRef + maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, + const ExplodedNode *N) override { + // TODO: Factor the logic of "what constitutes as an entity being passed + // into a function call" out by reusing the code in + // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating + // the printing technology in UninitializedObject's FieldChainInfo. + ArrayRef Parameters = Call.parameters(); + for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) { + SVal V = Call.getArgSVal(I); + if (V.getAsSymbol() == Sym) + return emitNote(N); + } + return nullptr; + } + +public: + NoOwnershipChangeVisitor(SymbolRef Sym) + : NoStateChangeFuncVisitor(bugreporter::TrackingKind::Thorough), + Sym(Sym) {} + + void Profile(llvm::FoldingSetNodeID &ID) const override { + static int Tag = 0; + ID.AddPointer(&Tag); + ID.AddPointer(Sym); + } + + void *getTag() const { + static int Tag = 0; + return static_cast(&Tag); + } +}; + +} // end anonymous namespace //===----------------------------------------------------------------------===// // Definition of MallocBugVisitor. //===----------------------------------------------------------------------===// +namespace { /// The bug visitor which allows us to print extra diagnostics along the /// BugReport path. For example, showing the allocation site of the leaked /// region. @@ -767,7 +937,7 @@ public: /// Did not track -> allocated. Other state (released) -> allocated. static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev, const Stmt *Stmt) { - return (Stmt && (isa(Stmt) || isa(Stmt)) && + return (isa_and_nonnull(Stmt) && (RSCurr && (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && (!RSPrev || @@ -780,8 +950,7 @@ public: const Stmt *Stmt) { bool IsReleased = (RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased()); - assert(!IsReleased || - (Stmt && (isa(Stmt) || isa(Stmt))) || + assert(!IsReleased || (isa_and_nonnull(Stmt)) || (!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer)); return IsReleased; } @@ -789,11 +958,10 @@ public: /// Did not track -> relinquished. Other state (allocated) -> relinquished. static inline bool isRelinquished(const RefState *RSCurr, const RefState *RSPrev, const Stmt *Stmt) { - return (Stmt && - (isa(Stmt) || isa(Stmt) || - isa(Stmt)) && - (RSCurr && RSCurr->isRelinquished()) && - (!RSPrev || !RSPrev->isRelinquished())); + return ( + isa_and_nonnull(Stmt) && + (RSCurr && RSCurr->isRelinquished()) && + (!RSPrev || !RSPrev->isRelinquished())); } /// If the expression is not a call, and the state change is @@ -803,7 +971,7 @@ public: static inline bool hasReallocFailed(const RefState *RSCurr, const RefState *RSPrev, const Stmt *Stmt) { - return ((!Stmt || !isa(Stmt)) && + return ((!isa_and_nonnull(Stmt)) && (RSCurr && (RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) && (RSPrev && @@ -851,7 +1019,6 @@ private: } }; }; - } // end anonymous namespace // A map from the freed symbol to the symbol representing the return value of @@ -1753,7 +1920,7 @@ ProgramStateRef MallocChecker::FreeMemAux( // Parameters, locals, statics, globals, and memory returned by // __builtin_alloca() shouldn't be freed. - if (!(isa(MS) || isa(MS))) { + if (!isa(MS)) { // FIXME: at the time this code was written, malloc() regions were // represented by conjured symbols, which are all in UnknownSpaceRegion. // This means that there isn't actually anything from HeapSpaceRegion @@ -2303,7 +2470,8 @@ void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range, categories::MemoryError)); auto R = std::make_unique( - *BT_UseZerroAllocated[*CheckKind], "Use of zero-allocated memory", N); + *BT_UseZerroAllocated[*CheckKind], + "Use of memory allocated with size zero", N); R->addRange(Range); if (Sym) { @@ -2579,6 +2747,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N, AllocNode->getLocationContext()->getDecl()); R->markInteresting(Sym); R->addVisitor(Sym, true); + if (ShouldRegisterNoOwnershipChangeVisitor) + R->addVisitor(Sym); C.emitReport(std::move(R)); } @@ -2733,7 +2903,7 @@ void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S, // the callee could still free the memory. // TODO: This logic should be a part of generic symbol escape callback. if (const MemRegion *MR = RetVal.getAsRegion()) - if (isa(MR) || isa(MR)) + if (isa(MR)) if (const SymbolicRegion *BMR = dyn_cast(MR->getBaseRegion())) Sym = BMR->getSymbol(); @@ -2916,7 +3086,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( // TODO: If we want to be more optimistic here, we'll need to make sure that // regions escape to C++ containers. They seem to do that even now, but for // mysterious reasons. - if (!(isa(Call) || isa(Call))) + if (!isa(Call)) return true; // Check Objective-C messages by selector name. @@ -3024,7 +3194,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts(); if (const DeclRefExpr *ArgDRE = dyn_cast(ArgE)) if (const VarDecl *D = dyn_cast(ArgDRE->getDecl())) - if (D->getCanonicalDecl()->getName().find("std") != StringRef::npos) + if (D->getCanonicalDecl()->getName().contains("std")) return true; } } @@ -3395,6 +3565,9 @@ void ento::registerDynamicMemoryModeling(CheckerManager &mgr) { auto *checker = mgr.registerChecker(); checker->ShouldIncludeOwnershipAnnotatedFunctions = mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic"); + checker->ShouldRegisterNoOwnershipChangeVisitor = + mgr.getAnalyzerOptions().getCheckerBooleanOption( + checker, "AddNoOwnershipChangeNotes"); } bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp index e31630f63b5..a6e8fcd425d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp @@ -32,12 +32,14 @@ using llvm::APSInt; namespace { struct MallocOverflowCheck { + const CallExpr *call; const BinaryOperator *mulop; const Expr *variable; APSInt maxVal; - MallocOverflowCheck(const BinaryOperator *m, const Expr *v, APSInt val) - : mulop(m), variable(v), maxVal(std::move(val)) {} + MallocOverflowCheck(const CallExpr *call, const BinaryOperator *m, + const Expr *v, APSInt val) + : call(call), mulop(m), variable(v), maxVal(std::move(val)) {} }; class MallocOverflowSecurityChecker : public Checker { @@ -46,8 +48,8 @@ public: BugReporter &BR) const; void CheckMallocArgument( - SmallVectorImpl &PossibleMallocOverflows, - const Expr *TheArgument, ASTContext &Context) const; + SmallVectorImpl &PossibleMallocOverflows, + const CallExpr *TheCall, ASTContext &Context) const; void OutputPossibleOverflows( SmallVectorImpl &PossibleMallocOverflows, @@ -62,16 +64,15 @@ static inline bool EvaluatesToZero(APSInt &Val, BinaryOperatorKind op) { } void MallocOverflowSecurityChecker::CheckMallocArgument( - SmallVectorImpl &PossibleMallocOverflows, - const Expr *TheArgument, - ASTContext &Context) const { + SmallVectorImpl &PossibleMallocOverflows, + const CallExpr *TheCall, ASTContext &Context) const { /* Look for a linear combination with a single variable, and at least one multiplication. Reject anything that applies to the variable: an explicit cast, conditional expression, an operation that could reduce the range of the result, or anything too complicated :-). */ - const Expr *e = TheArgument; + const Expr *e = TheCall->getArg(0); const BinaryOperator * mulop = nullptr; APSInt maxVal; @@ -101,8 +102,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument( e = rhs; } else return; - } - else if (isa(e) || isa(e)) + } else if (isa(e)) break; else return; @@ -115,9 +115,8 @@ void MallocOverflowSecurityChecker::CheckMallocArgument( // the data so when the body of the function is completely available // we can check for comparisons. - // TODO: Could push this into the innermost scope where 'e' is - // defined, rather than the whole function. - PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e, maxVal)); + PossibleMallocOverflows.push_back( + MallocOverflowCheck(TheCall, mulop, e, maxVal)); } namespace { @@ -153,17 +152,19 @@ private: return getDecl(CheckDR) == getDecl(DR) && Pred(Check); return false; }; - toScanFor.erase(std::remove_if(toScanFor.begin(), toScanFor.end(), P), - toScanFor.end()); + llvm::erase_if(toScanFor, P); } void CheckExpr(const Expr *E_p) { - auto PredTrue = [](const MallocOverflowCheck &) { return true; }; const Expr *E = E_p->IgnoreParenImpCasts(); + const auto PrecedesMalloc = [E, this](const MallocOverflowCheck &c) { + return Context.getSourceManager().isBeforeInTranslationUnit( + E->getExprLoc(), c.call->getExprLoc()); + }; if (const DeclRefExpr *DR = dyn_cast(E)) - Erase(DR, PredTrue); + Erase(DR, PrecedesMalloc); else if (const auto *ME = dyn_cast(E)) { - Erase(ME, PredTrue); + Erase(ME, PrecedesMalloc); } } @@ -322,7 +323,7 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D, if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) { if (TheCall->getNumArgs() == 1) - CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0), + CheckMallocArgument(PossibleMallocOverflows, TheCall, mgr.getASTContext()); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp index 5d63d6efd23..517a5d78271 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -46,7 +47,7 @@ int MmapWriteExecChecker::ProtRead = 0x01; void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - if (Call.isCalled(MmapFn) || Call.isCalled(MprotectFn)) { + if (matchesAny(Call, MmapFn, MprotectFn)) { SVal ProtVal = Call.getArgSVal(2); Optional ProtLoc = ProtVal.getAs(); int64_t Prot = ProtLoc->getValue().getSExtValue(); diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index cbe93898200..4a232c6f4b3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -553,8 +553,8 @@ MoveChecker::classifyObject(const MemRegion *MR, // For the purposes of this checker, we classify move-safe STL types // as not-"STL" types, because that's how the checker treats them. MR = unwrapRValueReferenceIndirection(MR); - bool IsLocal = - MR && isa(MR) && isa(MR->getMemorySpace()); + bool IsLocal = isa_and_nonnull(MR) && + isa(MR->getMemorySpace()); if (!RD || !RD->getDeclContext()->isStdNamespace()) return { IsLocal, SK_NonStd }; @@ -712,12 +712,9 @@ ProgramStateRef MoveChecker::checkRegionChanges( // directly, but not all of them end up being invalidated. // But when they do, they appear in the InvalidatedRegions array as well. for (const auto *Region : RequestedRegions) { - if (ThisRegion != Region) { - if (llvm::find(InvalidatedRegions, Region) != - std::end(InvalidatedRegions)) { - State = removeFromState(State, Region); - } - } + if (ThisRegion != Region && + llvm::is_contained(InvalidatedRegions, Region)) + State = removeFromState(State, Region); } } else { // For invalidations that aren't caused by calls, assume nothing. In diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index 90c5583d896..dcca8be55e3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file defines a CheckNSError, a flow-insenstive check +// This file defines a CheckNSError, a flow-insensitive check // that determines if an Objective-C class interface correctly returns // a non-void return type. // diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index ee71b55a39e..f4e9a67438e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -21,6 +21,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -681,9 +682,7 @@ ProgramStateRef PthreadLockChecker::checkRegionChanges( // We assume that system library function wouldn't touch the mutex unless // it takes the mutex explicitly as an argument. // FIXME: This is a bit quadratic. - if (IsLibraryFunction && - std::find(ExplicitRegions.begin(), ExplicitRegions.end(), R) == - ExplicitRegions.end()) + if (IsLibraryFunction && !llvm::is_contained(ExplicitRegions, R)) continue; State = State->remove(R); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 3f3267ff939..0bde088d0e8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -290,7 +290,7 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE, ProgramStateRef State = C.getState(); SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol(); - if (!Sym || !dyn_cast_or_null(Sym->getOriginRegion())) + if (!Sym || !isa_and_nonnull(Sym->getOriginRegion())) return; // Accessing an ivar directly is unusual. If we've done that, be more @@ -1188,14 +1188,14 @@ ProgramStateRef RetainCountChecker::checkRegionChanges( if (!invalidated) return state; - llvm::SmallPtrSet WhitelistedSymbols; + llvm::SmallPtrSet AllowedSymbols; for (const MemRegion *I : ExplicitRegions) if (const SymbolicRegion *SR = I->StripCasts()->getAs()) - WhitelistedSymbols.insert(SR->getSymbol()); + AllowedSymbols.insert(SR->getSymbol()); for (SymbolRef sym : *invalidated) { - if (WhitelistedSymbols.count(sym)) + if (AllowedSymbols.count(sym)) continue; // Remove any existing reference-count binding. state = removeRefBinding(state, sym); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp index 64ac6bc4c06..41ef45d317c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp @@ -73,11 +73,8 @@ RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT) static bool isNumericLiteralExpression(const Expr *E) { // FIXME: This set of cases was copied from SemaExprObjC. - return isa(E) || - isa(E) || - isa(E) || - isa(E) || - isa(E); + return isa(E); } /// If type represents a pointer to CXXRecordDecl, diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index 885750218b9..c4dc06d4a07 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -79,16 +80,44 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, "Returned pointer value points outside the original object " "(potential buffer overflow)")); - // FIXME: It would be nice to eventually make this diagnostic more clear, - // e.g., by referencing the original declaration or by saying *why* this - // reference is outside the range. - // Generate a report for this bug. - auto report = + auto Report = std::make_unique(*BT, BT->getDescription(), N); + Report->addRange(RetE->getSourceRange()); - report->addRange(RetE->getSourceRange()); - C.emitReport(std::move(report)); + const auto ConcreteElementCount = ElementCount.getAs(); + const auto ConcreteIdx = Idx.getAs(); + + const auto *DeclR = ER->getSuperRegion()->getAs(); + + if (DeclR) + Report->addNote("Original object declared here", + {DeclR->getDecl(), C.getSourceManager()}); + + if (ConcreteElementCount) { + SmallString<128> SBuf; + llvm::raw_svector_ostream OS(SBuf); + OS << "Original object "; + if (DeclR) { + OS << "'"; + DeclR->getDecl()->printName(OS); + OS << "' "; + } + OS << "is an array of " << ConcreteElementCount->getValue() << " '"; + ER->getValueType().print(OS, + PrintingPolicy(C.getASTContext().getLangOpts())); + OS << "' objects"; + if (ConcreteIdx) { + OS << ", returned pointer points at index " << ConcreteIdx->getValue(); + } + + Report->addNote(SBuf, + {RetE, C.getSourceManager(), C.getLocationContext()}); + } + + bugreporter::trackExpressionValue(N, RetE, *Report); + + C.emitReport(std::move(Report)); } } diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp index 14ecede1708..cd502241ef6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "llvm/ADT/Optional.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp index 933e0146ff5..ea72ebe3ed5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp @@ -12,6 +12,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp index 8d380ed1b93..1de5d7285f6 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include @@ -119,7 +120,7 @@ void SimpleStreamChecker::checkPostCall(const CallEvent &Call, if (!Call.isGlobalCFunction()) return; - if (!Call.isCalled(OpenFn)) + if (!OpenFn.matches(Call)) return; // Get the symbolic value corresponding to the file handle. @@ -138,7 +139,7 @@ void SimpleStreamChecker::checkPreCall(const CallEvent &Call, if (!Call.isGlobalCFunction()) return; - if (!Call.isCalled(CloseFn)) + if (!CloseFn.matches(Call)) return; // Get the symbolic value corresponding to the file handle. diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index 09e885e8133..c789a8dbcca 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -23,6 +23,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" @@ -102,12 +103,8 @@ static bool hasStdClassWithName(const CXXRecordDecl *RD, ArrayRef Names) { if (!RD || !RD->getDeclContext()->isStdNamespace()) return false; - if (RD->getDeclName().isIdentifier()) { - StringRef Name = RD->getName(); - return llvm::any_of(Names, [&Name](StringRef GivenName) -> bool { - return Name == GivenName; - }); - } + if (RD->getDeclName().isIdentifier()) + return llvm::is_contained(Names, RD->getName()); return false; } @@ -289,7 +286,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call)) return handleOstreamOperator(Call, C); - if (Call.isCalled(StdSwapCall)) { + if (StdSwapCall.matches(Call)) { // Check the first arg, if it is of std::unique_ptr type. assert(Call.getNumArgs() == 2 && "std::swap should have two arguments"); const Expr *FirstArg = Call.getArgExpr(0); @@ -298,8 +295,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call, return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C); } - if (Call.isCalled(StdMakeUniqueCall) || - Call.isCalled(StdMakeUniqueForOverwriteCall)) { + if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) { if (!ModelSmartPtrDereference) return false; diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index b5c9356322f..d5e86e86424 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" @@ -303,21 +303,53 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, class CallBack : public StoreManager::BindingsHandler { private: CheckerContext &Ctx; - const StackFrameContext *CurSFC; + const StackFrameContext *PoppedFrame; + + /// Look for stack variables referring to popped stack variables. + /// Returns true only if it found some dangling stack variables + /// referred by an other stack variable from different stack frame. + bool checkForDanglingStackVariable(const MemRegion *Referrer, + const MemRegion *Referred) { + const auto *ReferrerMemSpace = + Referrer->getMemorySpace()->getAs(); + const auto *ReferredMemSpace = + Referred->getMemorySpace()->getAs(); + + if (!ReferrerMemSpace || !ReferredMemSpace) + return false; + + const auto *ReferrerFrame = ReferrerMemSpace->getStackFrame(); + const auto *ReferredFrame = ReferredMemSpace->getStackFrame(); + + if (ReferrerMemSpace && ReferredMemSpace) { + if (ReferredFrame == PoppedFrame && + ReferrerFrame->isParentOf(PoppedFrame)) { + V.emplace_back(Referrer, Referred); + return true; + } + } + return false; + } public: SmallVector, 10> V; - CallBack(CheckerContext &CC) : Ctx(CC), CurSFC(CC.getStackFrame()) {} + CallBack(CheckerContext &CC) : Ctx(CC), PoppedFrame(CC.getStackFrame()) {} bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region, SVal Val) override { + const MemRegion *VR = Val.getAsRegion(); + if (!VR) + return true; + if (checkForDanglingStackVariable(Region, VR)) + return true; + + // Check the globals for the same. if (!isa(Region->getMemorySpace())) return true; - const MemRegion *VR = Val.getAsRegion(); - if (VR && isa(VR->getMemorySpace()) && - !isArcManagedBlock(VR, Ctx) && !isNotInCurrentFrame(VR, Ctx)) + if (VR && VR->hasStackStorage() && !isArcManagedBlock(VR, Ctx) && + !isNotInCurrentFrame(VR, Ctx)) V.emplace_back(Region, VR); return true; } @@ -344,19 +376,41 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS, "invalid after returning from the function"); for (const auto &P : Cb.V) { + const MemRegion *Referrer = P.first; + const MemRegion *Referred = P.second; + // Generate a report for this bug. + const StringRef CommonSuffix = + "upon returning to the caller. This will be a dangling reference"; SmallString<128> Buf; llvm::raw_svector_ostream Out(Buf); - SourceRange Range = genName(Out, P.second, Ctx.getASTContext()); - Out << " is still referred to by the "; - if (isa(P.first->getMemorySpace())) - Out << "static"; - else - Out << "global"; - Out << " variable '"; - const VarRegion *VR = cast(P.first->getBaseRegion()); - Out << *VR->getDecl() - << "' upon returning to the caller. This will be a dangling reference"; + const SourceRange Range = genName(Out, Referred, Ctx.getASTContext()); + + if (isa(Referrer)) { + Out << " is still referred to by a temporary object on the stack " + << CommonSuffix; + auto Report = + std::make_unique(*BT_stackleak, Out.str(), N); + Ctx.emitReport(std::move(Report)); + return; + } + + const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) { + if (isa(Space)) + return "static"; + if (isa(Space)) + return "global"; + assert(isa(Space)); + return "stack"; + }(Referrer->getMemorySpace()); + + // This cast supposed to succeed. + const VarRegion *ReferrerVar = cast(Referrer->getBaseRegion()); + const std::string ReferrerVarName = + ReferrerVar->getDecl()->getDeclName().getAsString(); + + Out << " is still referred to by the " << ReferrerMemorySpace + << " variable '" << ReferrerVarName << "' " << CommonSuffix; auto Report = std::make_unique(*BT_stackleak, Out.str(), N); if (Range.isValid()) diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp index e758b465af1..e8b963a535d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp @@ -568,6 +568,7 @@ public: bool DisplayLoadedSummaries = false; bool ModelPOSIX = false; + bool ShouldAssumeControlledEnvironment = false; private: Optional findFunctionSummary(const FunctionDecl *FD, @@ -1433,6 +1434,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( RetType{Ssize_tTy}), GetLineSummary); + { + Summary GetenvSummary = Summary(NoEvalCall) + .ArgConstraint(NotNull(ArgNo(0))) + .Case({NotNull(Ret)}); + // In untrusted environments the envvar might not exist. + if (!ShouldAssumeControlledEnvironment) + GetenvSummary.Case({NotNull(Ret)->negate()}); + + // char *getenv(const char *name); + addToFunctionSummaryMap( + "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}), + std::move(GetenvSummary)); + } + if (ModelPOSIX) { // long a64l(const char *str64); @@ -2645,11 +2660,12 @@ void StdLibraryFunctionsChecker::initFunctionSummaries( void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) { auto *Checker = mgr.registerChecker(); + const AnalyzerOptions &Opts = mgr.getAnalyzerOptions(); Checker->DisplayLoadedSummaries = - mgr.getAnalyzerOptions().getCheckerBooleanOption( - Checker, "DisplayLoadedSummaries"); - Checker->ModelPOSIX = - mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX"); + Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries"); + Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX"); + Checker->ShouldAssumeControlledEnvironment = + Opts.ShouldAssumeControlledEnvironment; } bool ento::shouldRegisterStdCLibraryFunctionsChecker( diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index dd65f8c035a..26218b8e045 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -1118,4 +1119,4 @@ void ento::registerStreamTesterChecker(CheckerManager &Mgr) { bool ento::shouldRegisterStreamTesterChecker(const CheckerManager &Mgr) { return true; -} \ No newline at end of file +} diff --git a/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp new file mode 100644 index 00000000000..0d745f5d8d6 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp @@ -0,0 +1,105 @@ +//=== StringChecker.cpp -------------------------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the modeling of the std::basic_string type. +// This involves checking preconditions of the operations and applying the +// effects of the operations, e.g. their post-conditions. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +using namespace clang; +using namespace ento; + +namespace { +class StringChecker : public Checker { + BugType BT_Null{this, "Dereference of null pointer", categories::LogicError}; + mutable const FunctionDecl *StringConstCharPtrCtor = nullptr; + mutable CanQualType SizeTypeTy; + const CallDescription TwoParamStdStringCtor = { + {"std", "basic_string", "basic_string"}, 2, 2}; + + bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const; + +public: + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; +}; + +bool StringChecker::isCharToStringCtor(const CallEvent &Call, + const ASTContext &ACtx) const { + if (!TwoParamStdStringCtor.matches(Call)) + return false; + const auto *FD = dyn_cast(Call.getDecl()); + assert(FD); + + // See if we already cached it. + if (StringConstCharPtrCtor && StringConstCharPtrCtor == FD) + return true; + + // Verify that the parameters have the expected types: + // - arg 1: `const CharT *` + // - arg 2: some allocator - which is definately not `size_t`. + const QualType Arg1Ty = Call.getArgExpr(0)->getType().getCanonicalType(); + const QualType Arg2Ty = Call.getArgExpr(1)->getType().getCanonicalType(); + + if (!Arg1Ty->isPointerType()) + return false; + + // It makes sure that we don't select the `string(const char* p, size_t len)` + // overload accidentally. + if (Arg2Ty.getCanonicalType() == ACtx.getSizeType()) + return false; + + StringConstCharPtrCtor = FD; // Cache the decl of the right overload. + return true; +} + +void StringChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + if (!isCharToStringCtor(Call, C.getASTContext())) + return; + const auto Param = Call.getArgSVal(0).getAs(); + if (!Param.hasValue()) + return; + + // We managed to constrain the parameter to non-null. + ProgramStateRef NotNull, Null; + std::tie(NotNull, Null) = C.getState()->assume(*Param); + + if (NotNull) { + const auto Callback = [Param](PathSensitiveBugReport &BR) -> std::string { + return BR.isInteresting(*Param) ? "Assuming the pointer is not null." + : ""; + }; + + // Emit note only if this operation constrained the pointer to be null. + C.addTransition(NotNull, Null ? C.getNoteTag(Callback) : nullptr); + return; + } + + // We found a path on which the parameter is NULL. + if (ExplodedNode *N = C.generateErrorNode(C.getState())) { + auto R = std::make_unique( + BT_Null, "The parameter must not be null", N); + bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R); + C.emitReport(std::move(R)); + } +} + +} // end anonymous namespace + +void ento::registerStringChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterStringChecker(const CheckerManager &) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index 381334de068..2244cdb96d4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -110,7 +110,7 @@ void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE, // Don't treat functions in namespaces with the same name a Unix function // as a call to the Unix function. const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); - if (NamespaceCtx && isa(NamespaceCtx)) + if (isa_and_nonnull(NamespaceCtx)) return; StringRef FName = C.getCalleeName(FD); @@ -466,7 +466,7 @@ void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE, // Don't treat functions in namespaces with the same name a Unix function // as a call to the Unix function. const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext(); - if (NamespaceCtx && isa(NamespaceCtx)) + if (isa_and_nonnull(NamespaceCtx)) return; StringRef FName = C.getCalleeName(FD); diff --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp index dde5912b6d6..60da4fca12e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -15,6 +15,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" @@ -126,15 +127,15 @@ void ValistChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction()) return; - if (Call.isCalled(VaStart)) + if (VaStart.matches(Call)) checkVAListStartCall(Call, C, false); - else if (Call.isCalled(VaCopy)) + else if (VaCopy.matches(Call)) checkVAListStartCall(Call, C, true); - else if (Call.isCalled(VaEnd)) + else if (VaEnd.matches(Call)) checkVAListEndCall(Call, C); else { for (auto FuncInfo : VAListAccepters) { - if (!Call.isCalled(FuncInfo.Func)) + if (!FuncInfo.Func.matches(Call)) continue; bool Symbolic; const MemRegion *VAList = diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp index 8f147026ae1..04e6603b4cb 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp @@ -9,7 +9,7 @@ // This file defines vfork checker which checks for dangerous uses of vfork. // Vforked process shares memory (including stack) with parent so it's // range of actions is significantly limited: can't write variables, -// can't call functions not in whitelist, etc. For more details, see +// can't call functions not in the allowed list, etc. For more details, see // http://man7.org/linux/man-pages/man2/vfork.2.html // // This checker checks for prohibited constructs in vforked process. @@ -44,13 +44,14 @@ namespace { class VforkChecker : public Checker> { mutable std::unique_ptr BT; - mutable llvm::SmallSet VforkWhitelist; + mutable llvm::SmallSet VforkAllowlist; mutable const IdentifierInfo *II_vfork; static bool isChildProcess(const ProgramStateRef State); bool isVforkCall(const Decl *D, CheckerContext &C) const; - bool isCallWhitelisted(const IdentifierInfo *II, CheckerContext &C) const; + bool isCallExplicitelyAllowed(const IdentifierInfo *II, + CheckerContext &C) const; void reportBug(const char *What, CheckerContext &C, const char *Details = nullptr) const; @@ -93,9 +94,9 @@ bool VforkChecker::isVforkCall(const Decl *D, CheckerContext &C) const { } // Returns true iff ok to call function after successful vfork. -bool VforkChecker::isCallWhitelisted(const IdentifierInfo *II, - CheckerContext &C) const { - if (VforkWhitelist.empty()) { +bool VforkChecker::isCallExplicitelyAllowed(const IdentifierInfo *II, + CheckerContext &C) const { + if (VforkAllowlist.empty()) { // According to manpage. const char *ids[] = { "_Exit", @@ -112,10 +113,10 @@ bool VforkChecker::isCallWhitelisted(const IdentifierInfo *II, ASTContext &AC = C.getASTContext(); for (const char **id = ids; *id; ++id) - VforkWhitelist.insert(&AC.Idents.get(*id)); + VforkAllowlist.insert(&AC.Idents.get(*id)); } - return VforkWhitelist.count(II); + return VforkAllowlist.count(II); } void VforkChecker::reportBug(const char *What, CheckerContext &C, @@ -179,12 +180,13 @@ void VforkChecker::checkPostCall(const CallEvent &Call, C.addTransition(ChildState); } -// Prohibit calls to non-whitelist functions in child process. +// Prohibit calls to functions in child process which are not explicitly +// allowed. void VforkChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); - if (isChildProcess(State) - && !isCallWhitelisted(Call.getCalleeIdentifier(), C)) + if (isChildProcess(State) && + !isCallExplicitelyAllowed(Call.getCalleeIdentifier(), C)) reportBug("This function call", C); } diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h index ed457775545..ec6a7144fa4 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -29,7 +29,7 @@ class Expr; /// values). /// /// For more context see Static Analyzer checkers documentation - specifically -/// webkit.UncountedCallArgsChecker checker. Whitelist of transformations: +/// webkit.UncountedCallArgsChecker checker. Allowed list of transformations: /// - constructors of ref-counted types (including factory methods) /// - getters of ref-counted types /// - member overloaded operators diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp index d70bd9489d2..e6d0948f71b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -68,8 +68,7 @@ public: if (auto *F = CE->getDirectCallee()) { // Skip the first argument for overloaded member operators (e. g. lambda // or std::function call operator). - unsigned ArgIdx = - isa(CE) && dyn_cast_or_null(F); + unsigned ArgIdx = isa(CE) && isa_and_nonnull(F); for (auto P = F->param_begin(); // FIXME: Also check variadic function parameters. diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp new file mode 100644 index 00000000000..d7d573cd2d3 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp @@ -0,0 +1,280 @@ +//== InvalidPtrChecker.cpp ------------------------------------- -*- C++ -*--=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines InvalidPtrChecker which finds usages of possibly +// invalidated pointer. +// CERT SEI Rules ENV31-C and ENV34-C +// For more information see: +// https://wiki.sei.cmu.edu/confluence/x/8tYxBQ +// https://wiki.sei.cmu.edu/confluence/x/5NUxBQ +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +using namespace clang; +using namespace ento; + +namespace { + +class InvalidPtrChecker + : public Checker { +private: + BugType BT{this, "Use of invalidated pointer", categories::MemoryError}; + + void EnvpInvalidatingCall(const CallEvent &Call, CheckerContext &C) const; + + using HandlerFn = void (InvalidPtrChecker::*)(const CallEvent &Call, + CheckerContext &C) const; + + // SEI CERT ENV31-C + const CallDescriptionMap EnvpInvalidatingFunctions = { + {{"setenv", 3}, &InvalidPtrChecker::EnvpInvalidatingCall}, + {{"unsetenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall}, + {{"putenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall}, + {{"_putenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall}, + {{"_wputenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall}, + }; + + void postPreviousReturnInvalidatingCall(const CallEvent &Call, + CheckerContext &C) const; + + // SEI CERT ENV34-C + const CallDescriptionMap PreviousCallInvalidatingFunctions = { + {{"getenv", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, + {{"setlocale", 2}, + &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, + {{"strerror", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, + {{"localeconv", 0}, + &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, + {{"asctime", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall}, + }; + +public: + // Obtain the environment pointer from 'main()' (if present). + void checkBeginFunction(CheckerContext &C) const; + + // Handle functions in EnvpInvalidatingFunctions, that invalidate environment + // pointer from 'main()' + // Handle functions in PreviousCallInvalidatingFunctions. + // Also, check if invalidated region is passed to a + // conservatively evaluated function call as an argument. + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + + // Check if invalidated region is being dereferenced. + void checkLocation(SVal l, bool isLoad, const Stmt *S, + CheckerContext &C) const; +}; + +} // namespace + +// Set of memory regions that were invalidated +REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *) + +// Stores the region of the environment pointer of 'main' (if present). +// Note: This pointer has type 'const MemRegion *', however the trait is only +// specialized to 'const void*' and 'void*' +REGISTER_TRAIT_WITH_PROGRAMSTATE(EnvPtrRegion, const void *) + +// Stores key-value pairs, where key is function declaration and value is +// pointer to memory region returned by previous call of this function +REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *, + const MemRegion *) + +void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call, + CheckerContext &C) const { + StringRef FunctionName = Call.getCalleeIdentifier()->getName(); + ProgramStateRef State = C.getState(); + const auto *Reg = State->get(); + if (!Reg) + return; + const auto *SymbolicEnvPtrRegion = + reinterpret_cast(const_cast(Reg)); + + State = State->add(SymbolicEnvPtrRegion); + + const NoteTag *Note = + C.getNoteTag([SymbolicEnvPtrRegion, FunctionName]( + PathSensitiveBugReport &BR, llvm::raw_ostream &Out) { + if (!BR.isInteresting(SymbolicEnvPtrRegion)) + return; + Out << '\'' << FunctionName + << "' call may invalidate the environment parameter of 'main'"; + }); + + C.addTransition(State, Note); +} + +void InvalidPtrChecker::postPreviousReturnInvalidatingCall( + const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + const NoteTag *Note = nullptr; + const FunctionDecl *FD = dyn_cast_or_null(Call.getDecl()); + // Invalidate the region of the previously returned pointer - if there was + // one. + if (const MemRegion *const *Reg = State->get(FD)) { + const MemRegion *PrevReg = *Reg; + State = State->add(PrevReg); + Note = C.getNoteTag([PrevReg, FD](PathSensitiveBugReport &BR, + llvm::raw_ostream &Out) { + if (!BR.isInteresting(PrevReg)) + return; + Out << '\''; + FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true); + Out << "' call may invalidate the the result of the previous " << '\''; + FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true); + Out << '\''; + }); + } + + const LocationContext *LCtx = C.getLocationContext(); + const auto *CE = cast(Call.getOriginExpr()); + + // Function call will return a pointer to the new symbolic region. + DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal( + CE, LCtx, CE->getType(), C.blockCount()); + State = State->BindExpr(CE, LCtx, RetVal); + + // Remember to this region. + const auto *SymRegOfRetVal = cast(RetVal.getAsRegion()); + const MemRegion *MR = + const_cast(SymRegOfRetVal->getBaseRegion()); + State = State->set(FD, MR); + + ExplodedNode *Node = C.addTransition(State, Note); + const NoteTag *PreviousCallNote = + C.getNoteTag([MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) { + if (!BR.isInteresting(MR)) + return; + Out << '\'' << "'previous function call was here" << '\''; + }); + + C.addTransition(State, Node, PreviousCallNote); +} + +// TODO: This seems really ugly. Simplify this. +static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State, + const MemRegion *Reg) { + while (Reg) { + if (State->contains(Reg)) + return Reg; + const auto *SymBase = Reg->getSymbolicBase(); + if (!SymBase) + break; + const auto *SRV = dyn_cast(SymBase->getSymbol()); + if (!SRV) + break; + Reg = SRV->getRegion(); + if (const auto *VarReg = dyn_cast(SRV->getRegion())) + Reg = VarReg; + } + return nullptr; +} + +// Handle functions in EnvpInvalidatingFunctions, that invalidate environment +// pointer from 'main()' Also, check if invalidated region is passed to a +// function call as an argument. +void InvalidPtrChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + // Check if function invalidates 'envp' argument of 'main' + if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call)) + (this->**Handler)(Call, C); + + // Check if function invalidates the result of previous call + if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call)) + (this->**Handler)(Call, C); + + // Check if one of the arguments of the function call is invalidated + + // If call was inlined, don't report invalidated argument + if (C.wasInlined) + return; + + ProgramStateRef State = C.getState(); + + for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) { + + if (const auto *SR = dyn_cast_or_null( + Call.getArgSVal(I).getAsRegion())) { + if (const MemRegion *InvalidatedSymbolicBase = + findInvalidatedSymbolicBase(State, SR)) { + ExplodedNode *ErrorNode = C.generateNonFatalErrorNode(); + if (!ErrorNode) + return; + + SmallString<256> Msg; + llvm::raw_svector_ostream Out(Msg); + Out << "use of invalidated pointer '"; + Call.getArgExpr(I)->printPretty(Out, /*Helper=*/nullptr, + C.getASTContext().getPrintingPolicy()); + Out << "' in a function call"; + + auto Report = + std::make_unique(BT, Out.str(), ErrorNode); + Report->markInteresting(InvalidatedSymbolicBase); + Report->addRange(Call.getArgSourceRange(I)); + C.emitReport(std::move(Report)); + } + } + } +} + +// Obtain the environment pointer from 'main()', if present. +void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const { + if (!C.inTopFrame()) + return; + + const auto *FD = dyn_cast(C.getLocationContext()->getDecl()); + if (!FD || FD->param_size() != 3 || !FD->isMain()) + return; + + ProgramStateRef State = C.getState(); + const MemRegion *EnvpReg = + State->getRegion(FD->parameters()[2], C.getLocationContext()); + + // Save the memory region pointed by the environment pointer parameter of + // 'main'. + State = State->set( + reinterpret_cast(const_cast(EnvpReg))); + C.addTransition(State); +} + +// Check if invalidated region is being dereferenced. +void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + + // Ignore memory operations involving 'non-invalidated' locations. + const MemRegion *InvalidatedSymbolicBase = + findInvalidatedSymbolicBase(State, Loc.getAsRegion()); + if (!InvalidatedSymbolicBase) + return; + + ExplodedNode *ErrorNode = C.generateNonFatalErrorNode(); + if (!ErrorNode) + return; + + auto Report = std::make_unique( + BT, "dereferencing an invalid pointer", ErrorNode); + Report->markInteresting(InvalidatedSymbolicBase); + C.emitReport(std::move(Report)); +} + +void ento::registerInvalidPtrChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp index 1c67bbd77ec..ed3bdafad08 100644 --- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" @@ -38,7 +39,7 @@ public: void PutenvWithAutoChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { - if (!Call.isCalled(Putenv)) + if (!Putenv.matches(Call)) return; SVal ArgV = Call.getArgSVal(0); diff --git a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp index d6f69ae03af..771ed2578f6 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -188,6 +188,9 @@ public: PathPieces &getMutablePieces() { return PD->getMutablePieces(); } bool shouldAddPathEdges() const { return Consumer->shouldAddPathEdges(); } + bool shouldAddControlNotes() const { + return Consumer->shouldAddControlNotes(); + } bool shouldGenerateDiagnostics() const { return Consumer->shouldGenerateDiagnostics(); } @@ -534,10 +537,10 @@ static void removeEdgesToDefaultInitializers(PathPieces &Pieces) { if (auto *CF = dyn_cast(I->get())) { const Stmt *Start = CF->getStartLocation().asStmt(); const Stmt *End = CF->getEndLocation().asStmt(); - if (Start && isa(Start)) { + if (isa_and_nonnull(Start)) { I = Pieces.erase(I); continue; - } else if (End && isa(End)) { + } else if (isa_and_nonnull(End)) { PathPieces::iterator Next = std::next(I); if (Next != E) { if (auto *NextCF = @@ -1232,8 +1235,11 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode( } else if (auto BE = P.getAs()) { - if (!C.shouldAddPathEdges()) { + if (C.shouldAddControlNotes()) { generateMinimalDiagForBlockEdge(C, *BE); + } + + if (!C.shouldAddPathEdges()) { return; } @@ -1254,12 +1260,14 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode( // do-while statements are explicitly excluded here auto p = std::make_shared( - L, "Looping back to the head " - "of the loop"); + L, "Looping back to the head of the loop"); p->setPrunable(true); addEdgeToPath(C.getActivePath(), PrevLoc, p->getLocation()); - C.getActivePath().push_front(std::move(p)); + // We might've added a very similar control node already + if (!C.shouldAddControlNotes()) { + C.getActivePath().push_front(std::move(p)); + } if (const auto *CS = dyn_cast_or_null(Body)) { addEdgeToPath(C.getActivePath(), PrevLoc, @@ -1300,10 +1308,13 @@ void PathDiagnosticBuilder::generatePathDiagnosticsForNode( auto PE = std::make_shared(L, str); PE->setPrunable(true); addEdgeToPath(C.getActivePath(), PrevLoc, PE->getLocation()); - C.getActivePath().push_front(std::move(PE)); + + // We might've added a very similar control node already + if (!C.shouldAddControlNotes()) { + C.getActivePath().push_front(std::move(PE)); + } } - } else if (isa(Term) || isa(Term) || - isa(Term)) { + } else if (isa(Term)) { PathDiagnosticLocation L(Term, SM, C.getCurrLocationContext()); addEdgeToPath(C.getActivePath(), PrevLoc, L); } @@ -1342,9 +1353,7 @@ static const Stmt *getStmtParent(const Stmt *S, const ParentMap &PM) { if (!S) break; - if (isa(S) || - isa(S) || - isa(S)) + if (isa(S)) continue; break; @@ -1446,7 +1455,7 @@ static void addContextEdges(PathPieces &pieces, const LocationContext *LC) { break; // If the source is in the same context, we're already good. - if (llvm::find(SrcContexts, DstContext) != SrcContexts.end()) + if (llvm::is_contained(SrcContexts, DstContext)) break; // Update the subexpression node to point to the context edge. @@ -1540,9 +1549,8 @@ static void simplifySimpleBranches(PathPieces &pieces) { // We only perform this transformation for specific branch kinds. // We don't want to do this for do..while, for example. - if (!(isa(s1Start) || isa(s1Start) || - isa(s1Start) || isa(s1Start) || - isa(s1Start))) + if (!isa(s1Start)) continue; // Is s1End the branch condition? @@ -3181,7 +3189,7 @@ findExecutedLines(const SourceManager &SM, const ExplodedNode *N) { P = N->getParentMap().getParent(RS); } - if (P && (isa(P) || isa(P))) + if (isa_and_nonnull(P)) populateExecutedLinesWithStmt(P, SM, *ExecutedLines); } diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index d06a2d49330..8774dc3323a 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -343,46 +343,179 @@ BugReporterVisitor::getDefaultEndPath(const BugReporterContext &BRC, return P; } +//===----------------------------------------------------------------------===// +// Implementation of NoStateChangeFuncVisitor. +//===----------------------------------------------------------------------===// + +bool NoStateChangeFuncVisitor::isModifiedInFrame(const ExplodedNode *N) { + const LocationContext *Ctx = N->getLocationContext(); + const StackFrameContext *SCtx = Ctx->getStackFrame(); + if (!FramesModifyingCalculated.count(SCtx)) + findModifyingFrames(N); + return FramesModifying.count(SCtx); +} + +void NoStateChangeFuncVisitor::markFrameAsModifying( + const StackFrameContext *SCtx) { + while (!SCtx->inTopFrame()) { + auto p = FramesModifying.insert(SCtx); + if (!p.second) + break; // Frame and all its parents already inserted. + + SCtx = SCtx->getParent()->getStackFrame(); + } +} + +static const ExplodedNode *getMatchingCallExitEnd(const ExplodedNode *N) { + assert(N->getLocationAs()); + // The stackframe of the callee is only found in the nodes succeeding + // the CallEnter node. CallEnter's stack frame refers to the caller. + const StackFrameContext *OrigSCtx = N->getFirstSucc()->getStackFrame(); + + // Similarly, the nodes preceding CallExitEnd refer to the callee's stack + // frame. + auto IsMatchingCallExitEnd = [OrigSCtx](const ExplodedNode *N) { + return N->getLocationAs() && + OrigSCtx == N->getFirstPred()->getStackFrame(); + }; + while (N && !IsMatchingCallExitEnd(N)) { + assert(N->succ_size() <= 1 && + "This function is to be used on the trimmed ExplodedGraph!"); + N = N->getFirstSucc(); + } + return N; +} + +void NoStateChangeFuncVisitor::findModifyingFrames( + const ExplodedNode *const CallExitBeginN) { + + assert(CallExitBeginN->getLocationAs()); + + const StackFrameContext *const OriginalSCtx = + CallExitBeginN->getLocationContext()->getStackFrame(); + + const ExplodedNode *CurrCallExitBeginN = CallExitBeginN; + const StackFrameContext *CurrentSCtx = OriginalSCtx; + + for (const ExplodedNode *CurrN = CallExitBeginN; CurrN; + CurrN = CurrN->getFirstPred()) { + // Found a new inlined call. + if (CurrN->getLocationAs()) { + CurrCallExitBeginN = CurrN; + CurrentSCtx = CurrN->getStackFrame(); + FramesModifyingCalculated.insert(CurrentSCtx); + // We won't see a change in between two identical exploded nodes: skip. + continue; + } + + if (auto CE = CurrN->getLocationAs()) { + if (const ExplodedNode *CallExitEndN = getMatchingCallExitEnd(CurrN)) + if (wasModifiedInFunction(CurrN, CallExitEndN)) + markFrameAsModifying(CurrentSCtx); + + // We exited this inlined call, lets actualize the stack frame. + CurrentSCtx = CurrN->getStackFrame(); + + // Stop calculating at the current function, but always regard it as + // modifying, so we can avoid notes like this: + // void f(Foo &F) { + // F.field = 0; // note: 0 assigned to 'F.field' + // // note: returning without writing to 'F.field' + // } + if (CE->getCalleeContext() == OriginalSCtx) { + markFrameAsModifying(CurrentSCtx); + break; + } + } + + if (wasModifiedBeforeCallExit(CurrN, CurrCallExitBeginN)) + markFrameAsModifying(CurrentSCtx); + } +} + +PathDiagnosticPieceRef NoStateChangeFuncVisitor::VisitNode( + const ExplodedNode *N, BugReporterContext &BR, PathSensitiveBugReport &R) { + + const LocationContext *Ctx = N->getLocationContext(); + const StackFrameContext *SCtx = Ctx->getStackFrame(); + ProgramStateRef State = N->getState(); + auto CallExitLoc = N->getLocationAs(); + + // No diagnostic if region was modified inside the frame. + if (!CallExitLoc || isModifiedInFrame(N)) + return nullptr; + + CallEventRef<> Call = + BR.getStateManager().getCallEventManager().getCaller(SCtx, State); + + // Optimistically suppress uninitialized value bugs that result + // from system headers having a chance to initialize the value + // but failing to do so. It's too unlikely a system header's fault. + // It's much more likely a situation in which the function has a failure + // mode that the user decided not to check. If we want to hunt such + // omitted checks, we should provide an explicit function-specific note + // describing the precondition under which the function isn't supposed to + // initialize its out-parameter, and additionally check that such + // precondition can actually be fulfilled on the current path. + if (Call->isInSystemHeader()) { + // We make an exception for system header functions that have no branches. + // Such functions unconditionally fail to initialize the variable. + // If they call other functions that have more paths within them, + // this suppression would still apply when we visit these inner functions. + // One common example of a standard function that doesn't ever initialize + // its out parameter is operator placement new; it's up to the follow-up + // constructor (if any) to initialize the memory. + if (!N->getStackFrame()->getCFG()->isLinear()) { + static int i = 0; + R.markInvalid(&i, nullptr); + } + return nullptr; + } + + if (const auto *MC = dyn_cast(Call)) { + // If we failed to construct a piece for self, we still want to check + // whether the entity of interest is in a parameter. + if (PathDiagnosticPieceRef Piece = maybeEmitNoteForObjCSelf(R, *MC, N)) + return Piece; + } + + if (const auto *CCall = dyn_cast(Call)) { + // Do not generate diagnostics for not modified parameters in + // constructors. + return maybeEmitNoteForCXXThis(R, *CCall, N); + } + + return maybeEmitNoteForParameters(R, *Call, N); +} + //===----------------------------------------------------------------------===// // Implementation of NoStoreFuncVisitor. //===----------------------------------------------------------------------===// namespace { - /// Put a diagnostic on return statement of all inlined functions /// for which the region of interest \p RegionOfInterest was passed into, /// but not written inside, and it has caused an undefined read or a null /// pointer dereference outside. -class NoStoreFuncVisitor final : public BugReporterVisitor { +class NoStoreFuncVisitor final : public NoStateChangeFuncVisitor { const SubRegion *RegionOfInterest; MemRegionManager &MmrMgr; const SourceManager &SM; const PrintingPolicy &PP; - bugreporter::TrackingKind TKind; /// Recursion limit for dereferencing fields when looking for the /// region of interest. /// The limit of two indicates that we will dereference fields only once. static const unsigned DEREFERENCE_LIMIT = 2; - /// Frames writing into \c RegionOfInterest. - /// This visitor generates a note only if a function does not write into - /// a region of interest. This information is not immediately available - /// by looking at the node associated with the exit from the function - /// (usually the return statement). To avoid recomputing the same information - /// many times (going up the path for each node and checking whether the - /// region was written into) we instead lazily compute the - /// stack frames along the path which write into the region of interest. - llvm::SmallPtrSet FramesModifyingRegion; - llvm::SmallPtrSet FramesModifyingCalculated; - using RegionVector = SmallVector; public: NoStoreFuncVisitor(const SubRegion *R, bugreporter::TrackingKind TKind) - : RegionOfInterest(R), MmrMgr(R->getMemRegionManager()), + : NoStateChangeFuncVisitor(TKind), RegionOfInterest(R), + MmrMgr(R->getMemRegionManager()), SM(MmrMgr.getContext().getSourceManager()), - PP(MmrMgr.getContext().getPrintingPolicy()), TKind(TKind) {} + PP(MmrMgr.getContext().getPrintingPolicy()) {} void Profile(llvm::FoldingSetNodeID &ID) const override { static int Tag = 0; @@ -395,11 +528,13 @@ public: return static_cast(&Tag); } - PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, - BugReporterContext &BR, - PathSensitiveBugReport &R) override; - private: + /// \return Whether \c RegionOfInterest was modified at \p CurrN compared to + /// the value it holds in \p CallExitBeginN. + virtual bool + wasModifiedBeforeCallExit(const ExplodedNode *CurrN, + const ExplodedNode *CallExitBeginN) override; + /// Attempts to find the region of interest in a given record decl, /// by either following the base classes or fields. /// Dereferences fields up to a given recursion limit. @@ -411,20 +546,21 @@ private: const MemRegion *R, const RegionVector &Vec = {}, int depth = 0); - /// Check and lazily calculate whether the region of interest is - /// modified in the stack frame to which \p N belongs. - /// The calculation is cached in FramesModifyingRegion. - bool isRegionOfInterestModifiedInFrame(const ExplodedNode *N) { - const LocationContext *Ctx = N->getLocationContext(); - const StackFrameContext *SCtx = Ctx->getStackFrame(); - if (!FramesModifyingCalculated.count(SCtx)) - findModifyingFrames(N); - return FramesModifyingRegion.count(SCtx); - } + // Region of interest corresponds to an IVar, exiting a method + // which could have written into that IVar, but did not. + virtual PathDiagnosticPieceRef + maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, + const ObjCMethodCall &Call, + const ExplodedNode *N) override final; - /// Write to \c FramesModifyingRegion all stack frames along - /// the path in the current stack frame which modify \c RegionOfInterest. - void findModifyingFrames(const ExplodedNode *N); + virtual PathDiagnosticPieceRef + maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, + const CXXConstructorCall &Call, + const ExplodedNode *N) override final; + + virtual PathDiagnosticPieceRef + maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call, + const ExplodedNode *N) override final; /// Consume the information on the no-store stack frame in order to /// either emit a note or suppress the report enirely. @@ -436,22 +572,18 @@ private: const MemRegion *MatchedRegion, StringRef FirstElement, bool FirstIsReferenceType, unsigned IndirectionLevel); - /// Pretty-print region \p MatchedRegion to \p os. - /// \return Whether printing succeeded. - bool prettyPrintRegionName(StringRef FirstElement, bool FirstIsReferenceType, + bool prettyPrintRegionName(const RegionVector &FieldChain, const MemRegion *MatchedRegion, - const RegionVector &FieldChain, - int IndirectionLevel, + StringRef FirstElement, bool FirstIsReferenceType, + unsigned IndirectionLevel, llvm::raw_svector_ostream &os); - /// Print first item in the chain, return new separator. - static StringRef prettyPrintFirstElement(StringRef FirstElement, - bool MoreItemsExpected, - int IndirectionLevel, - llvm::raw_svector_ostream &os); + StringRef prettyPrintFirstElement(StringRef FirstElement, + bool MoreItemsExpected, + int IndirectionLevel, + llvm::raw_svector_ostream &os); }; - -} // end of anonymous namespace +} // namespace /// \return Whether the method declaration \p Parent /// syntactically has a binary operation writing into the ivar \p Ivar. @@ -486,25 +618,6 @@ static bool potentiallyWritesIntoIvar(const Decl *Parent, return false; } -/// Get parameters associated with runtime definition in order -/// to get the correct parameter name. -static ArrayRef getCallParameters(CallEventRef<> Call) { - // Use runtime definition, if available. - RuntimeDefinition RD = Call->getRuntimeDefinition(); - if (const auto *FD = dyn_cast_or_null(RD.getDecl())) - return FD->parameters(); - if (const auto *MD = dyn_cast_or_null(RD.getDecl())) - return MD->parameters(); - - return Call->parameters(); -} - -/// \return whether \p Ty points to a const type, or is a const reference. -static bool isPointerToConst(QualType Ty) { - return !Ty->getPointeeType().isNull() && - Ty->getPointeeType().getCanonicalType().isConstQualified(); -} - /// Attempts to find the region of interest in a given CXX decl, /// by either following the base classes or fields. /// Dereferences fields up to a given recursion limit. @@ -564,68 +677,66 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord( } PathDiagnosticPieceRef -NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BR, - PathSensitiveBugReport &R) { - - const LocationContext *Ctx = N->getLocationContext(); - const StackFrameContext *SCtx = Ctx->getStackFrame(); - ProgramStateRef State = N->getState(); - auto CallExitLoc = N->getLocationAs(); - - // No diagnostic if region was modified inside the frame. - if (!CallExitLoc || isRegionOfInterestModifiedInFrame(N)) - return nullptr; - - CallEventRef<> Call = - BR.getStateManager().getCallEventManager().getCaller(SCtx, State); - - // Region of interest corresponds to an IVar, exiting a method - // which could have written into that IVar, but did not. - if (const auto *MC = dyn_cast(Call)) { - if (const auto *IvarR = dyn_cast(RegionOfInterest)) { - const MemRegion *SelfRegion = MC->getReceiverSVal().getAsRegion(); - if (RegionOfInterest->isSubRegionOf(SelfRegion) && - potentiallyWritesIntoIvar(Call->getRuntimeDefinition().getDecl(), - IvarR->getDecl())) - return maybeEmitNote(R, *Call, N, {}, SelfRegion, "self", - /*FirstIsReferenceType=*/false, 1); - } - } - - if (const auto *CCall = dyn_cast(Call)) { - const MemRegion *ThisR = CCall->getCXXThisVal().getAsRegion(); - if (RegionOfInterest->isSubRegionOf(ThisR) && - !CCall->getDecl()->isImplicit()) - return maybeEmitNote(R, *Call, N, {}, ThisR, "this", +NoStoreFuncVisitor::maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R, + const ObjCMethodCall &Call, + const ExplodedNode *N) { + if (const auto *IvarR = dyn_cast(RegionOfInterest)) { + const MemRegion *SelfRegion = Call.getReceiverSVal().getAsRegion(); + if (RegionOfInterest->isSubRegionOf(SelfRegion) && + potentiallyWritesIntoIvar(Call.getRuntimeDefinition().getDecl(), + IvarR->getDecl())) + return maybeEmitNote(R, Call, N, {}, SelfRegion, "self", /*FirstIsReferenceType=*/false, 1); - - // Do not generate diagnostics for not modified parameters in - // constructors. - return nullptr; } + return nullptr; +} - ArrayRef parameters = getCallParameters(Call); - for (unsigned I = 0; I < Call->getNumArgs() && I < parameters.size(); ++I) { - const ParmVarDecl *PVD = parameters[I]; - SVal V = Call->getArgSVal(I); +PathDiagnosticPieceRef +NoStoreFuncVisitor::maybeEmitNoteForCXXThis(PathSensitiveBugReport &R, + const CXXConstructorCall &Call, + const ExplodedNode *N) { + const MemRegion *ThisR = Call.getCXXThisVal().getAsRegion(); + if (RegionOfInterest->isSubRegionOf(ThisR) && !Call.getDecl()->isImplicit()) + return maybeEmitNote(R, Call, N, {}, ThisR, "this", + /*FirstIsReferenceType=*/false, 1); + + // Do not generate diagnostics for not modified parameters in + // constructors. + return nullptr; +} + +/// \return whether \p Ty points to a const type, or is a const reference. +static bool isPointerToConst(QualType Ty) { + return !Ty->getPointeeType().isNull() && + Ty->getPointeeType().getCanonicalType().isConstQualified(); +} + +PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNoteForParameters( + PathSensitiveBugReport &R, const CallEvent &Call, const ExplodedNode *N) { + ArrayRef Parameters = Call.parameters(); + for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) { + const ParmVarDecl *PVD = Parameters[I]; + SVal V = Call.getArgSVal(I); bool ParamIsReferenceType = PVD->getType()->isReferenceType(); std::string ParamName = PVD->getNameAsString(); - int IndirectionLevel = 1; + unsigned IndirectionLevel = 1; QualType T = PVD->getType(); while (const MemRegion *MR = V.getAsRegion()) { if (RegionOfInterest->isSubRegionOf(MR) && !isPointerToConst(T)) - return maybeEmitNote(R, *Call, N, {}, MR, ParamName, + return maybeEmitNote(R, Call, N, {}, MR, ParamName, ParamIsReferenceType, IndirectionLevel); QualType PT = T->getPointeeType(); if (PT.isNull() || PT->isVoidType()) break; + ProgramStateRef State = N->getState(); + if (const RecordDecl *RD = PT->getAsRecordDecl()) if (Optional P = findRegionOfInterestInRecord(RD, State, MR)) - return maybeEmitNote(R, *Call, N, *P, RegionOfInterest, ParamName, + return maybeEmitNote(R, Call, N, *P, RegionOfInterest, ParamName, ParamIsReferenceType, IndirectionLevel); V = State->getSVal(MR, PT); @@ -637,40 +748,11 @@ NoStoreFuncVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BR, return nullptr; } -void NoStoreFuncVisitor::findModifyingFrames(const ExplodedNode *N) { - assert(N->getLocationAs()); - ProgramStateRef LastReturnState = N->getState(); - SVal ValueAtReturn = LastReturnState->getSVal(RegionOfInterest); - const LocationContext *Ctx = N->getLocationContext(); - const StackFrameContext *OriginalSCtx = Ctx->getStackFrame(); - - do { - ProgramStateRef State = N->getState(); - auto CallExitLoc = N->getLocationAs(); - if (CallExitLoc) { - LastReturnState = State; - ValueAtReturn = LastReturnState->getSVal(RegionOfInterest); - } - - FramesModifyingCalculated.insert(N->getLocationContext()->getStackFrame()); - - if (wasRegionOfInterestModifiedAt(RegionOfInterest, N, ValueAtReturn)) { - const StackFrameContext *SCtx = N->getStackFrame(); - while (!SCtx->inTopFrame()) { - auto p = FramesModifyingRegion.insert(SCtx); - if (!p.second) - break; // Frame and all its parents already inserted. - SCtx = SCtx->getParent()->getStackFrame(); - } - } - - // Stop calculation at the call to the current function. - if (auto CE = N->getLocationAs()) - if (CE->getCalleeContext() == OriginalSCtx) - break; - - N = N->getFirstPred(); - } while (N); +bool NoStoreFuncVisitor::wasModifiedBeforeCallExit( + const ExplodedNode *CurrN, const ExplodedNode *CallExitBeginN) { + return ::wasRegionOfInterestModifiedAt( + RegionOfInterest, CurrN, + CallExitBeginN->getState()->getSVal(RegionOfInterest)); } static llvm::StringLiteral WillBeUsedForACondition = @@ -681,27 +763,6 @@ PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote( const RegionVector &FieldChain, const MemRegion *MatchedRegion, StringRef FirstElement, bool FirstIsReferenceType, unsigned IndirectionLevel) { - // Optimistically suppress uninitialized value bugs that result - // from system headers having a chance to initialize the value - // but failing to do so. It's too unlikely a system header's fault. - // It's much more likely a situation in which the function has a failure - // mode that the user decided not to check. If we want to hunt such - // omitted checks, we should provide an explicit function-specific note - // describing the precondition under which the function isn't supposed to - // initialize its out-parameter, and additionally check that such - // precondition can actually be fulfilled on the current path. - if (Call.isInSystemHeader()) { - // We make an exception for system header functions that have no branches. - // Such functions unconditionally fail to initialize the variable. - // If they call other functions that have more paths within them, - // this suppression would still apply when we visit these inner functions. - // One common example of a standard function that doesn't ever initialize - // its out parameter is operator placement new; it's up to the follow-up - // constructor (if any) to initialize the memory. - if (!N->getStackFrame()->getCFG()->isLinear()) - R.markInvalid(getTag(), nullptr); - return nullptr; - } PathDiagnosticLocation L = PathDiagnosticLocation::create(N->getLocation(), SM); @@ -717,8 +778,8 @@ PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote( os << "Returning without writing to '"; // Do not generate the note if failed to pretty-print. - if (!prettyPrintRegionName(FirstElement, FirstIsReferenceType, MatchedRegion, - FieldChain, IndirectionLevel, os)) + if (!prettyPrintRegionName(FieldChain, MatchedRegion, FirstElement, + FirstIsReferenceType, IndirectionLevel, os)) return nullptr; os << "'"; @@ -727,11 +788,11 @@ PathDiagnosticPieceRef NoStoreFuncVisitor::maybeEmitNote( return std::make_shared(L, os.str()); } -bool NoStoreFuncVisitor::prettyPrintRegionName(StringRef FirstElement, - bool FirstIsReferenceType, +bool NoStoreFuncVisitor::prettyPrintRegionName(const RegionVector &FieldChain, const MemRegion *MatchedRegion, - const RegionVector &FieldChain, - int IndirectionLevel, + StringRef FirstElement, + bool FirstIsReferenceType, + unsigned IndirectionLevel, llvm::raw_svector_ostream &os) { if (FirstIsReferenceType) @@ -754,7 +815,7 @@ bool NoStoreFuncVisitor::prettyPrintRegionName(StringRef FirstElement, // Just keep going up to the base region. // Element regions may appear due to casts. - if (isa(R) || isa(R)) + if (isa(R)) continue; if (Sep.empty()) @@ -1153,7 +1214,7 @@ class StoreSiteFinder final : public TrackingBugReporterVisitor { public: /// \param V We're searching for the store where \c R received this value. /// \param R The region we're tracking. - /// \param TKind May limit the amount of notes added to the bug report. + /// \param Options Tracking behavior options. /// \param OriginSFC Only adds notes when the last store happened in a /// different stackframe to this one. Disregarded if the tracking kind /// is thorough. @@ -2674,9 +2735,8 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, const Expr *OriginalExpr = Ex; Ex = Ex->IgnoreParenCasts(); - if (isa(Ex) || isa(Ex) || - isa(Ex) || isa(Ex) || - isa(Ex)) { + if (isa(Ex)) { // Use heuristics to determine if the expression is a macro // expanding to a literal and if so, use the macro's name. SourceLocation BeginLoc = OriginalExpr->getBeginLoc(); diff --git a/clang/lib/StaticAnalyzer/Core/CallDescription.cpp b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp new file mode 100644 index 00000000000..810fe365d02 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/CallDescription.cpp @@ -0,0 +1,146 @@ +//===- CallDescription.cpp - function/method call matching --*- 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 defines a generic mechanism for matching for function and +/// method calls of C, C++, and Objective-C languages. Instances of these +/// classes are frequently used together with the CallEvent classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include + +using namespace llvm; +using namespace clang; + +using MaybeCount = Optional; + +// A constructor helper. +static MaybeCount readRequiredParams(MaybeCount RequiredArgs, + MaybeCount RequiredParams) { + if (RequiredParams) + return RequiredParams; + if (RequiredArgs) + return RequiredArgs; + return None; +} + +ento::CallDescription::CallDescription(CallDescriptionFlags Flags, + ArrayRef QualifiedName, + MaybeCount RequiredArgs /*= None*/, + MaybeCount RequiredParams /*= None*/) + : RequiredArgs(RequiredArgs), + RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)), + Flags(Flags) { + assert(!QualifiedName.empty()); + this->QualifiedName.reserve(QualifiedName.size()); + llvm::copy(QualifiedName, std::back_inserter(this->QualifiedName)); +} + +/// Construct a CallDescription with default flags. +ento::CallDescription::CallDescription(ArrayRef QualifiedName, + MaybeCount RequiredArgs /*= None*/, + MaybeCount RequiredParams /*= None*/) + : CallDescription(CDF_None, QualifiedName, RequiredArgs, RequiredParams) {} + +bool ento::CallDescription::matches(const CallEvent &Call) const { + // FIXME: Add ObjC Message support. + if (Call.getKind() == CE_ObjCMessage) + return false; + + const auto *FD = dyn_cast_or_null(Call.getDecl()); + if (!FD) + return false; + + if (Flags & CDF_MaybeBuiltin) { + return CheckerContext::isCLibraryFunction(FD, getFunctionName()) && + (!RequiredArgs || *RequiredArgs <= Call.getNumArgs()) && + (!RequiredParams || *RequiredParams <= Call.parameters().size()); + } + + if (!II.hasValue()) { + II = &Call.getState()->getStateManager().getContext().Idents.get( + getFunctionName()); + } + + const auto MatchNameOnly = [](const CallDescription &CD, + const NamedDecl *ND) -> bool { + DeclarationName Name = ND->getDeclName(); + if (const auto *II = Name.getAsIdentifierInfo()) + return II == CD.II.getValue(); // Fast case. + + // Fallback to the slow stringification and comparison for: + // C++ overloaded operators, constructors, destructors, etc. + // FIXME This comparison is way SLOWER than comparing pointers. + // At some point in the future, we should compare FunctionDecl pointers. + return Name.getAsString() == CD.getFunctionName(); + }; + + const auto ExactMatchArgAndParamCounts = + [](const CallEvent &Call, const CallDescription &CD) -> bool { + const bool ArgsMatch = + !CD.RequiredArgs || *CD.RequiredArgs == Call.getNumArgs(); + const bool ParamsMatch = + !CD.RequiredParams || *CD.RequiredParams == Call.parameters().size(); + return ArgsMatch && ParamsMatch; + }; + + const auto MatchQualifiedNameParts = [](const CallDescription &CD, + const Decl *D) -> bool { + const auto FindNextNamespaceOrRecord = + [](const DeclContext *Ctx) -> const DeclContext * { + while (Ctx && !isa(Ctx)) + Ctx = Ctx->getParent(); + return Ctx; + }; + + auto QualifierPartsIt = CD.begin_qualified_name_parts(); + const auto QualifierPartsEndIt = CD.end_qualified_name_parts(); + + // Match namespace and record names. Skip unrelated names if they don't + // match. + const DeclContext *Ctx = FindNextNamespaceOrRecord(D->getDeclContext()); + for (; Ctx && QualifierPartsIt != QualifierPartsEndIt; + Ctx = FindNextNamespaceOrRecord(Ctx->getParent())) { + // If not matched just continue and try matching for the next one. + if (cast(Ctx)->getName() != *QualifierPartsIt) + continue; + ++QualifierPartsIt; + } + + // We matched if we consumed all expected qualifier segments. + return QualifierPartsIt == QualifierPartsEndIt; + }; + + // Let's start matching... + if (!ExactMatchArgAndParamCounts(Call, *this)) + return false; + + if (!MatchNameOnly(*this, FD)) + return false; + + if (!hasQualifiedNameParts()) + return true; + + return MatchQualifiedNameParts(*this, FD); +} + +ento::CallDescriptionSet::CallDescriptionSet( + std::initializer_list &&List) { + Impl.LinearMap.reserve(List.size()); + for (const CallDescription &CD : List) + Impl.LinearMap.push_back({CD, /*unused*/ true}); +} + +bool ento::CallDescriptionSet::contains(const CallEvent &Call) const { + return static_cast(Impl.lookup(Call)); +} diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 3785f498414..764dad3e7ab 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -36,6 +36,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" #include "clang/CrossTU/CrossTranslationUnit.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" @@ -73,26 +74,7 @@ QualType CallEvent::getResultType() const { const Expr *E = getOriginExpr(); if (!E) return Ctx.VoidTy; - assert(E); - - QualType ResultTy = E->getType(); - - // A function that returns a reference to 'int' will have a result type - // of simply 'int'. Check the origin expr's value kind to recover the - // proper type. - switch (E->getValueKind()) { - case VK_LValue: - ResultTy = Ctx.getLValueReferenceType(ResultTy); - break; - case VK_XValue: - ResultTy = Ctx.getRValueReferenceType(ResultTy); - break; - case VK_PRValue: - // No adjustment is necessary. - break; - } - - return ResultTy; + return Ctx.getReferenceQualifiedType(E); } static bool isCallback(QualType T) { @@ -321,64 +303,6 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit, return PostImplicitCall(D, Loc, getLocationContext(), Tag); } -bool CallEvent::isCalled(const CallDescription &CD) const { - // FIXME: Add ObjC Message support. - if (getKind() == CE_ObjCMessage) - return false; - - const IdentifierInfo *II = getCalleeIdentifier(); - if (!II) - return false; - const FunctionDecl *FD = dyn_cast_or_null(getDecl()); - if (!FD) - return false; - - if (CD.Flags & CDF_MaybeBuiltin) { - return CheckerContext::isCLibraryFunction(FD, CD.getFunctionName()) && - (!CD.RequiredArgs || CD.RequiredArgs <= getNumArgs()) && - (!CD.RequiredParams || CD.RequiredParams <= parameters().size()); - } - - if (!CD.IsLookupDone) { - CD.IsLookupDone = true; - CD.II = &getState()->getStateManager().getContext().Idents.get( - CD.getFunctionName()); - } - - if (II != CD.II) - return false; - - // If CallDescription provides prefix names, use them to improve matching - // accuracy. - if (CD.QualifiedName.size() > 1 && FD) { - const DeclContext *Ctx = FD->getDeclContext(); - // See if we'll be able to match them all. - size_t NumUnmatched = CD.QualifiedName.size() - 1; - for (; Ctx && isa(Ctx); Ctx = Ctx->getParent()) { - if (NumUnmatched == 0) - break; - - if (const auto *ND = dyn_cast(Ctx)) { - if (ND->getName() == CD.QualifiedName[NumUnmatched - 1]) - --NumUnmatched; - continue; - } - - if (const auto *RD = dyn_cast(Ctx)) { - if (RD->getName() == CD.QualifiedName[NumUnmatched - 1]) - --NumUnmatched; - continue; - } - } - - if (NumUnmatched > 0) - return false; - } - - return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) && - (!CD.RequiredParams || CD.RequiredParams == parameters().size()); -} - SVal CallEvent::getArgSVal(unsigned Index) const { const Expr *ArgE = getArgExpr(Index); if (!ArgE) @@ -406,7 +330,6 @@ void CallEvent::dump(raw_ostream &Out) const { ASTContext &Ctx = getState()->getStateManager().getContext(); if (const Expr *E = getOriginExpr()) { E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); - Out << "\n"; return; } @@ -420,9 +343,7 @@ void CallEvent::dump(raw_ostream &Out) const { } bool CallEvent::isCallStmt(const Stmt *S) { - return isa(S) || isa(S) - || isa(S) - || isa(S); + return isa(S); } QualType CallEvent::getDeclaredResultType(const Decl *D) { @@ -676,7 +597,7 @@ bool AnyFunctionCall::argumentsMayEscape() const { // - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can // be deallocated by NSMapRemove. - if (FName.startswith("NS") && (FName.find("Insert") != StringRef::npos)) + if (FName.startswith("NS") && FName.contains("Insert")) return true; // - Many CF containers allow objects to escape through custom @@ -1058,12 +979,12 @@ const PseudoObjectExpr *ObjCMethodCall::getContainingPseudoObjectExpr() const { static const Expr * getSyntacticFromForPseudoObjectExpr(const PseudoObjectExpr *POE) { - const Expr *Syntactic = POE->getSyntacticForm(); + const Expr *Syntactic = POE->getSyntacticForm()->IgnoreParens(); // This handles the funny case of assigning to the result of a getter. // This can happen if the getter returns a non-const reference. if (const auto *BO = dyn_cast(Syntactic)) - Syntactic = BO->getLHS(); + Syntactic = BO->getLHS()->IgnoreParens(); return Syntactic; } diff --git a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp index 3d64ce45347..4c684c3ffd9 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -38,7 +38,7 @@ StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { } StringRef CheckerContext::getDeclDescription(const Decl *D) { - if (isa(D) || isa(D)) + if (isa(D)) return "method"; if (isa(D)) return "anonymous block"; @@ -55,7 +55,7 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, if (Name.empty()) return true; StringRef BName = FD->getASTContext().BuiltinInfo.getName(BId); - if (BName.find(Name) != StringRef::npos) + if (BName.contains(Name)) return true; } @@ -83,11 +83,10 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, if (FName.equals(Name)) return true; - if (FName.startswith("__inline") && (FName.find(Name) != StringRef::npos)) + if (FName.startswith("__inline") && FName.contains(Name)) return true; - if (FName.startswith("__") && FName.endswith("_chk") && - FName.find(Name) != StringRef::npos) + if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name)) return true; return false; diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index e09399a8358..94287b7992d 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormatVariadic.h" #include #include @@ -655,7 +656,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, ExprEngine &Eng, const EvalCallOptions &CallOpts) { for (auto *const Pred : Src) { - bool anyEvaluated = false; + Optional evaluatorChecker; ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); @@ -674,10 +675,26 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, CheckerContext C(B, Eng, Pred, L); evaluated = EvalCallChecker(Call, C); } - assert(!(evaluated && anyEvaluated) - && "There are more than one checkers evaluating the call"); +#ifndef NDEBUG + if (evaluated && evaluatorChecker) { + const auto toString = [](const CallEvent &Call) -> std::string { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + Call.dump(OS); + OS.flush(); + return Buf; + }; + std::string AssertionMessage = llvm::formatv( + "The '{0}' call has been already evaluated by the {1} checker, " + "while the {2} checker also tried to evaluate the same call. At " + "most one checker supposed to evaluate a call.", + toString(Call), evaluatorChecker->getName(), + EvalCallChecker.Checker->getCheckerName()); + llvm_unreachable(AssertionMessage.c_str()); + } +#endif if (evaluated) { - anyEvaluated = true; + evaluatorChecker = EvalCallChecker.Checker->getCheckerName(); Dst.insert(checkDst); #ifdef NDEBUG break; // on release don't check that no other checker also evals. @@ -686,7 +703,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, } // If none of the checkers evaluated the call, ask ExprEngine to handle it. - if (!anyEvaluated) { + if (!evaluatorChecker) { NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); Eng.defaultEvalCall(B, Pred, Call, CallOpts); } diff --git a/clang/lib/StaticAnalyzer/Core/Environment.cpp b/clang/lib/StaticAnalyzer/Core/Environment.cpp index ee747459252..64e915a09ce 100644 --- a/clang/lib/StaticAnalyzer/Core/Environment.cpp +++ b/clang/lib/StaticAnalyzer/Core/Environment.cpp @@ -88,7 +88,7 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry, const Stmt *S = Entry.getStmt(); assert(!isa(S) && "Use ExprEngine::hasMoreIteration()!"); - assert((isa(S) || isa(S)) && + assert((isa(S)) && "Environment can only argue about Exprs, since only they express " "a value! Any non-expression statement stored in Environment is a " "result of a hack!"); diff --git a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index 635495e9bf6..294572b7dbe 100644 --- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -50,8 +50,7 @@ ExplodedGraph::~ExplodedGraph() = default; bool ExplodedGraph::isInterestingLValueExpr(const Expr *Ex) { if (!Ex->isLValue()) return false; - return isa(Ex) || isa(Ex) || - isa(Ex) || isa(Ex); + return isa(Ex); } bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 66332d3b848..12b005d43c5 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -393,8 +393,7 @@ ProgramStateRef ExprEngine::createTemporaryRegionIfNeeded( SVal BaseReg = Reg; // Make the necessary adjustments to obtain the sub-object. - for (auto I = Adjustments.rbegin(), E = Adjustments.rend(); I != E; ++I) { - const SubobjectAdjustment &Adj = *I; + for (const SubobjectAdjustment &Adj : llvm::reverse(Adjustments)) { switch (Adj.Kind) { case SubobjectAdjustment::DerivedToBaseAdjustment: Reg = StoreMgr.evalDerivedToBase(Reg, Adj.DerivedToBase.BasePath); @@ -1297,8 +1296,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPInteropDirectiveClass: case Stmt::OMPDispatchDirectiveClass: case Stmt::OMPMaskedDirectiveClass: + case Stmt::OMPGenericLoopDirectiveClass: case Stmt::CapturedStmtClass: - case Stmt::OMPUnrollDirectiveClass: { + case Stmt::OMPUnrollDirectiveClass: + case Stmt::OMPMetaDirectiveClass: { const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); Engine.addAbortedBlock(node, currBldrCtx->getBlock()); break; @@ -1988,8 +1989,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 && AMgr.options.ShouldWidenLoops) { const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt(); - if (!(Term && - (isa(Term) || isa(Term) || isa(Term)))) + if (!isa_and_nonnull(Term)) return; // Widen. const LocationContext *LCtx = Pred->getLocationContext(); @@ -2265,7 +2265,7 @@ void ExprEngine::processBranch(const Stmt *Condition, continue; } if (StTrue && StFalse) - assert(!isa(Condition));; + assert(!isa(Condition)); // Process the true branch. if (builder.isFeasible(true)) { @@ -2593,7 +2593,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ProgramPoint::PostLValueKind); return; } - if (isa(D) || isa(D)) { + if (isa(D)) { // Delegate all work related to pointer to members to the surrounding // operator&. return; @@ -2670,7 +2670,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, // Handle static member variables and enum constants accessed via // member syntax. - if (isa(Member) || isa(Member)) { + if (isa(Member)) { for (const auto I : CheckedSet) VisitCommonDeclRefExpr(M, Member, I, EvalSet); } else { diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 7ad3dca831a..69d67cf9b46 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -550,7 +550,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, const Expr *Init = CL->getInitializer(); SVal V = State->getSVal(CL->getInitializer(), LCtx); - if (isa(Init) || isa(Init)) { + if (isa(Init)) { // No work needed. Just pass the value up to this expression. } else { assert(isa(Init)); @@ -757,9 +757,8 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE, return; } - for (InitListExpr::const_reverse_iterator it = IE->rbegin(), - ei = IE->rend(); it != ei; ++it) { - SVal V = state->getSVal(cast(*it), LCtx); + for (const Stmt *S : llvm::reverse(*IE)) { + SVal V = state->getSVal(cast(S), LCtx); vals = getBasicVals().prependSVal(V, vals); } @@ -984,8 +983,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, if (const DeclRefExpr *DRE = dyn_cast(Ex)) { const ValueDecl *VD = DRE->getDecl(); - if (isa(VD) || isa(VD) || - isa(VD)) { + if (isa(VD)) { ProgramStateRef State = (*I)->getState(); const LocationContext *LCtx = (*I)->getLocationContext(); SVal SV = svalBuilder.getMemberPointer(cast(VD)); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index cab65687444..ba105f34a91 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -531,7 +531,7 @@ void ExprEngine::handleConstructor(const Expr *E, // FIXME: Instead of relying on the ParentMap, we should have the // trigger-statement (InitListExpr in this case) passed down from CFG or // otherwise always available during construction. - if (dyn_cast_or_null(LCtx->getParentMap().getParent(E))) { + if (isa_and_nonnull(LCtx->getParentMap().getParent(E))) { MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(E, LCtx)); CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true; diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 64fc32ea755..3b847d6f0d8 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -27,6 +27,8 @@ #include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" @@ -57,6 +59,8 @@ using namespace ento; namespace { +class ArrowMap; + class HTMLDiagnostics : public PathDiagnosticConsumer { PathDiagnosticConsumerOptions DiagOpts; std::string Directory; @@ -77,60 +81,93 @@ public: void FlushDiagnosticsImpl(std::vector &Diags, FilesMade *filesMade) override; - StringRef getName() const override { - return "HTMLDiagnostics"; - } + StringRef getName() const override { return "HTMLDiagnostics"; } bool supportsCrossFileDiagnostics() const override { return SupportsCrossFileDiagnostics; } - unsigned ProcessMacroPiece(raw_ostream &os, - const PathDiagnosticMacroPiece& P, + unsigned ProcessMacroPiece(raw_ostream &os, const PathDiagnosticMacroPiece &P, unsigned num); + unsigned ProcessControlFlowPiece(Rewriter &R, FileID BugFileID, + const PathDiagnosticControlFlowPiece &P, + unsigned Number); + void HandlePiece(Rewriter &R, FileID BugFileID, const PathDiagnosticPiece &P, const std::vector &PopUpRanges, unsigned num, unsigned max); - void HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, + void HighlightRange(Rewriter &R, FileID BugFileID, SourceRange Range, const char *HighlightStart = "", const char *HighlightEnd = ""); - void ReportDiag(const PathDiagnostic& D, - FilesMade *filesMade); + void ReportDiag(const PathDiagnostic &D, FilesMade *filesMade); // Generate the full HTML report - std::string GenerateHTML(const PathDiagnostic& D, Rewriter &R, - const SourceManager& SMgr, const PathPieces& path, + std::string GenerateHTML(const PathDiagnostic &D, Rewriter &R, + const SourceManager &SMgr, const PathPieces &path, const char *declName); // Add HTML header/footers to file specified by FID - void FinalizeHTML(const PathDiagnostic& D, Rewriter &R, - const SourceManager& SMgr, const PathPieces& path, + void FinalizeHTML(const PathDiagnostic &D, Rewriter &R, + const SourceManager &SMgr, const PathPieces &path, FileID FID, const FileEntry *Entry, const char *declName); // Rewrite the file specified by FID with HTML formatting. - void RewriteFile(Rewriter &R, const PathPieces& path, FileID FID); + void RewriteFile(Rewriter &R, const PathPieces &path, FileID FID); + PathGenerationScheme getGenerationScheme() const override { + return Everything; + } private: + void addArrowSVGs(Rewriter &R, FileID BugFileID, + const ArrowMap &ArrowIndices); + /// \return Javascript for displaying shortcuts help; StringRef showHelpJavascript(); /// \return Javascript for navigating the HTML report using j/k keys. StringRef generateKeyboardNavigationJavascript(); + /// \return Javascript for drawing control-flow arrows. + StringRef generateArrowDrawingJavascript(); + /// \return JavaScript for an option to only show relevant lines. - std::string showRelevantLinesJavascript( - const PathDiagnostic &D, const PathPieces &path); + std::string showRelevantLinesJavascript(const PathDiagnostic &D, + const PathPieces &path); /// Write executed lines from \p D in JSON format into \p os. - void dumpCoverageData(const PathDiagnostic &D, - const PathPieces &path, + void dumpCoverageData(const PathDiagnostic &D, const PathPieces &path, llvm::raw_string_ostream &os); }; +bool isArrowPiece(const PathDiagnosticPiece &P) { + return isa(P) && P.getString().empty(); +} + +unsigned getPathSizeWithoutArrows(const PathPieces &Path) { + unsigned TotalPieces = Path.size(); + unsigned TotalArrowPieces = llvm::count_if( + Path, [](const PathDiagnosticPieceRef &P) { return isArrowPiece(*P); }); + return TotalPieces - TotalArrowPieces; +} + +class ArrowMap : public std::vector { + using Base = std::vector; + +public: + ArrowMap(unsigned Size) : Base(Size, 0) {} + unsigned getTotalNumberOfArrows() const { return at(0); } +}; + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const ArrowMap &Indices) { + OS << "[ "; + llvm::interleave(Indices, OS, ","); + return OS << " ]"; +} + } // namespace void ento::createHTMLDiagnosticConsumer( @@ -208,6 +245,18 @@ void HTMLDiagnostics::FlushDiagnosticsImpl( ReportDiag(*Diag, filesMade); } +static llvm::SmallString<32> getIssueHash(const PathDiagnostic &D, + const Preprocessor &PP) { + SourceManager &SMgr = PP.getSourceManager(); + PathDiagnosticLocation UPDLoc = D.getUniqueingLoc(); + FullSourceLoc L(SMgr.getExpansionLoc(UPDLoc.isValid() + ? UPDLoc.asLocation() + : D.getLocation().asLocation()), + SMgr); + return getIssueHash(L, D.getCheckerName(), D.getBugType(), + D.getDeclWithIssue(), PP.getLangOpts()); +} + void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, FilesMade *filesMade) { // Create the HTML directory if it is missing. @@ -234,11 +283,6 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a new rewriter to generate HTML. Rewriter R(const_cast(SMgr), PP.getLangOpts()); - // The file for the first path element is considered the main report file, it - // will usually be equivalent to SMgr.getMainFileID(); however, it might be a - // header when -analyzer-opt-analyze-headers is used. - FileID ReportFile = path.front()->getLocation().asLocation().getExpansionLoc().getFileID(); - // Get the function/method name SmallString<128> declName("unknown"); int offsetDecl = 0; @@ -265,46 +309,52 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, // Create a path for the target HTML file. int FD; - SmallString<128> Model, ResultPath; - if (!DiagOpts.ShouldWriteStableReportFilename) { - llvm::sys::path::append(Model, Directory, "report-%%%%%%.html"); - if (std::error_code EC = - llvm::sys::fs::make_absolute(Model)) { - llvm::errs() << "warning: could not make '" << Model - << "' absolute: " << EC.message() << '\n'; - return; - } - if (std::error_code EC = llvm::sys::fs::createUniqueFile( - Model, FD, ResultPath, llvm::sys::fs::OF_Text)) { - llvm::errs() << "warning: could not create file in '" << Directory - << "': " << EC.message() << '\n'; - return; - } - } else { - int i = 1; - std::error_code EC; - do { - // Find a filename which is not already used - const FileEntry* Entry = SMgr.getFileEntryForID(ReportFile); - std::stringstream filename; - Model = ""; - filename << "report-" - << llvm::sys::path::filename(Entry->getName()).str() - << "-" << declName.c_str() - << "-" << offsetDecl - << "-" << i << ".html"; - llvm::sys::path::append(Model, Directory, - filename.str()); - EC = llvm::sys::fs::openFileForReadWrite( - Model, FD, llvm::sys::fs::CD_CreateNew, llvm::sys::fs::OF_None); - if (EC && EC != llvm::errc::file_exists) { - llvm::errs() << "warning: could not create file '" << Model - << "': " << EC.message() << '\n'; - return; - } - i++; - } while (EC); + SmallString<128> FileNameStr; + llvm::raw_svector_ostream FileName(FileNameStr); + FileName << "report-"; + + // Historically, neither the stable report filename nor the unstable report + // filename were actually stable. That said, the stable report filename + // was more stable because it was mostly composed of information + // about the bug report instead of being completely random. + // Now both stable and unstable report filenames are in fact stable + // but the stable report filename is still more verbose. + if (DiagOpts.ShouldWriteVerboseReportFilename) { + // FIXME: This code relies on knowing what constitutes the issue hash. + // Otherwise deduplication won't work correctly. + FileID ReportFile = + path.back()->getLocation().asLocation().getExpansionLoc().getFileID(); + + const FileEntry *Entry = SMgr.getFileEntryForID(ReportFile); + + FileName << llvm::sys::path::filename(Entry->getName()).str() << "-" + << declName.c_str() << "-" << offsetDecl << "-"; + } + + FileName << StringRef(getIssueHash(D, PP)).substr(0, 6).str() << ".html"; + + SmallString<128> ResultPath; + llvm::sys::path::append(ResultPath, Directory, FileName.str()); + if (std::error_code EC = llvm::sys::fs::make_absolute(ResultPath)) { + llvm::errs() << "warning: could not make '" << ResultPath + << "' absolute: " << EC.message() << '\n'; + return; + } + + if (std::error_code EC = llvm::sys::fs::openFileForReadWrite( + ResultPath, FD, llvm::sys::fs::CD_CreateNew, + llvm::sys::fs::OF_Text)) { + // Existence of the file corresponds to the situation where a different + // Clang instance has emitted a bug report with the same issue hash. + // This is an entirely normal situation that does not deserve a warning, + // as apart from hash collisions this can happen because the reports + // are in fact similar enough to be considered duplicates of each other. + if (EC != llvm::errc::file_exists) { + llvm::errs() << "warning: could not create file in '" << Directory + << "': " << EC.message() << '\n'; + } + return; } llvm::raw_fd_ostream os(FD, true); @@ -452,10 +502,11 @@ window.addEventListener("keydown", function (event) { if (event.defaultPrevented) { return; } - if (event.key == "S") { + // SHIFT + S + if (event.shiftKey && event.keyCode == 83) { var checked = document.getElementsByName("showCounterexample")[0].checked; filterCounterexample(!checked); - document.getElementsByName("showCounterexample")[0].checked = !checked; + document.getElementsByName("showCounterexample")[0].click(); } else { return; } @@ -475,6 +526,11 @@ document.addEventListener("DOMContentLoaded", function() { + + )<<<"; @@ -503,6 +559,9 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), generateKeyboardNavigationJavascript()); + R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), + generateArrowDrawingJavascript()); + // Checkbox and javascript for filtering the output to the counterexample. R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), showRelevantLinesJavascript(D, path)); @@ -570,6 +629,7 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, Close )<<<"; + R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str()); } @@ -591,7 +651,6 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, ? UPDLoc.asLocation() : D.getLocation().asLocation()), SMgr); - const Decl *DeclWithIssue = D.getDeclWithIssue(); StringRef BugCategory = D.getCategory(); if (!BugCategory.empty()) @@ -603,9 +662,7 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R, os << "\n\n"; - os << "\n\n"; os << "\n\n"; - os << "\n\n"; + os << "\n\n"; // Mark the end of the tags. os << "\n\n"; @@ -695,8 +752,7 @@ static void HandlePopUpPieceEndTag(Rewriter &R, Out << "" << Piece.getString() << ""; // If no report made at this range mark the variable and add the end tags. - if (std::find(PopUpRanges.begin(), PopUpRanges.end(), Range) == - PopUpRanges.end()) { + if (!llvm::is_contained(PopUpRanges, Range)) { // Store that we create a report at this range. PopUpRanges.push_back(Range); @@ -711,30 +767,33 @@ static void HandlePopUpPieceEndTag(Rewriter &R, } } -void HTMLDiagnostics::RewriteFile(Rewriter &R, - const PathPieces& path, FileID FID) { +void HTMLDiagnostics::RewriteFile(Rewriter &R, const PathPieces &path, + FileID FID) { + // Process the path. // Maintain the counts of extra note pieces separately. - unsigned TotalPieces = path.size(); - unsigned TotalNotePieces = std::count_if( - path.begin(), path.end(), [](const PathDiagnosticPieceRef &p) { + unsigned TotalPieces = getPathSizeWithoutArrows(path); + unsigned TotalNotePieces = + llvm::count_if(path, [](const PathDiagnosticPieceRef &p) { return isa(*p); }); - unsigned PopUpPieceCount = std::count_if( - path.begin(), path.end(), [](const PathDiagnosticPieceRef &p) { + unsigned PopUpPieceCount = + llvm::count_if(path, [](const PathDiagnosticPieceRef &p) { return isa(*p); }); unsigned TotalRegularPieces = TotalPieces - TotalNotePieces - PopUpPieceCount; unsigned NumRegularPieces = TotalRegularPieces; unsigned NumNotePieces = TotalNotePieces; + unsigned NumberOfArrows = 0; // Stores the count of the regular piece indices. std::map IndexMap; + ArrowMap ArrowIndices(TotalRegularPieces + 1); // Stores the different ranges where we have reported something. std::vector PopUpRanges; - for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { - const auto &Piece = *I->get(); + for (const PathDiagnosticPieceRef &I : llvm::reverse(path)) { + const auto &Piece = *I.get(); if (isa(Piece)) { ++IndexMap[NumRegularPieces]; @@ -744,18 +803,40 @@ void HTMLDiagnostics::RewriteFile(Rewriter &R, // as a separate pass through the piece list. HandlePiece(R, FID, Piece, PopUpRanges, NumNotePieces, TotalNotePieces); --NumNotePieces; + + } else if (isArrowPiece(Piece)) { + NumberOfArrows = ProcessControlFlowPiece( + R, FID, cast(Piece), NumberOfArrows); + ArrowIndices[NumRegularPieces] = NumberOfArrows; + } else { HandlePiece(R, FID, Piece, PopUpRanges, NumRegularPieces, TotalRegularPieces); --NumRegularPieces; + ArrowIndices[NumRegularPieces] = ArrowIndices[NumRegularPieces + 1]; } } + ArrowIndices[0] = NumberOfArrows; + + // At this point ArrowIndices represent the following data structure: + // [a_0, a_1, ..., a_N] + // where N is the number of events in the path. + // + // Then for every event with index i \in [0, N - 1], we can say that + // arrows with indices \in [a_(i+1), a_i) correspond to that event. + // We can say that because arrows with these indices appeared in the + // path in between the i-th and the (i+1)-th events. + assert(ArrowIndices.back() == 0 && + "No arrows should be after the last event"); + // This assertion also guarantees that all indices in are <= NumberOfArrows. + assert(llvm::is_sorted(ArrowIndices, std::greater()) && + "Incorrect arrow indices map"); // Secondary indexing if we are having multiple pop-ups between two notes. // (e.g. [(13) 'a' is 'true']; [(13.1) 'b' is 'false']; [(13.2) 'c' is...) NumRegularPieces = TotalRegularPieces; - for (auto I = path.rbegin(), E = path.rend(); I != E; ++I) { - const auto &Piece = *I->get(); + for (const PathDiagnosticPieceRef &I : llvm::reverse(path)) { + const auto &Piece = *I.get(); if (const auto *PopUpP = dyn_cast(&Piece)) { int PopUpPieceIndex = IndexMap[NumRegularPieces]; @@ -771,7 +852,7 @@ void HTMLDiagnostics::RewriteFile(Rewriter &R, if (PopUpPieceIndex > 0) --IndexMap[NumRegularPieces]; - } else if (!isa(Piece)) { + } else if (!isa(Piece) && !isArrowPiece(Piece)) { --NumRegularPieces; } } @@ -783,6 +864,8 @@ void HTMLDiagnostics::RewriteFile(Rewriter &R, html::EscapeText(R, FID); html::AddLineNumbers(R, FID); + addArrowSVGs(R, FID, ArrowIndices); + // If we have a preprocessor, relex the file and syntax highlight. // We might not have a preprocessor if we come from a deserialized AST file, // for example. @@ -1007,8 +1090,7 @@ void HTMLDiagnostics::HandlePiece(Rewriter &R, FileID BugFileID, ArrayRef Ranges = P.getRanges(); for (const auto &Range : Ranges) { // If we have already highlighted the range as a pop-up there is no work. - if (std::find(PopUpRanges.begin(), PopUpRanges.end(), Range) != - PopUpRanges.end()) + if (llvm::is_contained(PopUpRanges, Range)) continue; HighlightRange(R, LPosInfo.first, Range); @@ -1049,6 +1131,104 @@ unsigned HTMLDiagnostics::ProcessMacroPiece(raw_ostream &os, return num; } +void HTMLDiagnostics::addArrowSVGs(Rewriter &R, FileID BugFileID, + const ArrowMap &ArrowIndices) { + std::string S; + llvm::raw_string_ostream OS(S); + + OS << R"<<<( + + + + + + + + + + + +)<<<"; + + for (unsigned Index : llvm::seq(0u, ArrowIndices.getTotalNumberOfArrows())) { + OS << " \n"; + } + + OS << R"<<<( + + +\n"; + + R.InsertTextBefore(R.getSourceMgr().getLocForStartOfFile(BugFileID), + OS.str()); +} + +std::string getSpanBeginForControl(const char *ClassName, unsigned Index) { + std::string Result; + llvm::raw_string_ostream OS(Result); + OS << ""; + return OS.str(); +} + +std::string getSpanBeginForControlStart(unsigned Index) { + return getSpanBeginForControl("start", Index); +} + +std::string getSpanBeginForControlEnd(unsigned Index) { + return getSpanBeginForControl("end", Index); +} + +unsigned HTMLDiagnostics::ProcessControlFlowPiece( + Rewriter &R, FileID BugFileID, const PathDiagnosticControlFlowPiece &P, + unsigned Number) { + for (const PathDiagnosticLocationPair &LPair : P) { + std::string Start = getSpanBeginForControlStart(Number), + End = getSpanBeginForControlEnd(Number++); + + HighlightRange(R, BugFileID, LPair.getStart().asRange().getBegin(), + Start.c_str()); + HighlightRange(R, BugFileID, LPair.getEnd().asRange().getBegin(), + End.c_str()); + } + + return Number; +} + void HTMLDiagnostics::HighlightRange(Rewriter& R, FileID BugFileID, SourceRange Range, const char *HighlightStart, @@ -1109,7 +1289,7 @@ document.addEventListener("DOMContentLoaded", function() { }); var findNum = function() { - var s = document.querySelector(".selected"); + var s = document.querySelector(".msg.selected"); if (!s || s.id == "EndPath") { return 0; } @@ -1117,14 +1297,32 @@ var findNum = function() { return out; }; +var classListAdd = function(el, theClass) { + if(!el.className.baseVal) + el.className += " " + theClass; + else + el.className.baseVal += " " + theClass; +}; + +var classListRemove = function(el, theClass) { + var className = (!el.className.baseVal) ? + el.className : el.className.baseVal; + className = className.replace(" " + theClass, ""); + if(!el.className.baseVal) + el.className = className; + else + el.className.baseVal = className; +}; + var scrollTo = function(el) { querySelectorAllArray(".selected").forEach(function(s) { - s.classList.remove("selected"); + classListRemove(s, "selected"); }); - el.classList.add("selected"); + classListAdd(el, "selected"); window.scrollBy(0, el.getBoundingClientRect().top - (window.innerHeight / 2)); -} + highlightArrowsForSelectedEvent(); +}; var move = function(num, up, numItems) { if (num == 1 && up || num == numItems - 1 && !up) { @@ -1159,9 +1357,11 @@ window.addEventListener("keydown", function (event) { if (event.defaultPrevented) { return; } - if (event.key == "j") { + // key 'j' + if (event.keyCode == 74) { navigateTo(/*up=*/false); - } else if (event.key == "k") { + // key 'k' + } else if (event.keyCode == 75) { navigateTo(/*up=*/true); } else { return; @@ -1171,3 +1371,258 @@ window.addEventListener("keydown", function (event) { )<<<"; } + +StringRef HTMLDiagnostics::generateArrowDrawingJavascript() { + return R"<<<( + + )<<<"; +} diff --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp index e5f4e9ea30c..8bf6fc085c6 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp @@ -69,7 +69,7 @@ namespace clang { namespace ento { static bool isLoopStmt(const Stmt *S) { - return S && (isa(S) || isa(S) || isa(S)); + return isa_and_nonnull(S); } ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) { diff --git a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp index 47e34dd84b9..748c65f578a 100644 --- a/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp +++ b/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp @@ -45,8 +45,7 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState, const LocationContext *LCtx, unsigned BlockCount, const Stmt *LoopStmt) { - assert(isa(LoopStmt) || isa(LoopStmt) || - isa(LoopStmt)); + assert((isa(LoopStmt))); // Invalidate values in the current state. // TODO Make this more conservative by only invalidating values that might diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index bd725ee9eaa..f77fcb030a1 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -28,6 +28,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" @@ -768,14 +769,39 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR, return UnknownVal(); QualType Ty = cast(SR)->getDesugaredValueType(Ctx); - DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB); + const DefinedOrUnknownSVal Size = getElementExtent(Ty, SVB); - // A zero-length array at the end of a struct often stands for dynamically - // allocated extra memory. - if (Size.isZeroConstant()) { - if (isa(Ty)) - return UnknownVal(); - } + // We currently don't model flexible array members (FAMs), which are: + // - int array[]; of IncompleteArrayType + // - int array[0]; of ConstantArrayType with size 0 + // - int array[1]; of ConstantArrayType with size 1 (*) + // (*): Consider single element array object members as FAM candidates only + // if the consider-single-element-arrays-as-flexible-array-members + // analyzer option is true. + // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html + const auto isFlexibleArrayMemberCandidate = [this, + &SVB](QualType Ty) -> bool { + const ArrayType *AT = Ctx.getAsArrayType(Ty); + if (!AT) + return false; + if (isa(AT)) + return true; + + if (const auto *CAT = dyn_cast(AT)) { + const llvm::APInt &Size = CAT->getSize(); + if (Size.isZero()) + return true; + + const AnalyzerOptions &Opts = SVB.getAnalyzerOptions(); + if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers && + Size.isOne()) + return true; + } + return false; + }; + + if (isFlexibleArrayMemberCandidate(Ty)) + return UnknownVal(); return Size; } @@ -948,9 +974,9 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, // First handle the globals defined in system headers. if (Ctx.getSourceManager().isInSystemHeader(D->getLocation())) { - // Whitelist the system globals which often DO GET modified, assume the + // Allow the system globals which often DO GET modified, assume the // rest are immutable. - if (D->getName().find("errno") != StringRef::npos) + if (D->getName().contains("errno")) sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); else sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); @@ -986,14 +1012,15 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D, sReg = getUnknownRegion(); } else { if (D->hasLocalStorage()) { - sReg = isa(D) || isa(D) - ? static_cast(getStackArgumentsRegion(STC)) - : static_cast(getStackLocalsRegion(STC)); + sReg = + isa(D) + ? static_cast(getStackArgumentsRegion(STC)) + : static_cast(getStackLocalsRegion(STC)); } else { assert(D->isStaticLocal()); const Decl *STCD = STC->getDecl(); - if (isa(STCD) || isa(STCD)) + if (isa(STCD)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, getFunctionCodeRegion(cast(STCD))); else if (const auto *BD = dyn_cast(STCD)) { @@ -1257,9 +1284,7 @@ bool MemRegion::hasStackParametersStorage() const { } bool MemRegion::hasGlobalsOrParametersStorage() const { - const MemSpaceRegion *MS = getMemorySpace(); - return isa(MS) || - isa(MS); + return isa(getMemorySpace()); } // getBaseRegion strips away all elements and fields, and get the base region diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 69554576bdb..74403a160b8 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -494,15 +494,17 @@ RangeSet RangeSet::Factory::deletePoint(RangeSet From, return intersect(From, Upper, Lower); } -void Range::dump(raw_ostream &OS) const { +LLVM_DUMP_METHOD void Range::dump(raw_ostream &OS) const { OS << '[' << toString(From(), 10) << ", " << toString(To(), 10) << ']'; } +LLVM_DUMP_METHOD void Range::dump() const { dump(llvm::errs()); } -void RangeSet::dump(raw_ostream &OS) const { +LLVM_DUMP_METHOD void RangeSet::dump(raw_ostream &OS) const { OS << "{ "; llvm::interleaveComma(*this, OS, [&OS](const Range &R) { R.dump(OS); }); OS << " }"; } +LLVM_DUMP_METHOD void RangeSet::dump() const { dump(llvm::errs()); } REGISTER_SET_FACTORY_WITH_PROGRAMSTATE(SymbolSet, SymbolRef) @@ -599,6 +601,10 @@ public: LLVM_NODISCARD static inline Optional areEqual(ProgramStateRef State, SymbolRef First, SymbolRef Second); + /// Remove one member from the class. + LLVM_NODISCARD ProgramStateRef removeMember(ProgramStateRef State, + const SymbolRef Old); + /// Iterate over all symbols and try to simplify them. LLVM_NODISCARD static inline ProgramStateRef simplify(SValBuilder &SVB, RangeSet::Factory &F, @@ -655,6 +661,7 @@ private: inline ProgramStateRef mergeImpl(RangeSet::Factory &F, ProgramStateRef State, SymbolSet Members, EquivalenceClass Other, SymbolSet OtherMembers); + static inline bool addToDisequalityInfo(DisequalityMapTy &Info, ConstraintRangeTy &Constraints, RangeSet::Factory &F, ProgramStateRef State, @@ -1112,7 +1119,7 @@ private: if (!SSE) return llvm::None; - BinaryOperatorKind CurrentOP = SSE->getOpcode(); + const BinaryOperatorKind CurrentOP = SSE->getOpcode(); // We currently do not support <=> (C++20). if (!BinaryOperator::isComparisonOp(CurrentOP) || (CurrentOP == BO_Cmp)) @@ -1126,7 +1133,12 @@ private: SymbolManager &SymMgr = State->getSymbolManager(); - int UnknownStates = 0; + // We use this variable to store the last queried operator (`QueriedOP`) + // for which the `getCmpOpState` returned with `Unknown`. If there are two + // different OPs that returned `Unknown` then we have to query the special + // `UnknownX2` column. We assume that `getCmpOpState(CurrentOP, CurrentOP)` + // never returns `Unknown`, so `CurrentOP` is a good initial value. + BinaryOperatorKind LastQueriedOpToUnknown = CurrentOP; // Loop goes through all of the columns exept the last one ('UnknownX2'). // We treat `UnknownX2` column separately at the end of the loop body. @@ -1163,15 +1175,18 @@ private: CmpOpTable.getCmpOpState(CurrentOP, QueriedOP); if (BranchState == OperatorRelationsTable::Unknown) { - if (++UnknownStates == 2) - // If we met both Unknown states. + if (LastQueriedOpToUnknown != CurrentOP && + LastQueriedOpToUnknown != QueriedOP) { + // If we got the Unknown state for both different operators. // if (x <= y) // assume true // if (x != y) // assume true // if (x < y) // would be also true // Get a state from `UnknownX2` column. BranchState = CmpOpTable.getCmpOpStateForUnknownX2(CurrentOP); - else + } else { + LastQueriedOpToUnknown = QueriedOP; continue; + } } return (BranchState == OperatorRelationsTable::True) ? getTrueRange(T) @@ -1381,6 +1396,113 @@ RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)}; } +//===----------------------------------------------------------------------===// +// Constraint manager implementation details +//===----------------------------------------------------------------------===// + +class RangeConstraintManager : public RangedConstraintManager { +public: + RangeConstraintManager(ExprEngine *EE, SValBuilder &SVB) + : RangedConstraintManager(EE, SVB), F(getBasicVals()) {} + + //===------------------------------------------------------------------===// + // Implementation for interface from ConstraintManager. + //===------------------------------------------------------------------===// + + bool haveEqualConstraints(ProgramStateRef S1, + ProgramStateRef S2) const override { + // NOTE: ClassMembers are as simple as back pointers for ClassMap, + // so comparing constraint ranges and class maps should be + // sufficient. + return S1->get() == S2->get() && + S1->get() == S2->get(); + } + + bool canReasonAbout(SVal X) const override; + + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override; + + const llvm::APSInt *getSymVal(ProgramStateRef State, + SymbolRef Sym) const override; + + ProgramStateRef removeDeadBindings(ProgramStateRef State, + SymbolReaper &SymReaper) override; + + void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", + unsigned int Space = 0, bool IsDot = false) const override; + void printConstraints(raw_ostream &Out, ProgramStateRef State, + const char *NL = "\n", unsigned int Space = 0, + bool IsDot = false) const; + void printEquivalenceClasses(raw_ostream &Out, ProgramStateRef State, + const char *NL = "\n", unsigned int Space = 0, + bool IsDot = false) const; + void printDisequalities(raw_ostream &Out, ProgramStateRef State, + const char *NL = "\n", unsigned int Space = 0, + bool IsDot = false) const; + + //===------------------------------------------------------------------===// + // Implementation for interface from RangedConstraintManager. + //===------------------------------------------------------------------===// + + ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym, + const llvm::APSInt &V, + const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymWithinInclusiveRange( + ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, + const llvm::APSInt &To, const llvm::APSInt &Adjustment) override; + + ProgramStateRef assumeSymOutsideInclusiveRange( + ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, + const llvm::APSInt &To, const llvm::APSInt &Adjustment) override; + +private: + RangeSet::Factory F; + + RangeSet getRange(ProgramStateRef State, SymbolRef Sym); + RangeSet getRange(ProgramStateRef State, EquivalenceClass Class); + ProgramStateRef setRange(ProgramStateRef State, SymbolRef Sym, + RangeSet Range); + ProgramStateRef setRange(ProgramStateRef State, EquivalenceClass Class, + RangeSet Range); + + RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment); + RangeSet getSymGTRange(ProgramStateRef St, SymbolRef Sym, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment); + RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment); + RangeSet getSymLERange(llvm::function_ref RS, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment); + RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym, + const llvm::APSInt &Int, + const llvm::APSInt &Adjustment); +}; + //===----------------------------------------------------------------------===// // Constraint assignment logic //===----------------------------------------------------------------------===// @@ -1492,7 +1614,28 @@ public: return Assignor.assign(CoS, NewConstraint); } + /// Handle expressions like: a % b != 0. + template + bool handleRemainderOp(const SymT *Sym, RangeSet Constraint) { + if (Sym->getOpcode() != BO_Rem) + return true; + // a % b != 0 implies that a != 0. + if (!Constraint.containsZero()) { + SVal SymSVal = Builder.makeSymbolVal(Sym->getLHS()); + if (auto NonLocSymSVal = SymSVal.getAs()) { + State = State->assume(*NonLocSymSVal, true); + if (!State) + return false; + } + } + return true; + } + inline bool assignSymExprToConst(const SymExpr *Sym, Const Constraint); + inline bool assignSymIntExprToRangeSet(const SymIntExpr *Sym, + RangeSet Constraint) { + return handleRemainderOp(Sym, Constraint); + } inline bool assignSymSymExprToRangeSet(const SymSymExpr *Sym, RangeSet Constraint); @@ -1568,11 +1711,9 @@ private: assert(!Constraint.isEmpty() && "Empty ranges shouldn't get here"); if (Constraint.getConcreteValue()) - return !Constraint.getConcreteValue()->isNullValue(); + return !Constraint.getConcreteValue()->isZero(); - APSIntType T{Constraint.getMinValue()}; - Const Zero = T.getZeroValue(); - if (!Constraint.contains(Zero)) + if (!Constraint.containsZero()) return true; return llvm::None; @@ -1583,112 +1724,6 @@ private: RangeSet::Factory &RangeFactory; }; -//===----------------------------------------------------------------------===// -// Constraint manager implementation details -//===----------------------------------------------------------------------===// - -class RangeConstraintManager : public RangedConstraintManager { -public: - RangeConstraintManager(ExprEngine *EE, SValBuilder &SVB) - : RangedConstraintManager(EE, SVB), F(getBasicVals()) {} - - //===------------------------------------------------------------------===// - // Implementation for interface from ConstraintManager. - //===------------------------------------------------------------------===// - - bool haveEqualConstraints(ProgramStateRef S1, - ProgramStateRef S2) const override { - // NOTE: ClassMembers are as simple as back pointers for ClassMap, - // so comparing constraint ranges and class maps should be - // sufficient. - return S1->get() == S2->get() && - S1->get() == S2->get(); - } - - bool canReasonAbout(SVal X) const override; - - ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym) override; - - const llvm::APSInt *getSymVal(ProgramStateRef State, - SymbolRef Sym) const override; - - ProgramStateRef removeDeadBindings(ProgramStateRef State, - SymbolReaper &SymReaper) override; - - void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", - unsigned int Space = 0, bool IsDot = false) const override; - void printConstraints(raw_ostream &Out, ProgramStateRef State, - const char *NL = "\n", unsigned int Space = 0, - bool IsDot = false) const; - void printEquivalenceClasses(raw_ostream &Out, ProgramStateRef State, - const char *NL = "\n", unsigned int Space = 0, - bool IsDot = false) const; - void printDisequalities(raw_ostream &Out, ProgramStateRef State, - const char *NL = "\n", unsigned int Space = 0, - bool IsDot = false) const; - - //===------------------------------------------------------------------===// - // Implementation for interface from RangedConstraintManager. - //===------------------------------------------------------------------===// - - ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymLT(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymGT(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymLE(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymGE(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymWithinInclusiveRange( - ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, - const llvm::APSInt &To, const llvm::APSInt &Adjustment) override; - - ProgramStateRef assumeSymOutsideInclusiveRange( - ProgramStateRef State, SymbolRef Sym, const llvm::APSInt &From, - const llvm::APSInt &To, const llvm::APSInt &Adjustment) override; - -private: - RangeSet::Factory F; - - RangeSet getRange(ProgramStateRef State, SymbolRef Sym); - RangeSet getRange(ProgramStateRef State, EquivalenceClass Class); - ProgramStateRef setRange(ProgramStateRef State, SymbolRef Sym, - RangeSet Range); - ProgramStateRef setRange(ProgramStateRef State, EquivalenceClass Class, - RangeSet Range); - - RangeSet getSymLTRange(ProgramStateRef St, SymbolRef Sym, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment); - RangeSet getSymGTRange(ProgramStateRef St, SymbolRef Sym, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment); - RangeSet getSymLERange(ProgramStateRef St, SymbolRef Sym, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment); - RangeSet getSymLERange(llvm::function_ref RS, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment); - RangeSet getSymGERange(ProgramStateRef St, SymbolRef Sym, - const llvm::APSInt &Int, - const llvm::APSInt &Adjustment); -}; bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym, const llvm::APSInt &Constraint) { @@ -1716,11 +1751,26 @@ bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym, return false; } + // We may have trivial equivalence classes in the disequality info as + // well, and we need to simplify them. + DisequalityMapTy DisequalityInfo = State->get(); + for (std::pair DisequalityEntry : + DisequalityInfo) { + EquivalenceClass Class = DisequalityEntry.first; + ClassSet DisequalClasses = DisequalityEntry.second; + State = EquivalenceClass::simplify(Builder, RangeFactory, State, Class); + if (!State) + return false; + } + return true; } bool ConstraintAssignor::assignSymSymExprToRangeSet(const SymSymExpr *Sym, RangeSet Constraint) { + if (!handleRemainderOp(Sym, Constraint)) + return false; + Optional ConstraintAsBool = interpreteAsBool(Constraint); if (!ConstraintAsBool) @@ -2086,6 +2136,61 @@ inline Optional EquivalenceClass::areEqual(ProgramStateRef State, return llvm::None; } +LLVM_NODISCARD ProgramStateRef +EquivalenceClass::removeMember(ProgramStateRef State, const SymbolRef Old) { + + SymbolSet ClsMembers = getClassMembers(State); + assert(ClsMembers.contains(Old)); + + // We don't remove `Old`'s Sym->Class relation for two reasons: + // 1) This way constraints for the old symbol can still be found via it's + // equivalence class that it used to be the member of. + // 2) Performance and resource reasons. We can spare one removal and thus one + // additional tree in the forest of `ClassMap`. + + // Remove `Old`'s Class->Sym relation. + SymbolSet::Factory &F = getMembersFactory(State); + ClassMembersTy::Factory &EMFactory = State->get_context(); + ClsMembers = F.remove(ClsMembers, Old); + // Ensure another precondition of the removeMember function (we can check + // this only with isEmpty, thus we have to do the remove first). + assert(!ClsMembers.isEmpty() && + "Class should have had at least two members before member removal"); + // Overwrite the existing members assigned to this class. + ClassMembersTy ClassMembersMap = State->get(); + ClassMembersMap = EMFactory.add(ClassMembersMap, *this, ClsMembers); + State = State->set(ClassMembersMap); + + return State; +} + +// Re-evaluate an SVal with top-level `State->assume` logic. +LLVM_NODISCARD ProgramStateRef reAssume(ProgramStateRef State, + const RangeSet *Constraint, + SVal TheValue) { + if (!Constraint) + return State; + + const auto DefinedVal = TheValue.castAs(); + + // If the SVal is 0, we can simply interpret that as `false`. + if (Constraint->encodesFalseRange()) + return State->assume(DefinedVal, false); + + // If the constraint does not encode 0 then we can interpret that as `true` + // AND as a Range(Set). + if (Constraint->encodesTrueRange()) { + State = State->assume(DefinedVal, true); + if (!State) + return nullptr; + // Fall through, re-assume based on the range values as well. + } + // Overestimate the individual Ranges with the RangeSet' lowest and + // highest values. + return State->assumeInclusiveRange(DefinedVal, Constraint->getMinValue(), + Constraint->getMaxValue(), true); +} + // Iterate over all symbols and try to simplify them. Once a symbol is // simplified then we check if we can merge the simplified symbol's equivalence // class to this class. This way, we simplify not just the symbols but the @@ -2096,14 +2201,62 @@ EquivalenceClass::simplify(SValBuilder &SVB, RangeSet::Factory &F, ProgramStateRef State, EquivalenceClass Class) { SymbolSet ClassMembers = Class.getClassMembers(State); for (const SymbolRef &MemberSym : ClassMembers) { - SymbolRef SimplifiedMemberSym = ento::simplify(State, MemberSym); + + const SVal SimplifiedMemberVal = simplifyToSVal(State, MemberSym); + const SymbolRef SimplifiedMemberSym = SimplifiedMemberVal.getAsSymbol(); + + // The symbol is collapsed to a constant, check if the current State is + // still feasible. + if (const auto CI = SimplifiedMemberVal.getAs()) { + const llvm::APSInt &SV = CI->getValue(); + const RangeSet *ClassConstraint = getConstraint(State, Class); + // We have found a contradiction. + if (ClassConstraint && !ClassConstraint->contains(SV)) + return nullptr; + } + if (SimplifiedMemberSym && MemberSym != SimplifiedMemberSym) { // The simplified symbol should be the member of the original Class, // however, it might be in another existing class at the moment. We // have to merge these classes. + ProgramStateRef OldState = State; State = merge(F, State, MemberSym, SimplifiedMemberSym); if (!State) return nullptr; + // No state change, no merge happened actually. + if (OldState == State) + continue; + + assert(find(State, MemberSym) == find(State, SimplifiedMemberSym)); + // Remove the old and more complex symbol. + State = find(State, MemberSym).removeMember(State, MemberSym); + + // Query the class constraint again b/c that may have changed during the + // merge above. + const RangeSet *ClassConstraint = getConstraint(State, Class); + + // Re-evaluate an SVal with top-level `State->assume`, this ignites + // a RECURSIVE algorithm that will reach a FIXPOINT. + // + // About performance and complexity: Let us assume that in a State we + // have N non-trivial equivalence classes and that all constraints and + // disequality info is related to non-trivial classes. In the worst case, + // we can simplify only one symbol of one class in each iteration. The + // number of symbols in one class cannot grow b/c we replace the old + // symbol with the simplified one. Also, the number of the equivalence + // classes can decrease only, b/c the algorithm does a merge operation + // optionally. We need N iterations in this case to reach the fixpoint. + // Thus, the steps needed to be done in the worst case is proportional to + // N*N. + // + // This worst case scenario can be extended to that case when we have + // trivial classes in the constraints and in the disequality map. This + // case can be reduced to the case with a State where there are only + // non-trivial classes. This is because a merge operation on two trivial + // classes results in one non-trivial class. + State = reAssume(State, ClassConstraint, SimplifiedMemberVal); + if (!State) + return nullptr; } } return State; diff --git a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp index d227c025fb2..892d64ea4e4 100644 --- a/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp @@ -41,7 +41,12 @@ ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State, return assumeSymRel(State, SIE->getLHS(), op, SIE->getRHS()); } - } else if (const SymSymExpr *SSE = dyn_cast(Sym)) { + // Handle adjustment with non-comparison ops. + const llvm::APSInt &Zero = getBasicVals().getValue(0, SIE->getType()); + return assumeSymRel(State, SIE, (Assumption ? BO_NE : BO_EQ), Zero); + } + + if (const auto *SSE = dyn_cast(Sym)) { BinaryOperator::Opcode Op = SSE->getOpcode(); assert(BinaryOperator::isComparisonOp(Op)); @@ -226,9 +231,13 @@ void RangedConstraintManager::computeAdjustment(SymbolRef &Sym, } } -SymbolRef simplify(ProgramStateRef State, SymbolRef Sym) { +SVal simplifyToSVal(ProgramStateRef State, SymbolRef Sym) { SValBuilder &SVB = State->getStateManager().getSValBuilder(); - SVal SimplifiedVal = SVB.simplifySVal(State, SVB.makeSymbolVal(Sym)); + return SVB.simplifySVal(State, SVB.makeSymbolVal(Sym)); +} + +SymbolRef simplify(ProgramStateRef State, SymbolRef Sym) { + SVal SimplifiedVal = simplifyToSVal(State, Sym); if (SymbolRef SimplifiedSym = SimplifiedVal.getAsSymbol()) return SimplifiedSym; return Sym; diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 4ffa1aacb41..135130b35ba 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -62,8 +62,8 @@ private: : P(r, k), Data(offset) { assert(r && "Must have known regions."); assert(getOffset() == offset && "Failed to store offset"); - assert((r == r->getBaseRegion() || isa(r) || - isa (r)) && + assert((r == r->getBaseRegion() || + isa(r)) && "Not a base"); } public: @@ -437,6 +437,15 @@ public: RegionBindingsRef removeSubRegionBindings(RegionBindingsConstRef B, const SubRegion *R); + Optional + getConstantValFromConstArrayInitializer(RegionBindingsConstRef B, + const ElementRegion *R); + Optional + getSValFromInitListExpr(const InitListExpr *ILE, + const SmallVector &ConcreteOffsets, + QualType ElemT); + SVal getSValFromStringLiteral(const StringLiteral *SL, uint64_t Offset, + QualType ElemT); public: // Part of public interface to class. @@ -1135,7 +1144,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, if (Regions) Regions->push_back(baseR); - if (isa(baseR) || isa(baseR)) { + if (isa(baseR)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = @@ -1224,7 +1233,7 @@ void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, // detection. SVal V = I.getData(); const MemRegion *R = V.getAsRegion(); - if (R && isa(R)) + if (isa_and_nonnull(R)) VisitBinding(V); } } @@ -1625,6 +1634,280 @@ RegionStoreManager::findLazyBinding(RegionBindingsConstRef B, return Result; } +/// This is a helper function for `getConstantValFromConstArrayInitializer`. +/// +/// Return an array of extents of the declared array type. +/// +/// E.g. for `int x[1][2][3];` returns { 1, 2, 3 }. +static SmallVector +getConstantArrayExtents(const ConstantArrayType *CAT) { + assert(CAT && "ConstantArrayType should not be null"); + CAT = cast(CAT->getCanonicalTypeInternal()); + SmallVector Extents; + do { + Extents.push_back(CAT->getSize().getZExtValue()); + } while ((CAT = dyn_cast(CAT->getElementType()))); + return Extents; +} + +/// This is a helper function for `getConstantValFromConstArrayInitializer`. +/// +/// Return an array of offsets from nested ElementRegions and a root base +/// region. The array is never empty and a base region is never null. +/// +/// E.g. for `Element{Element{Element{VarRegion},1},2},3}` returns { 3, 2, 1 }. +/// This represents an access through indirection: `arr[1][2][3];` +/// +/// \param ER The given (possibly nested) ElementRegion. +/// +/// \note The result array is in the reverse order of indirection expression: +/// arr[1][2][3] -> { 3, 2, 1 }. This helps to provide complexity O(n), where n +/// is a number of indirections. It may not affect performance in real-life +/// code, though. +static std::pair, const MemRegion *> +getElementRegionOffsetsWithBase(const ElementRegion *ER) { + assert(ER && "ConstantArrayType should not be null"); + const MemRegion *Base; + SmallVector SValOffsets; + do { + SValOffsets.push_back(ER->getIndex()); + Base = ER->getSuperRegion(); + ER = dyn_cast(Base); + } while (ER); + return {SValOffsets, Base}; +} + +/// This is a helper function for `getConstantValFromConstArrayInitializer`. +/// +/// Convert array of offsets from `SVal` to `uint64_t` in consideration of +/// respective array extents. +/// \param SrcOffsets [in] The array of offsets of type `SVal` in reversed +/// order (expectedly received from `getElementRegionOffsetsWithBase`). +/// \param ArrayExtents [in] The array of extents. +/// \param DstOffsets [out] The array of offsets of type `uint64_t`. +/// \returns: +/// - `None` for successful convertion. +/// - `UndefinedVal` or `UnknownVal` otherwise. It's expected that this SVal +/// will be returned as a suitable value of the access operation. +/// which should be returned as a correct +/// +/// \example: +/// const int arr[10][20][30] = {}; // ArrayExtents { 10, 20, 30 } +/// int x1 = arr[4][5][6]; // SrcOffsets { NonLoc(6), NonLoc(5), NonLoc(4) } +/// // DstOffsets { 4, 5, 6 } +/// // returns None +/// int x2 = arr[42][5][-6]; // returns UndefinedVal +/// int x3 = arr[4][5][x2]; // returns UnknownVal +static Optional +convertOffsetsFromSvalToUnsigneds(const SmallVector &SrcOffsets, + const SmallVector ArrayExtents, + SmallVector &DstOffsets) { + // Check offsets for being out of bounds. + // C++20 [expr.add] 7.6.6.4 (excerpt): + // If P points to an array element i of an array object x with n + // elements, where i < 0 or i > n, the behavior is undefined. + // Dereferencing is not allowed on the "one past the last + // element", when i == n. + // Example: + // const int arr[3][2] = {{1, 2}, {3, 4}}; + // arr[0][0]; // 1 + // arr[0][1]; // 2 + // arr[0][2]; // UB + // arr[1][0]; // 3 + // arr[1][1]; // 4 + // arr[1][-1]; // UB + // arr[2][0]; // 0 + // arr[2][1]; // 0 + // arr[-2][0]; // UB + DstOffsets.resize(SrcOffsets.size()); + auto ExtentIt = ArrayExtents.begin(); + auto OffsetIt = DstOffsets.begin(); + // Reverse `SValOffsets` to make it consistent with `ArrayExtents`. + for (SVal V : llvm::reverse(SrcOffsets)) { + if (auto CI = V.getAs()) { + // When offset is out of array's bounds, result is UB. + const llvm::APSInt &Offset = CI->getValue(); + if (Offset.isNegative() || Offset.uge(*(ExtentIt++))) + return UndefinedVal(); + // Store index in a reversive order. + *(OffsetIt++) = Offset.getZExtValue(); + continue; + } + // Symbolic index presented. Return Unknown value. + // FIXME: We also need to take ElementRegions with symbolic indexes into + // account. + return UnknownVal(); + } + return None; +} + +Optional RegionStoreManager::getConstantValFromConstArrayInitializer( + RegionBindingsConstRef B, const ElementRegion *R) { + assert(R && "ElementRegion should not be null"); + + // Treat an n-dimensional array. + SmallVector SValOffsets; + const MemRegion *Base; + std::tie(SValOffsets, Base) = getElementRegionOffsetsWithBase(R); + const VarRegion *VR = dyn_cast(Base); + if (!VR) + return None; + + assert(!SValOffsets.empty() && "getElementRegionOffsets guarantees the " + "offsets vector is not empty."); + + // Check if the containing array has an initialized value that we can trust. + // We can trust a const value or a value of a global initializer in main(). + const VarDecl *VD = VR->getDecl(); + if (!VD->getType().isConstQualified() && + !R->getElementType().isConstQualified() && + (!B.isMainAnalysis() || !VD->hasGlobalStorage())) + return None; + + // Array's declaration should have `ConstantArrayType` type, because only this + // type contains an array extent. It may happen that array type can be of + // `IncompleteArrayType` type. To get the declaration of `ConstantArrayType` + // type, we should find the declaration in the redeclarations chain that has + // the initialization expression. + // NOTE: `getAnyInitializer` has an out-parameter, which returns a new `VD` + // from which an initializer is obtained. We replace current `VD` with the new + // `VD`. If the return value of the function is null than `VD` won't be + // replaced. + const Expr *Init = VD->getAnyInitializer(VD); + // NOTE: If `Init` is non-null, then a new `VD` is non-null for sure. So check + // `Init` for null only and don't worry about the replaced `VD`. + if (!Init) + return None; + + // Array's declaration should have ConstantArrayType type, because only this + // type contains an array extent. + const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(VD->getType()); + if (!CAT) + return None; + + // Get array extents. + SmallVector Extents = getConstantArrayExtents(CAT); + + // The number of offsets should equal to the numbers of extents, + // otherwise wrong type punning occured. For instance: + // int arr[1][2][3]; + // auto ptr = (int(*)[42])arr; + // auto x = ptr[4][2]; // UB + // FIXME: Should return UndefinedVal. + if (SValOffsets.size() != Extents.size()) + return None; + + SmallVector ConcreteOffsets; + if (Optional V = convertOffsetsFromSvalToUnsigneds(SValOffsets, Extents, + ConcreteOffsets)) + return *V; + + // Handle InitListExpr. + // Example: + // const char arr[4][2] = { { 1, 2 }, { 3 }, 4, 5 }; + if (const auto *ILE = dyn_cast(Init)) + return getSValFromInitListExpr(ILE, ConcreteOffsets, R->getElementType()); + + // Handle StringLiteral. + // Example: + // const char arr[] = "abc"; + if (const auto *SL = dyn_cast(Init)) + return getSValFromStringLiteral(SL, ConcreteOffsets.front(), + R->getElementType()); + + // FIXME: Handle CompoundLiteralExpr. + + return None; +} + +/// Returns an SVal, if possible, for the specified position of an +/// initialization list. +/// +/// \param ILE The given initialization list. +/// \param Offsets The array of unsigned offsets. E.g. for the expression +/// `int x = arr[1][2][3];` an array should be { 1, 2, 3 }. +/// \param ElemT The type of the result SVal expression. +/// \return Optional SVal for the particular position in the initialization +/// list. E.g. for the list `{{1, 2},[3, 4],{5, 6}, {}}` offsets: +/// - {1, 1} returns SVal{4}, because it's the second position in the second +/// sublist; +/// - {3, 0} returns SVal{0}, because there's no explicit value at this +/// position in the sublist. +/// +/// NOTE: Inorder to get a valid SVal, a caller shall guarantee valid offsets +/// for the given initialization list. Otherwise SVal can be an equivalent to 0 +/// or lead to assertion. +Optional RegionStoreManager::getSValFromInitListExpr( + const InitListExpr *ILE, const SmallVector &Offsets, + QualType ElemT) { + assert(ILE && "InitListExpr should not be null"); + + for (uint64_t Offset : Offsets) { + // C++20 [dcl.init.string] 9.4.2.1: + // An array of ordinary character type [...] can be initialized by [...] + // an appropriately-typed string-literal enclosed in braces. + // Example: + // const char arr[] = { "abc" }; + if (ILE->isStringLiteralInit()) + if (const auto *SL = dyn_cast(ILE->getInit(0))) + return getSValFromStringLiteral(SL, Offset, ElemT); + + // C++20 [expr.add] 9.4.17.5 (excerpt): + // i-th array element is value-initialized for each k < i ≤ n, + // where k is an expression-list size and n is an array extent. + if (Offset >= ILE->getNumInits()) + return svalBuilder.makeZeroVal(ElemT); + + const Expr *E = ILE->getInit(Offset); + const auto *IL = dyn_cast(E); + if (!IL) + // Return a constant value, if it is presented. + // FIXME: Support other SVals. + return svalBuilder.getConstantVal(E); + + // Go to the nested initializer list. + ILE = IL; + } + llvm_unreachable( + "Unhandled InitListExpr sub-expressions or invalid offsets."); +} + +/// Returns an SVal, if possible, for the specified position in a string +/// literal. +/// +/// \param SL The given string literal. +/// \param Offset The unsigned offset. E.g. for the expression +/// `char x = str[42];` an offset should be 42. +/// E.g. for the string "abc" offset: +/// - 1 returns SVal{b}, because it's the second position in the string. +/// - 42 returns SVal{0}, because there's no explicit value at this +/// position in the string. +/// \param ElemT The type of the result SVal expression. +/// +/// NOTE: We return `0` for every offset >= the literal length for array +/// declarations, like: +/// const char str[42] = "123"; // Literal length is 4. +/// char c = str[41]; // Offset is 41. +/// FIXME: Nevertheless, we can't do the same for pointer declaraions, like: +/// const char * const str = "123"; // Literal length is 4. +/// char c = str[41]; // Offset is 41. Returns `0`, but Undef +/// // expected. +/// It should be properly handled before reaching this point. +/// The main problem is that we can't distinguish between these declarations, +/// because in case of array we can get the Decl from VarRegion, but in case +/// of pointer the region is a StringRegion, which doesn't contain a Decl. +/// Possible solution could be passing an array extent along with the offset. +SVal RegionStoreManager::getSValFromStringLiteral(const StringLiteral *SL, + uint64_t Offset, + QualType ElemT) { + assert(SL && "StringLiteral should not be null"); + // C++20 [dcl.init.string] 9.4.2.3: + // If there are fewer initializers than there are array elements, each + // element not explicitly initialized shall be zero-initialized [dcl.init]. + uint32_t Code = (Offset >= SL->getLength()) ? 0 : SL->getCodeUnit(Offset); + return svalBuilder.makeIntVal(Code, ElemT); +} + SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B, const ElementRegion* R) { // Check if the region has a binding. @@ -1636,59 +1919,21 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B, // Check if the region is an element region of a string literal. if (const StringRegion *StrR = dyn_cast(superR)) { // FIXME: Handle loads from strings where the literal is treated as - // an integer, e.g., *((unsigned int*)"hello") + // an integer, e.g., *((unsigned int*)"hello"). Such loads are UB according + // to C++20 7.2.1.11 [basic.lval]. QualType T = Ctx.getAsArrayType(StrR->getValueType())->getElementType(); if (!Ctx.hasSameUnqualifiedType(T, R->getElementType())) return UnknownVal(); - - const StringLiteral *Str = StrR->getStringLiteral(); - SVal Idx = R->getIndex(); - if (Optional CI = Idx.getAs()) { - int64_t i = CI->getValue().getSExtValue(); - // Abort on string underrun. This can be possible by arbitrary - // clients of getBindingForElement(). - if (i < 0) + if (const auto CI = R->getIndex().getAs()) { + const llvm::APSInt &Idx = CI->getValue(); + if (Idx < 0) return UndefinedVal(); - int64_t length = Str->getLength(); - // Technically, only i == length is guaranteed to be null. - // However, such overflows should be caught before reaching this point; - // the only time such an access would be made is if a string literal was - // used to initialize a larger array. - char c = (i >= length) ? '\0' : Str->getCodeUnit(i); - return svalBuilder.makeIntVal(c, T); - } - } else if (const VarRegion *VR = dyn_cast(superR)) { - // Check if the containing array has an initialized value that we can trust. - // We can trust a const value or a value of a global initializer in main(). - const VarDecl *VD = VR->getDecl(); - if (VD->getType().isConstQualified() || - R->getElementType().isConstQualified() || - (B.isMainAnalysis() && VD->hasGlobalStorage())) { - if (const Expr *Init = VD->getAnyInitializer()) { - if (const auto *InitList = dyn_cast(Init)) { - // The array index has to be known. - if (auto CI = R->getIndex().getAs()) { - int64_t i = CI->getValue().getSExtValue(); - // If it is known that the index is out of bounds, we can return - // an undefined value. - if (i < 0) - return UndefinedVal(); - - if (auto CAT = Ctx.getAsConstantArrayType(VD->getType())) - if (CAT->getSize().sle(i)) - return UndefinedVal(); - - // If there is a list, but no init, it must be zero. - if (i >= InitList->getNumInits()) - return svalBuilder.makeZeroVal(R->getElementType()); - - if (const Expr *ElemInit = InitList->getInit(i)) - if (Optional V = svalBuilder.getConstantVal(ElemInit)) - return *V; - } - } - } + const StringLiteral *SL = StrR->getStringLiteral(); + return getSValFromStringLiteral(SL, Idx.getZExtValue(), T); } + } else if (isa(superR)) { + if (Optional V = getConstantValFromConstArrayInitializer(B, R)) + return *V; } // Check for loads from a code text region. For such loads, just give up. diff --git a/clang/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp index 7395622a659..04165a443ff 100644 --- a/clang/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SMTConstraintManager.cpp @@ -1,9 +1,8 @@ //== SMTConstraintManager.cpp -----------------------------------*- C++ -*--==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp index b459b5adb51..71bfc86ab8f 100644 --- a/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -49,6 +49,16 @@ using namespace ento; void SValBuilder::anchor() {} +SValBuilder::SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, + ProgramStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), MemMgr(context, alloc), + StateMgr(stateMgr), + AnOpts( + stateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions()), + ArrayIndexTy(context.LongLongTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} + DefinedOrUnknownSVal SValBuilder::makeZeroVal(QualType type) { if (Loc::isLocType(type)) return makeNull(); @@ -244,8 +254,7 @@ SValBuilder::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol, } DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) { - assert(!ND || isa(ND) || isa(ND) || - isa(ND)); + assert(!ND || (isa(ND))); if (const auto *MD = dyn_cast_or_null(ND)) { // Sema treats pointers to static member functions as have function pointer @@ -405,9 +414,7 @@ SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op, // TODO: When the Max Complexity is reached, we should conjure a symbol // instead of generating an Unknown value and propagate the taint info to it. - const unsigned MaxComp = StateMgr.getOwningEngine() - .getAnalysisManager() - .options.MaxSymbolComplexity; + const unsigned MaxComp = AnOpts.MaxSymbolComplexity; if (symLHS && symRHS && (symLHS->computeComplexity() + symRHS->computeComplexity()) < MaxComp) @@ -725,16 +732,12 @@ SVal SValBuilder::evalCastSubKind(loc::MemRegionVal V, QualType CastTy, // This change is needed for architectures with varying // pointer widths. See the amdgcn opencl reproducer with // this change as an example: solver-sym-simplification-ptr-bool.cl - // FIXME: We could encounter a reference here, - // try returning a concrete 'true' since it might - // be easier on the solver. // FIXME: Cleanup remainder of `getZeroWithPtrWidth ()` // and `getIntWithPtrWidth()` functions to prevent future // confusion - const llvm::APSInt &Zero = Ty->isReferenceType() - ? BasicVals.getZeroWithPtrWidth() - : BasicVals.getZeroWithTypeSize(Ty); - return makeNonLoc(Sym, BO_NE, Zero, CastTy); + if (!Ty->isReferenceType()) + return makeNonLoc(Sym, BO_NE, BasicVals.getZeroWithTypeSize(Ty), + CastTy); } // Non-symbolic memory regions are always true. return makeTruthVal(true, CastTy); diff --git a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index e57d92fbceb..681a1f64ead 100644 --- a/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" @@ -25,7 +24,7 @@ class SimpleSValBuilder : public SValBuilder { public: SimpleSValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, ProgramStateManager &stateMgr) - : SValBuilder(alloc, context, stateMgr) {} + : SValBuilder(alloc, context, stateMgr) {} ~SimpleSValBuilder() override {} SVal evalMinus(NonLoc val) override; @@ -129,14 +128,14 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, // a&0 and a&(~0) if (RHS == 0) return makeIntVal(0, resultTy); - else if (RHS.isAllOnesValue()) + else if (RHS.isAllOnes()) isIdempotent = true; break; case BO_Or: // a|0 and a|(~0) if (RHS == 0) isIdempotent = true; - else if (RHS.isAllOnesValue()) { + else if (RHS.isAllOnes()) { const llvm::APSInt &Result = BasicVals.Convert(resultTy, RHS); return nonloc::ConcreteInt(Result); } @@ -320,13 +319,10 @@ static Optional tryRearrange(ProgramStateRef State, // We expect everything to be of the same type - this type. QualType SingleTy; - auto &Opts = - StateMgr.getOwningEngine().getAnalysisManager().getAnalyzerOptions(); - // FIXME: After putting complexity threshold to the symbols we can always // rearrange additive operations but rearrange comparisons only if // option is set. - if(!Opts.ShouldAggressivelySimplifyBinaryOperation) + if (!SVB.getAnalyzerOptions().ShouldAggressivelySimplifyBinaryOperation) return None; SymbolRef LSym = Lhs.getAsSymbol(); @@ -513,7 +509,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, continue; case BO_Shr: // (~0)>>a - if (LHSValue.isAllOnesValue() && LHSValue.isSigned()) + if (LHSValue.isAllOnes() && LHSValue.isSigned()) return evalCast(lhs, resultTy, QualType{}); LLVM_FALLTHROUGH; case BO_Shl: diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index b867b0746f9..3cc0cd224d7 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -84,7 +84,7 @@ Optional StoreManager::castRegion(const MemRegion *R, // involved. Blocks can be casted to/from 'id', as they can be treated // as Objective-C objects. This could possibly be handled by enhancing // our reasoning of downcasts of symbolic objects. - if (isa(R) || isa(R)) + if (isa(R)) return R; // We don't know what to make of it. Return a NULL region, which @@ -96,18 +96,24 @@ Optional StoreManager::castRegion(const MemRegion *R, // already be handled. QualType PointeeTy = CastToTy->getPointeeType(); QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); + CanonPointeeTy = CanonPointeeTy.getLocalUnqualifiedType(); // Handle casts to void*. We just pass the region through. - if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy) + if (CanonPointeeTy == Ctx.VoidTy) return R; - // Handle casts from compatible types. - if (R->isBoundable()) + const auto IsSameRegionType = [&Ctx](const MemRegion *R, QualType OtherTy) { if (const auto *TR = dyn_cast(R)) { QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - if (CanonPointeeTy == ObjTy) - return R; + if (OtherTy == ObjTy.getLocalUnqualifiedType()) + return true; } + return false; + }; + + // Handle casts from compatible types. + if (R->isBoundable() && IsSameRegionType(R, CanonPointeeTy)) + return R; // Process region cast according to the kind of the region being cast. switch (R->getKind()) { @@ -174,16 +180,11 @@ Optional StoreManager::castRegion(const MemRegion *R, CharUnits off = rawOff.getOffset(); if (off.isZero()) { - // Edge case: we are at 0 bytes off the beginning of baseR. We - // check to see if type we are casting to is the same as the base - // region. If so, just return the base region. - if (const auto *TR = dyn_cast(baseR)) { - QualType ObjTy = Ctx.getCanonicalType(TR->getValueType()); - QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy); - if (CanonPointeeTy == ObjTy) - return baseR; - } - + // Edge case: we are at 0 bytes off the beginning of baseR. We check to + // see if the type we are casting to is the same as the type of the base + // region. If so, just return the base region. + if (IsSameRegionType(baseR, CanonPointeeTy)) + return baseR; // Otherwise, create a new ElementRegion at offset 0. return MakeElementRegion(cast(baseR), PointeeTy); } @@ -442,6 +443,19 @@ SVal StoreManager::getLValueIvar(const ObjCIvarDecl *decl, SVal base) { SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, SVal Base) { + + // Special case, if index is 0, return the same type as if + // this was not an array dereference. + if (Offset.isZeroConstant()) { + QualType BT = Base.getType(this->Ctx); + if (!BT.isNull() && !elementType.isNull()) { + QualType PointeeTy = BT->getPointeeType(); + if (!PointeeTy.isNull() && + PointeeTy.getCanonicalType() == elementType.getCanonicalType()) + return Base; + } + } + // If the base is an unknown or undefined value, just return it back. // FIXME: For absolute pointer addresses, we just return that value back as // well, although in reality we should return the offset added to that diff --git a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp index 79a8eef3057..1ae1f97efd2 100644 --- a/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -425,19 +425,7 @@ bool SymbolReaper::isLiveRegion(const MemRegion *MR) { // tell if anything still refers to this region. Unlike SymbolicRegions, // AllocaRegions don't have associated symbols, though, so we don't actually // have a way to track their liveness. - if (isa(MR)) - return true; - - if (isa(MR)) - return true; - - if (isa(MR)) - return true; - - if (isa(MR)) - return true; - - return false; + return isa(MR); } bool SymbolReaper::isLive(SymbolRef sym) { diff --git a/clang/lib/Tooling/CommonOptionsParser.cpp b/clang/lib/Tooling/CommonOptionsParser.cpp index 6301544dbb2..7d48dd50546 100644 --- a/clang/lib/Tooling/CommonOptionsParser.cpp +++ b/clang/lib/Tooling/CommonOptionsParser.cpp @@ -170,7 +170,7 @@ CommonOptionsParser::CommonOptionsParser( llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview); if (Err) { llvm::report_fatal_error( - "CommonOptionsParser: failed to parse command-line arguments. " + + Twine("CommonOptionsParser: failed to parse command-line arguments. ") + llvm::toString(std::move(Err))); } } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp index 4f3e574719d..4b6c87aba62 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -15,9 +15,9 @@ using namespace dependencies; DependencyScanningService::DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager, - bool SkipExcludedPPRanges) + bool SkipExcludedPPRanges, bool OptimizeArgs) : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager), - SkipExcludedPPRanges(SkipExcludedPPRanges) { + SkipExcludedPPRanges(SkipExcludedPPRanges), OptimizeArgs(OptimizeArgs) { // Initialize targets for object file support. llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp index 2fd12f7e12b..739712baadd 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -24,8 +24,6 @@ std::vector FullDependencies::getAdditionalArgs( ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths); for (const std::string &PCMPath : PCMPaths) Ret.push_back("-fmodule-file=" + PCMPath); - for (const std::string &ModMapPath : ModMapPaths) - Ret.push_back("-fmodule-map-file=" + ModMapPath); return Ret; } @@ -37,10 +35,8 @@ FullDependencies::getAdditionalArgsWithoutModulePaths() const { "-fno-implicit-module-maps", }; - for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) { - Args.push_back("-fmodule-file=" + PMD.ModuleName + "=" + PMD.PCMFile); - Args.push_back("-fmodule-map-file=" + PMD.ModuleMapFile); - } + for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps) + Args.push_back("-fmodule-file=" + PMD.PCMFile); return Args; } @@ -50,7 +46,8 @@ DependencyScanningTool::DependencyScanningTool( : Worker(Service) {} llvm::Expected DependencyScanningTool::getDependencyFile( - const tooling::CompilationDatabase &Compilations, StringRef CWD) { + const std::vector &CommandLine, StringRef CWD, + llvm::Optional ModuleName) { /// Prints out all of the gathered dependencies into a string. class MakeDependencyPrinterConsumer : public DependencyConsumer { public: @@ -102,17 +99,9 @@ llvm::Expected DependencyScanningTool::getDependencyFile( std::vector Dependencies; }; - // We expect a single command here because if a source file occurs multiple - // times in the original CDB, then `computeDependencies` would run the - // `DependencyScanningAction` once for every time the input occured in the - // CDB. Instead we split up the CDB into single command chunks to avoid this - // behavior. - assert(Compilations.getAllCompileCommands().size() == 1 && - "Expected a compilation database with a single command!"); - std::string Input = Compilations.getAllCompileCommands().front().Filename; - MakeDependencyPrinterConsumer Consumer; - auto Result = Worker.computeDependencies(Input, CWD, Compilations, Consumer); + auto Result = + Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); if (Result) return std::move(Result); std::string Output; @@ -122,8 +111,9 @@ llvm::Expected DependencyScanningTool::getDependencyFile( llvm::Expected DependencyScanningTool::getFullDependencies( - const tooling::CompilationDatabase &Compilations, StringRef CWD, - const llvm::StringSet<> &AlreadySeen) { + const std::vector &CommandLine, StringRef CWD, + const llvm::StringSet<> &AlreadySeen, + llvm::Optional ModuleName) { class FullDependencyPrinterConsumer : public DependencyConsumer { public: FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen) @@ -180,24 +170,15 @@ DependencyScanningTool::getFullDependencies( private: std::vector Dependencies; std::vector PrebuiltModuleDeps; - std::unordered_map ClangModuleDeps; + std::map ClangModuleDeps; std::string ContextHash; std::vector OutputPaths; const llvm::StringSet<> &AlreadySeen; }; - // We expect a single command here because if a source file occurs multiple - // times in the original CDB, then `computeDependencies` would run the - // `DependencyScanningAction` once for every time the input occured in the - // CDB. Instead we split up the CDB into single command chunks to avoid this - // behavior. - assert(Compilations.getAllCompileCommands().size() == 1 && - "Expected a compilation database with a single command!"); - std::string Input = Compilations.getAllCompileCommands().front().Filename; - FullDependencyPrinterConsumer Consumer(AlreadySeen); llvm::Error Result = - Worker.computeDependencies(Input, CWD, Compilations, Consumer); + Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); if (Result) return std::move(Result); return Consumer.getFullDependencies(); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index d651ff23b38..7fdc4927179 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -133,6 +133,16 @@ deduceDepTarget(const std::string &OutputFile, return makeObjFileName(InputFiles.front().getFile()); } +/// Sanitize diagnostic options for dependency scan. +static void sanitizeDiagOpts(DiagnosticOptions &DiagOpts) { + // Don't print 'X warnings and Y errors generated'. + DiagOpts.ShowCarets = false; + // Don't write out diagnostic file. + DiagOpts.DiagnosticSerializationFile.clear(); + // Don't treat warnings as errors. + DiagOpts.Warnings.push_back("no-error"); +} + /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. class DependencyScanningAction : public tooling::ToolAction { @@ -141,10 +151,11 @@ public: StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr DepFS, ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, - ScanningOutputFormat Format) + ScanningOutputFormat Format, bool OptimizeArgs, + llvm::Optional ModuleName = None) : WorkingDirectory(WorkingDirectory), Consumer(Consumer), - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), - Format(Format) {} + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), Format(Format), + OptimizeArgs(OptimizeArgs), ModuleName(ModuleName) {} bool runInvocation(std::shared_ptr Invocation, FileManager *FileMgr, @@ -154,39 +165,34 @@ public: CompilerInvocation OriginalInvocation(*Invocation); // Create a compiler instance to handle the actual work. - CompilerInstance Compiler(std::move(PCHContainerOps)); - Compiler.setInvocation(std::move(Invocation)); + CompilerInstance ScanInstance(std::move(PCHContainerOps)); + ScanInstance.setInvocation(std::move(Invocation)); - // Don't print 'X warnings and Y errors generated'. - Compiler.getDiagnosticOpts().ShowCarets = false; - // Don't write out diagnostic file. - Compiler.getDiagnosticOpts().DiagnosticSerializationFile.clear(); - // Don't treat warnings as errors. - Compiler.getDiagnosticOpts().Warnings.push_back("no-error"); // Create the compiler's actual diagnostics engine. - Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); - if (!Compiler.hasDiagnostics()) + sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); + ScanInstance.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); + if (!ScanInstance.hasDiagnostics()) return false; - Compiler.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = true; + ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = + true; FileMgr->getFileSystemOpts().WorkingDir = std::string(WorkingDirectory); - Compiler.setFileManager(FileMgr); - Compiler.createSourceManager(*FileMgr); + ScanInstance.setFileManager(FileMgr); + ScanInstance.createSourceManager(*FileMgr); llvm::StringSet<> PrebuiltModulesInputFiles; // Store the list of prebuilt module files into header search options. This // will prevent the implicit build to create duplicate modules and will // force reuse of the existing prebuilt module files instead. - if (!Compiler.getPreprocessorOpts().ImplicitPCHInclude.empty()) + if (!ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) visitPrebuiltModule( - Compiler.getPreprocessorOpts().ImplicitPCHInclude, Compiler, - Compiler.getHeaderSearchOpts().PrebuiltModuleFiles, + ScanInstance.getPreprocessorOpts().ImplicitPCHInclude, ScanInstance, + ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles, PrebuiltModulesInputFiles, /*VisitInputFiles=*/DepFS != nullptr); // Use the dependency scanning optimized file system if requested to do so. if (DepFS) { - const CompilerInvocation &CI = Compiler.getInvocation(); DepFS->clearIgnoredFiles(); // Ignore any files that contributed to prebuilt modules. The implicit // build validates the modules by comparing the reported sizes of their @@ -197,20 +203,20 @@ public: // Add any filenames that were explicity passed in the build settings and // that might be opened, as we want to ensure we don't run source // minimization on them. - for (const auto &Entry : CI.getHeaderSearchOpts().UserEntries) - DepFS->ignoreFile(Entry.Path); - for (const auto &Entry : CI.getHeaderSearchOpts().VFSOverlayFiles) - DepFS->ignoreFile(Entry); + for (const auto &E : ScanInstance.getHeaderSearchOpts().UserEntries) + DepFS->ignoreFile(E.Path); + for (const auto &F : ScanInstance.getHeaderSearchOpts().VFSOverlayFiles) + DepFS->ignoreFile(F); // Support for virtual file system overlays on top of the caching // filesystem. FileMgr->setVirtualFileSystem(createVFSFromCompilerInvocation( - CI, Compiler.getDiagnostics(), DepFS)); + ScanInstance.getInvocation(), ScanInstance.getDiagnostics(), DepFS)); // Pass the skip mappings which should speed up excluded conditional block // skipping in the preprocessor. if (PPSkipMappings) - Compiler.getPreprocessorOpts() + ScanInstance.getPreprocessorOpts() .ExcludedConditionalDirectiveSkipMappings = PPSkipMappings; } @@ -222,35 +228,43 @@ public: // which ensures that the compiler won't create new dependency collectors, // and thus won't write out the extra '.d' files to disk. auto Opts = std::make_unique(); - std::swap(*Opts, Compiler.getInvocation().getDependencyOutputOpts()); + std::swap(*Opts, ScanInstance.getInvocation().getDependencyOutputOpts()); // We need at least one -MT equivalent for the generator of make dependency // files to work. if (Opts->Targets.empty()) - Opts->Targets = {deduceDepTarget(Compiler.getFrontendOpts().OutputFile, - Compiler.getFrontendOpts().Inputs)}; + Opts->Targets = { + deduceDepTarget(ScanInstance.getFrontendOpts().OutputFile, + ScanInstance.getFrontendOpts().Inputs)}; Opts->IncludeSystemHeaders = true; switch (Format) { case ScanningOutputFormat::Make: - Compiler.addDependencyCollector( + ScanInstance.addDependencyCollector( std::make_shared(std::move(Opts), Consumer)); break; case ScanningOutputFormat::Full: - Compiler.addDependencyCollector(std::make_shared( - std::move(Opts), Compiler, Consumer, std::move(OriginalInvocation))); + ScanInstance.addDependencyCollector(std::make_shared( + std::move(Opts), ScanInstance, Consumer, + std::move(OriginalInvocation), OptimizeArgs)); break; } // Consider different header search and diagnostic options to create // different modules. This avoids the unsound aliasing of module PCMs. // - // TODO: Implement diagnostic bucketing and header search pruning to reduce - // the impact of strict context hashing. - Compiler.getHeaderSearchOpts().ModulesStrictContextHash = true; + // TODO: Implement diagnostic bucketing to reduce the impact of strict + // context hashing. + ScanInstance.getHeaderSearchOpts().ModulesStrictContextHash = true; - auto Action = std::make_unique(); - const bool Result = Compiler.ExecuteAction(*Action); + std::unique_ptr Action; + + if (ModuleName.hasValue()) + Action = std::make_unique(*ModuleName); + else + Action = std::make_unique(); + + const bool Result = ScanInstance.ExecuteAction(*Action); if (!DepFS) FileMgr->clearStatCache(); return Result; @@ -262,15 +276,15 @@ private: llvm::IntrusiveRefCntPtr DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; ScanningOutputFormat Format; + bool OptimizeArgs; + llvm::Optional ModuleName; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( DependencyScanningService &Service) - : Format(Service.getFormat()) { - DiagOpts = new DiagnosticOptions(); - + : Format(Service.getFormat()), OptimizeArgs(Service.canOptimizeArgs()) { PCHContainerOps = std::make_shared(); PCHContainerOps->registerReader( std::make_unique()); @@ -279,7 +293,12 @@ DependencyScanningWorker::DependencyScanningWorker( PCHContainerOps->registerWriter( std::make_unique()); - RealFS = llvm::vfs::createPhysicalFileSystem(); + auto OverlayFS = llvm::makeIntrusiveRefCnt( + llvm::vfs::createPhysicalFileSystem()); + InMemoryFS = llvm::makeIntrusiveRefCnt(); + OverlayFS->pushOverlay(InMemoryFS); + RealFS = OverlayFS; + if (Service.canSkipExcludedPPRanges()) PPSkipMappings = std::make_unique(); @@ -290,36 +309,64 @@ DependencyScanningWorker::DependencyScanningWorker( Files = new FileManager(FileSystemOptions(), RealFS); } -static llvm::Error runWithDiags( - DiagnosticOptions *DiagOpts, - llvm::function_ref BodyShouldSucceed) { +static llvm::Error +runWithDiags(DiagnosticOptions *DiagOpts, + llvm::function_ref + BodyShouldSucceed) { + sanitizeDiagOpts(*DiagOpts); + // Capture the emitted diagnostics and report them to the client // in the case of a failure. std::string DiagnosticOutput; llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts); - if (BodyShouldSucceed(DiagPrinter)) + if (BodyShouldSucceed(DiagPrinter, *DiagOpts)) return llvm::Error::success(); return llvm::make_error(DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); } llvm::Error DependencyScanningWorker::computeDependencies( - const std::string &Input, StringRef WorkingDirectory, - const CompilationDatabase &CDB, DependencyConsumer &Consumer) { + StringRef WorkingDirectory, const std::vector &CommandLine, + DependencyConsumer &Consumer, llvm::Optional ModuleName) { + // Reset what might have been modified in the previous worker invocation. RealFS->setCurrentWorkingDirectory(WorkingDirectory); - return runWithDiags(DiagOpts.get(), [&](DiagnosticConsumer &DC) { - /// Create the tool that uses the underlying file system to ensure that any - /// file system requests that are made by the driver do not go through the - /// dependency scanning filesystem. - tooling::ClangTool Tool(CDB, Input, PCHContainerOps, RealFS, Files); - Tool.clearArgumentsAdjusters(); - Tool.setRestoreWorkingDir(false); - Tool.setPrintErrorMessage(false); - Tool.setDiagnosticConsumer(&DC); - DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - PPSkipMappings.get(), Format); - return !Tool.run(&Action); - }); + if (Files) + Files->setVirtualFileSystem(RealFS); + + llvm::IntrusiveRefCntPtr CurrentFiles = + Files ? Files : new FileManager(FileSystemOptions(), RealFS); + + Optional> ModifiedCommandLine; + if (ModuleName.hasValue()) { + ModifiedCommandLine = CommandLine; + InMemoryFS->addFile(*ModuleName, 0, llvm::MemoryBuffer::getMemBuffer("")); + ModifiedCommandLine->emplace_back(*ModuleName); + } + + const std::vector &FinalCommandLine = + ModifiedCommandLine ? *ModifiedCommandLine : CommandLine; + + std::vector FinalCCommandLine(CommandLine.size(), nullptr); + llvm::transform(CommandLine, FinalCCommandLine.begin(), + [](const std::string &Str) { return Str.c_str(); }); + + return runWithDiags(CreateAndPopulateDiagOpts(FinalCCommandLine).release(), + [&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) { + DependencyScanningAction Action( + WorkingDirectory, Consumer, DepFS, + PPSkipMappings.get(), Format, OptimizeArgs, + ModuleName); + // Create an invocation that uses the underlying file + // system to ensure that any file system requests that + // are made by the driver do not go through the + // dependency scanning filesystem. + ToolInvocation Invocation(FinalCommandLine, &Action, + CurrentFiles.get(), + PCHContainerOps); + Invocation.setDiagnosticConsumer(&DC); + Invocation.setDiagnosticOptions(&DiagOpts); + return Invocation.run(); + }); } diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 88cee63c98a..383a850301a 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -1,9 +1,8 @@ //===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -18,11 +17,26 @@ using namespace clang; using namespace tooling; using namespace dependencies; +static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts, + ASTReader &Reader, + const serialization::ModuleFile &MF) { + // Only preserve search paths that were used during the dependency scan. + std::vector Entries = Opts.UserEntries; + Opts.UserEntries.clear(); + for (unsigned I = 0; I < Entries.size(); ++I) + if (MF.SearchPathUsage[I]) + Opts.UserEntries.push_back(Entries[I]); +} + CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( - const ModuleDeps &Deps) const { + const ModuleDeps &Deps, + llvm::function_ref Optimize) const { // Make a deep copy of the original Clang invocation. CompilerInvocation CI(OriginalInvocation); + CI.getLangOpts()->resetNonModularOptions(); + CI.getPreprocessorOpts().resetNonModularOptions(); + // Remove options incompatible with explicit module build. CI.getFrontendOpts().Inputs.clear(); CI.getFrontendOpts().OutputFile.clear(); @@ -34,12 +48,18 @@ CompilerInvocation ModuleDepCollector::makeInvocationForModuleBuildWithoutPaths( CI.getLangOpts()->ImplicitModules = false; // Report the prebuilt modules this module uses. - for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) { + for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); - CI.getFrontendOpts().ModuleMapFiles.push_back(PrebuiltModule.ModuleMapFile); - } - CI.getPreprocessorOpts().ImplicitPCHInclude.clear(); + Optimize(CI); + + // The original invocation probably didn't have strict context hash enabled. + // We will use the context hash of this invocation to distinguish between + // multiple incompatible versions of the same module and will use it when + // reporting dependencies to the clients. Let's make sure we're using + // **strict** context hash in order to prevent accidental sharing of + // incompatible modules (e.g. with differences in search paths). + CI.getHeaderSearchOpts().ModulesStrictContextHash = true; return CI; } @@ -62,7 +82,7 @@ serializeCompilerInvocation(const CompilerInvocation &CI) { std::vector ModuleDeps::getCanonicalCommandLine( std::function LookupPCMPath, std::function LookupModuleDeps) const { - CompilerInvocation CI(Invocation); + CompilerInvocation CI(BuildInvocation); FrontendOptions &FrontendOpts = CI.getFrontendOpts(); InputKind ModuleMapInputKind(FrontendOpts.DashX.getLanguage(), @@ -79,7 +99,7 @@ std::vector ModuleDeps::getCanonicalCommandLine( std::vector ModuleDeps::getCanonicalCommandLineWithoutModulePaths() const { - return serializeCompilerInvocation(Invocation); + return serializeCompilerInvocation(BuildInvocation); } void dependencies::detail::collectPCMAndModuleMapPaths( @@ -112,15 +132,15 @@ void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, FileID PrevFID) { if (Reason != PPCallbacks::EnterFile) return; - + // This has to be delayed as the context hash can change at the start of // `CompilerInstance::ExecuteAction`. if (MDC.ContextHash.empty()) { - MDC.ContextHash = Instance.getInvocation().getModuleHash(); + MDC.ContextHash = MDC.ScanInstance.getInvocation().getModuleHash(); MDC.Consumer.handleContextHash(MDC.ContextHash); } - SourceManager &SM = Instance.getSourceManager(); + SourceManager &SM = MDC.ScanInstance.getSourceManager(); // Dependency generation really does want to go all the way to the // file entry for a source location to find out what is depended on. @@ -163,12 +183,14 @@ void ModuleDepCollectorPP::handleImport(const Module *Imported) { } void ModuleDepCollectorPP::EndOfMainFile() { - FileID MainFileID = Instance.getSourceManager().getMainFileID(); - MDC.MainFile = std::string( - Instance.getSourceManager().getFileEntryForID(MainFileID)->getName()); + FileID MainFileID = MDC.ScanInstance.getSourceManager().getMainFileID(); + MDC.MainFile = std::string(MDC.ScanInstance.getSourceManager() + .getFileEntryForID(MainFileID) + ->getName()); - if (!Instance.getPreprocessorOpts().ImplicitPCHInclude.empty()) - MDC.FileDeps.push_back(Instance.getPreprocessorOpts().ImplicitPCHInclude); + if (!MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude.empty()) + MDC.FileDeps.push_back( + MDC.ScanInstance.getPreprocessorOpts().ImplicitPCHInclude); for (const Module *M : DirectModularDeps) { // A top-level module might not be actually imported as a module when @@ -207,15 +229,16 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { MD.ImplicitModulePCMPath = std::string(M->getASTFile()->getName()); MD.IsSystem = M->IsSystem; - const FileEntry *ModuleMap = Instance.getPreprocessor() + const FileEntry *ModuleMap = MDC.ScanInstance.getPreprocessor() .getHeaderSearchInfo() .getModuleMap() .getModuleMapFileForUniquing(M); MD.ClangModuleMapFile = std::string(ModuleMap ? ModuleMap->getName() : ""); serialization::ModuleFile *MF = - MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); - MDC.Instance.getASTReader()->visitInputFiles( + MDC.ScanInstance.getASTReader()->getModuleManager().lookup( + M->getASTFile()); + MDC.ScanInstance.getASTReader()->visitInputFiles( *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { // __inferred_module.map is the result of the way in which an implicit // module build handles inferred modules. It adds an overlay VFS with @@ -232,10 +255,16 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { // Add direct prebuilt module dependencies now, so that we can use them when // creating a CompilerInvocation and computing context hash for this // ModuleDeps instance. - addDirectPrebuiltModuleDeps(M, MD); + llvm::DenseSet SeenModules; + addAllSubmodulePrebuiltDeps(M, MD, SeenModules); - MD.Invocation = MDC.makeInvocationForModuleBuildWithoutPaths(MD); - MD.ID.ContextHash = MD.Invocation.getModuleHash(); + MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutPaths( + MD, [&](CompilerInvocation &BuildInvocation) { + if (MDC.OptimizeArgs) + optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), + *MDC.ScanInstance.getASTReader(), *MF); + }); + MD.ID.ContextHash = MD.BuildInvocation.getModuleHash(); llvm::DenseSet AddedModules; addAllSubmoduleDeps(M, MD, AddedModules); @@ -243,12 +272,23 @@ ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { return MD.ID; } -void ModuleDepCollectorPP::addDirectPrebuiltModuleDeps(const Module *M, - ModuleDeps &MD) { +void ModuleDepCollectorPP::addAllSubmodulePrebuiltDeps( + const Module *M, ModuleDeps &MD, + llvm::DenseSet &SeenSubmodules) { + addModulePrebuiltDeps(M, MD, SeenSubmodules); + + for (const Module *SubM : M->submodules()) + addAllSubmodulePrebuiltDeps(SubM, MD, SeenSubmodules); +} + +void ModuleDepCollectorPP::addModulePrebuiltDeps( + const Module *M, ModuleDeps &MD, + llvm::DenseSet &SeenSubmodules) { for (const Module *Import : M->Imports) if (Import->getTopLevelModule() != M->getTopLevelModule()) - if (MDC.isPrebuiltModule(Import)) - MD.PrebuiltModuleDeps.emplace_back(Import); + if (MDC.isPrebuiltModule(Import->getTopLevelModule())) + if (SeenSubmodules.insert(Import->getTopLevelModule()).second) + MD.PrebuiltModuleDeps.emplace_back(Import->getTopLevelModule()); } void ModuleDepCollectorPP::addAllSubmoduleDeps( @@ -274,13 +314,14 @@ void ModuleDepCollectorPP::addModuleDep( } ModuleDepCollector::ModuleDepCollector( - std::unique_ptr Opts, CompilerInstance &I, - DependencyConsumer &C, CompilerInvocation &&OriginalCI) - : Instance(I), Consumer(C), Opts(std::move(Opts)), - OriginalInvocation(std::move(OriginalCI)) {} + std::unique_ptr Opts, + CompilerInstance &ScanInstance, DependencyConsumer &C, + CompilerInvocation &&OriginalCI, bool OptimizeArgs) + : ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)), + OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs) {} void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { - PP.addPPCallbacks(std::make_unique(Instance, *this)); + PP.addPPCallbacks(std::make_unique(*this)); } void ModuleDepCollector::attachToASTReader(ASTReader &R) {} @@ -288,7 +329,7 @@ void ModuleDepCollector::attachToASTReader(ASTReader &R) {} bool ModuleDepCollector::isPrebuiltModule(const Module *M) { std::string Name(M->getTopLevelModuleName()); const auto &PrebuiltModuleFiles = - Instance.getHeaderSearchOpts().PrebuiltModuleFiles; + ScanInstance.getHeaderSearchOpts().PrebuiltModuleFiles; auto PrebuiltModuleFileIt = PrebuiltModuleFiles.find(Name); if (PrebuiltModuleFileIt == PrebuiltModuleFiles.end()) return false; diff --git a/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp b/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp index 8091a467d05..9c825428f2e 100644 --- a/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp +++ b/clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp @@ -91,12 +91,8 @@ int main(int argc, const char **argv) { llvm::transform(Args, Argv.begin(), [](const std::string &Arg) { return Arg.c_str(); }); - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - unsigned MissingArgIndex, MissingArgCount; - auto Opts = driver::getDriverOptTable(); - auto ParsedArgs = Opts.ParseArgs(llvm::makeArrayRef(Argv).slice(1), - MissingArgIndex, MissingArgCount); - ParseDiagnosticArgs(*DiagOpts, ParsedArgs); + IntrusiveRefCntPtr DiagOpts = + CreateAndPopulateDiagOpts(Argv); // Don't output diagnostics, because common scenarios such as // cross-compiling fail with diagnostics. This is not fatal, but diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index 97ba7e411fb..5e18d7a576c 100644 --- a/clang/lib/Tooling/JSONCompilationDatabase.cpp +++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp @@ -135,15 +135,12 @@ class CommandLineArgumentParser { std::vector unescapeCommandLine(JSONCommandLineSyntax Syntax, StringRef EscapedCommandLine) { if (Syntax == JSONCommandLineSyntax::AutoDetect) { +#ifdef _WIN32 + // Assume Windows command line parsing on Win32 + Syntax = JSONCommandLineSyntax::Windows; +#else Syntax = JSONCommandLineSyntax::Gnu; - llvm::Triple Triple(llvm::sys::getProcessTriple()); - if (Triple.getOS() == llvm::Triple::OSType::Win32) { - // Assume Windows command line parsing on Win32 unless the triple - // explicitly tells us otherwise. - if (!Triple.hasEnvironment() || - Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC) - Syntax = JSONCommandLineSyntax::Windows; - } +#endif } if (Syntax == JSONCommandLineSyntax::Windows) { diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 07888b5c32f..fcac2250dd9 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -155,9 +155,8 @@ private: } // namespace static CallExpr::arg_range dropDefaultArgs(CallExpr::arg_range Args) { - auto FirstDefaultArg = std::find_if(Args.begin(), Args.end(), [](auto It) { - return isa(It); - }); + auto FirstDefaultArg = + llvm::find_if(Args, [](auto It) { return isa(It); }); return llvm::make_range(Args.begin(), FirstDefaultArg); } diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 5242134097d..6314615f83c 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -343,23 +343,27 @@ bool ToolInvocation::run() { for (const std::string &Str : CommandLine) Argv.push_back(Str.c_str()); const char *const BinaryName = Argv[0]; - IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); - unsigned MissingArgIndex, MissingArgCount; - llvm::opt::InputArgList ParsedArgs = driver::getDriverOptTable().ParseArgs( - ArrayRef(Argv).slice(1), MissingArgIndex, MissingArgCount); - ParseDiagnosticArgs(*DiagOpts, ParsedArgs); - TextDiagnosticPrinter DiagnosticPrinter( - llvm::errs(), &*DiagOpts); - DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs()), &*DiagOpts, - DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); + + // Parse diagnostic options from the driver command-line only if none were + // explicitly set. + IntrusiveRefCntPtr ParsedDiagOpts; + DiagnosticOptions *DiagOpts = this->DiagOpts; + if (!DiagOpts) { + ParsedDiagOpts = CreateAndPopulateDiagOpts(Argv); + DiagOpts = &*ParsedDiagOpts; + } + + TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), DiagOpts); + IntrusiveRefCntPtr Diagnostics = + CompilerInstance::createDiagnostics( + &*DiagOpts, DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); // Although `Diagnostics` are used only for command-line parsing, the custom // `DiagConsumer` might expect a `SourceManager` to be present. - SourceManager SrcMgr(Diagnostics, *Files); - Diagnostics.setSourceManager(&SrcMgr); + SourceManager SrcMgr(*Diagnostics, *Files); + Diagnostics->setSourceManager(&SrcMgr); const std::unique_ptr Driver( - newDriver(&Diagnostics, BinaryName, &Files->getVirtualFileSystem())); + newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem())); // The "input file not found" diagnostics from the driver are useful. // The driver is only aware of the VFS working directory, but some clients // change this at the FileManager level instead. @@ -371,11 +375,11 @@ bool ToolInvocation::run() { if (!Compilation) return false; const llvm::opt::ArgStringList *const CC1Args = getCC1Arguments( - &Diagnostics, Compilation.get()); + &*Diagnostics, Compilation.get()); if (!CC1Args) return false; std::unique_ptr Invocation( - newInvocation(&Diagnostics, *CC1Args, BinaryName)); + newInvocation(&*Diagnostics, *CC1Args, BinaryName)); return runInvocation(BinaryName, Compilation.get(), std::move(Invocation), std::move(PCHContainerOps)); } diff --git a/clang/lib/Tooling/Transformer/Parsing.cpp b/clang/lib/Tooling/Transformer/Parsing.cpp index 66fa04a1559..242db2a16b4 100644 --- a/clang/lib/Tooling/Transformer/Parsing.cpp +++ b/clang/lib/Tooling/Transformer/Parsing.cpp @@ -165,7 +165,7 @@ static ExpectedProgress parseChar(char c, ParseState State) { static ExpectedProgress parseId(ParseState State) { State.Input = consumeWhitespace(State.Input); auto Id = State.Input.take_while( - [](char c) { return isASCII(c) && isIdentifierBody(c); }); + [](char c) { return isASCII(c) && isAsciiIdentifierContinue(c); }); if (Id.empty()) return makeParseError(State, "failed to parse name"); return makeParseProgress(advance(State, Id.size()), Id.str()); diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp index 4dc3544bb06..8b20ef34c3f 100644 --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -27,14 +27,15 @@ using namespace clang; using namespace transformer; +using ast_matchers::BoundNodes; using ast_matchers::MatchFinder; using llvm::errc; using llvm::Error; using llvm::Expected; using llvm::StringError; -static llvm::Expected -getNode(const ast_matchers::BoundNodes &Nodes, StringRef Id) { +static llvm::Expected getNode(const BoundNodes &Nodes, + StringRef Id) { auto &NodesMap = Nodes.getMap(); auto It = NodesMap.find(Id); if (It == NodesMap.end()) @@ -366,6 +367,73 @@ public: } }; +class SelectBoundStencil : public clang::transformer::StencilInterface { + static bool containsNoNullStencils( + const std::vector> &Cases) { + for (const auto &S : Cases) + if (S.second == nullptr) + return false; + return true; + } + +public: + SelectBoundStencil(std::vector> Cases, + Stencil Default) + : CaseStencils(std::move(Cases)), DefaultStencil(std::move(Default)) { + assert(containsNoNullStencils(CaseStencils) && + "cases of selectBound may not be null"); + } + ~SelectBoundStencil() override{}; + + llvm::Error eval(const MatchFinder::MatchResult &match, + std::string *result) const override { + const BoundNodes::IDToNodeMap &NodeMap = match.Nodes.getMap(); + for (const auto &S : CaseStencils) { + if (NodeMap.count(S.first) > 0) { + return S.second->eval(match, result); + } + } + + if (DefaultStencil != nullptr) { + return DefaultStencil->eval(match, result); + } + + llvm::SmallVector CaseIDs; + CaseIDs.reserve(CaseStencils.size()); + for (const auto &S : CaseStencils) + CaseIDs.emplace_back(S.first); + + return llvm::createStringError( + errc::result_out_of_range, + llvm::Twine("selectBound failed: no cases bound and no default: {") + + llvm::join(CaseIDs, ", ") + "}"); + } + + std::string toString() const override { + std::string Buffer; + llvm::raw_string_ostream Stream(Buffer); + Stream << "selectBound({"; + bool First = true; + for (const auto &S : CaseStencils) { + if (First) + First = false; + else + Stream << "}, "; + Stream << "{\"" << S.first << "\", " << S.second->toString(); + } + Stream << "}}"; + if (DefaultStencil != nullptr) { + Stream << ", " << DefaultStencil->toString(); + } + Stream << ")"; + return Stream.str(); + } + +private: + std::vector> CaseStencils; + Stencil DefaultStencil; +}; + class SequenceStencil : public StencilInterface { std::vector Stencils; @@ -462,6 +530,13 @@ Stencil transformer::ifBound(StringRef Id, Stencil TrueStencil, std::move(FalseStencil)); } +Stencil transformer::selectBound( + std::vector> CaseStencils, + Stencil DefaultStencil) { + return std::make_shared(std::move(CaseStencils), + std::move(DefaultStencil)); +} + Stencil transformer::run(MatchConsumer Fn) { return std::make_shared(std::move(Fn)); } diff --git a/clang/tools/clang-format/ClangFormat.cpp b/clang/tools/clang-format/ClangFormat.cpp index 144e87f78c6..56dc628869a 100644 --- a/clang/tools/clang-format/ClangFormat.cpp +++ b/clang/tools/clang-format/ClangFormat.cpp @@ -19,10 +19,12 @@ #include "clang/Basic/Version.h" #include "clang/Format/Format.h" #include "clang/Rewrite/Core/Rewriter.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Process.h" +#include using namespace llvm; using clang::tooling::Replacements; @@ -104,6 +106,17 @@ static cl::opt SortIncludes( "SortIncludes style flag"), cl::cat(ClangFormatCategory)); +static cl::opt QualifierAlignment( + "qualifier-alignment", + cl::desc( + "If set, overrides the qualifier alignment style determined by the " + "QualifierAlignment style flag"), + cl::init(""), cl::cat(ClangFormatCategory)); + +static cl::opt + Files("files", cl::desc("Provide a list of files to run clang-format"), + cl::init(""), cl::cat(ClangFormatCategory)); + static cl::opt Verbose("verbose", cl::desc("If set, shows the list of processed files"), cl::cat(ClangFormatCategory)); @@ -353,6 +366,18 @@ static void outputXML(const Replacements &Replaces, outs() << "\n"; } +class ClangFormatDiagConsumer : public DiagnosticConsumer { + virtual void anchor() {} + + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) override { + + SmallVector vec; + Info.FormatDiagnostic(vec); + errs() << "clang-format error:" << vec << "\n"; + } +}; + // Returns true on error. static bool format(StringRef FileName) { if (!OutputXML && Inplace && FileName == "-") { @@ -402,6 +427,27 @@ static bool format(StringRef FileName) { return true; } + StringRef QualifierAlignmentOrder = QualifierAlignment; + + FormatStyle->QualifierAlignment = + StringSwitch( + QualifierAlignmentOrder.lower()) + .Case("right", FormatStyle::QAS_Right) + .Case("left", FormatStyle::QAS_Left) + .Default(FormatStyle->QualifierAlignment); + + if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Left) + FormatStyle->QualifierOrder = {"const", "volatile", "type"}; + else if (FormatStyle->QualifierAlignment == FormatStyle::QAS_Right) + FormatStyle->QualifierOrder = {"type", "const", "volatile"}; + else if (QualifierAlignmentOrder.contains("type")) { + FormatStyle->QualifierAlignment = FormatStyle::QAS_Custom; + SmallVector Qualifiers; + QualifierAlignmentOrder.split(Qualifiers, " ", /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + FormatStyle->QualifierOrder = {Qualifiers.begin(), Qualifiers.end()}; + } + if (SortIncludes.getNumOccurrences() != 0) { if (SortIncludes) FormatStyle->SortIncludes = FormatStyle::SI_CaseSensitive; @@ -443,9 +489,12 @@ static bool format(StringRef FileName) { IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); FileManager Files(FileSystemOptions(), InMemoryFileSystem); + + IntrusiveRefCntPtr DiagOpts(new DiagnosticOptions()); + ClangFormatDiagConsumer IgnoreDiagnostics; DiagnosticsEngine Diagnostics( - IntrusiveRefCntPtr(new DiagnosticIDs), - new DiagnosticOptions); + IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, + &IgnoreDiagnostics, false); SourceManager Sources(Diagnostics, Files); FileID ID = createInMemoryFile(AssumedFileName, *Code, Sources, Files, InMemoryFileSystem.get()); @@ -534,6 +583,17 @@ int main(int argc, const char **argv) { return dumpConfig(); } + if (!Files.empty()) { + std::ifstream ExternalFileOfFiles{std::string(Files)}; + std::string Line; + unsigned LineNo = 1; + while (std::getline(ExternalFileOfFiles, Line)) { + FileNames.push_back(Line); + LineNo++; + } + errs() << "Clang-formating " << LineNo << " files\n"; + } + bool Error = false; if (FileNames.empty()) { Error = clang::format::format("-"); @@ -545,9 +605,12 @@ int main(int argc, const char **argv) { "single file.\n"; return 1; } + + unsigned FileNo = 1; for (const auto &FileName : FileNames) { if (Verbose) - errs() << "Formatting " << FileName << "\n"; + errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] " + << FileName << "\n"; Error |= clang::format::format(FileName); } return Error ? 1 : 0; diff --git a/clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp new file mode 100644 index 00000000000..bc5b9a9f1fd --- /dev/null +++ b/clang/tools/clang-nvlink-wrapper/ClangNvlinkWrapper.cpp @@ -0,0 +1,196 @@ +//===-- clang-nvlink-wrapper/ClangNvlinkWrapper.cpp - wrapper over nvlink-===// +// +// 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 tool works as a wrapper over nvlink program. It transparently passes +/// every input option and objects to nvlink except archive files. It reads +/// each input archive file to extract archived cubin files as temporary files. +/// These temp (*.cubin) files are passed to nvlink, because nvlink does not +/// support linking of archive files implicitly. +/// +/// During linking of heterogeneous device archive libraries, the +/// clang-offload-bundler creates a device specific archive of cubin files. +/// Such an archive is then passed to this tool to extract cubin files before +/// passing to nvlink. +/// +/// Example: +/// clang-nvlink-wrapper -o a.out-openmp-nvptx64 /tmp/libTest-nvptx-sm_50.a +/// +/// 1. Extract (libTest-nvptx-sm_50.a) => /tmp/a.cubin /tmp/b.cubin +/// 2. nvlink -o a.out-openmp-nvptx64 /tmp/a.cubin /tmp/b.cubin +//===---------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt Help("h", cl::desc("Alias for -help"), cl::Hidden); + +// Mark all our options with this category, everything else (except for -help) +// will be hidden. +static cl::OptionCategory + ClangNvlinkWrapperCategory("clang-nvlink-wrapper options"); + +static cl::opt NvlinkUserPath("nvlink-path", + cl::desc("Path of nvlink binary"), + cl::cat(ClangNvlinkWrapperCategory)); + +// Do not parse nvlink options +static cl::list + NVArgs(cl::Sink, cl::desc("...")); + +static Error runNVLink(std::string NVLinkPath, + SmallVectorImpl &Args) { + std::vector NVLArgs; + NVLArgs.push_back(NVLinkPath); + for (auto &Arg : Args) { + NVLArgs.push_back(Arg); + } + + if (sys::ExecuteAndWait(NVLinkPath.c_str(), NVLArgs)) + return createStringError(inconvertibleErrorCode(), "'nvlink' failed"); + return Error::success(); +} + +static Error extractArchiveFiles(StringRef Filename, + SmallVectorImpl &Args, + SmallVectorImpl &TmpFiles) { + std::vector> ArchiveBuffers; + + ErrorOr> BufOrErr = + MemoryBuffer::getFileOrSTDIN(Filename, false, false); + if (std::error_code EC = BufOrErr.getError()) + return createFileError(Filename, EC); + + ArchiveBuffers.push_back(std::move(*BufOrErr)); + Expected> LibOrErr = + object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); + if (!LibOrErr) + return LibOrErr.takeError(); + + auto Archive = std::move(*LibOrErr); + + Error Err = Error::success(); + auto ChildEnd = Archive->child_end(); + for (auto ChildIter = Archive->child_begin(Err); ChildIter != ChildEnd; + ++ChildIter) { + if (Err) + return Err; + auto ChildNameOrErr = (*ChildIter).getName(); + if (!ChildNameOrErr) + return ChildNameOrErr.takeError(); + + StringRef ChildName = sys::path::filename(ChildNameOrErr.get()); + + auto ChildBufferRefOrErr = (*ChildIter).getMemoryBufferRef(); + if (!ChildBufferRefOrErr) + return ChildBufferRefOrErr.takeError(); + + auto ChildBuffer = + MemoryBuffer::getMemBuffer(ChildBufferRefOrErr.get(), false); + auto ChildNameSplit = ChildName.split('.'); + + SmallString<16> Path; + int FileDesc; + if (std::error_code EC = sys::fs::createTemporaryFile( + (ChildNameSplit.first), (ChildNameSplit.second), FileDesc, Path)) + return createFileError(ChildName, EC); + + std::string TmpFileName(Path.str()); + Args.push_back(TmpFileName); + TmpFiles.push_back(TmpFileName); + std::error_code EC; + raw_fd_ostream OS(Path.c_str(), EC, sys::fs::OF_None); + if (EC) + return createFileError(TmpFileName, errc::io_error); + OS << ChildBuffer->getBuffer(); + OS.close(); + } + return Err; +} + +static Error cleanupTmpFiles(SmallVectorImpl &TmpFiles) { + for (auto &TmpFile : TmpFiles) { + if (std::error_code EC = sys::fs::remove(TmpFile)) + return createFileError(TmpFile, errc::no_such_file_or_directory); + } + return Error::success(); +} + +static void PrintVersion(raw_ostream &OS) { + OS << clang::getClangToolFullVersion("clang-nvlink-wrapper") << '\n'; +} + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + cl::SetVersionPrinter(PrintVersion); + cl::HideUnrelatedOptions(ClangNvlinkWrapperCategory); + cl::ParseCommandLineOptions( + argc, argv, + "A wrapper tool over nvlink program. It transparently passes every \n" + "input option and objects to nvlink except archive files and path of \n" + "nvlink binary. It reads each input archive file to extract archived \n" + "cubin files as temporary files.\n"); + + if (Help) { + cl::PrintHelpMessage(); + return 0; + } + + auto reportError = [argv](Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + exit(1); + }; + + std::string NvlinkPath; + SmallVector Argv(argv, argv + argc); + SmallVector ArgvSubst; + SmallVector TmpFiles; + BumpPtrAllocator Alloc; + StringSaver Saver(Alloc); + cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); + + for (const std::string &Arg : NVArgs) { + if (sys::path::extension(Arg) == ".a") { + if (Error Err = extractArchiveFiles(Arg, ArgvSubst, TmpFiles)) + reportError(std::move(Err)); + } else { + ArgvSubst.push_back(Arg); + } + } + + NvlinkPath = NvlinkUserPath; + + // If user hasn't specified nvlink binary then search it in PATH + if (NvlinkPath.empty()) { + ErrorOr NvlinkPathErr = sys::findProgramByName("nvlink"); + if (!NvlinkPathErr) { + reportError(createStringError(NvlinkPathErr.getError(), + "unable to find 'nvlink' in path")); + } + NvlinkPath = NvlinkPathErr.get(); + } + + if (Error Err = runNVLink(NvlinkPath, ArgvSubst)) + reportError(std::move(Err)); + if (Error Err = cleanupTmpFiles(TmpFiles)) + reportError(std::move(Err)); + + return 0; +} diff --git a/clang/tools/clang-repl/ClangRepl.cpp b/clang/tools/clang-repl/ClangRepl.cpp index ba6bb11abc8..4240b9d425d 100644 --- a/clang/tools/clang-repl/ClangRepl.cpp +++ b/clang/tools/clang-repl/ClangRepl.cpp @@ -32,7 +32,7 @@ static llvm::cl::list OptInputs(llvm::cl::Positional, llvm::cl::ZeroOrMore, llvm::cl::desc("[code to run]")); -static void LLVMErrorHandler(void *UserData, const std::string &Message, +static void LLVMErrorHandler(void *UserData, const char *Message, bool GenCrashDiag) { auto &Diags = *static_cast(UserData); @@ -80,6 +80,9 @@ int main(int argc, const char **argv) { llvm::install_fatal_error_handler(LLVMErrorHandler, static_cast(&CI->getDiagnostics())); + // Load any requested plugins. + CI->LoadRequestedPlugins(); + auto Interp = ExitOnErr(clang::Interpreter::create(std::move(CI))); for (const std::string &input : OptInputs) { if (auto Err = Interp->ParseAndExecute(input)) diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 396d6ff529f..fd3b25ccb3c 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Config/llvm-config.h" #include "llvm/LinkAllPasses.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -38,7 +39,6 @@ #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/Support/Timer.h" @@ -57,7 +57,7 @@ using namespace llvm::opt; // Main driver //===----------------------------------------------------------------------===// -static void LLVMErrorHandler(void *UserData, const std::string &Message, +static void LLVMErrorHandler(void *UserData, const char *Message, bool GenCrashDiag) { DiagnosticsEngine &Diags = *static_cast(UserData); diff --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp index 086ce0ea778..db3288d7528 100644 --- a/clang/tools/driver/cc1as_main.cpp +++ b/clang/tools/driver/cc1as_main.cpp @@ -36,6 +36,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetOptions.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/OptTable.h" @@ -49,7 +50,6 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" @@ -490,7 +490,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts, T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI, Opts.RelaxAll, Opts.IncrementalLinkerCompatible, /*DWARFMustBeAtTheEnd*/ true)); - Str.get()->InitSections(Opts.NoExecStack); + Str.get()->initSections(Opts.NoExecStack, *STI); } // When -fembed-bitcode is passed to clang_as, a 1-byte marker @@ -550,7 +550,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, return Failed; } -static void LLVMErrorHandler(void *UserData, const std::string &Message, +static void LLVMErrorHandler(void *UserData, const char *Message, bool GenCrashDiag) { DiagnosticsEngine &Diags = *static_cast(UserData); diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp index 5a453429e79..c9129ee9e50 100644 --- a/clang/tools/driver/driver.cpp +++ b/clang/tools/driver/driver.cpp @@ -278,27 +278,6 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, DiagClient->setPrefix(std::string(ExeBasename)); } -// This lets us create the DiagnosticsEngine with a properly-filled-out -// DiagnosticOptions instance. -static DiagnosticOptions * -CreateAndPopulateDiagOpts(ArrayRef argv, bool &UseNewCC1Process) { - auto *DiagOpts = new DiagnosticOptions; - unsigned MissingArgIndex, MissingArgCount; - InputArgList Args = getDriverOptTable().ParseArgs( - argv.slice(1), MissingArgIndex, MissingArgCount); - // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. - // Any errors that would be diagnosed here will also be diagnosed later, - // when the DiagnosticsEngine actually exists. - (void)ParseDiagnosticArgs(*DiagOpts, Args); - - UseNewCC1Process = - Args.hasFlag(clang::driver::options::OPT_fno_integrated_cc1, - clang::driver::options::OPT_fintegrated_cc1, - /*Default=*/CLANG_SPAWN_CC1); - - return DiagOpts; -} - static void SetInstallDir(SmallVectorImpl &argv, Driver &TheDriver, bool CanonicalPrefixes) { // Attempt to find the original path used to invoke the driver, to determine @@ -398,8 +377,8 @@ int main(int Argc, const char **Argv) { // Handle -cc1 integrated tools, even if -cc1 was expanded from a response // file. - auto FirstArg = std::find_if(Args.begin() + 1, Args.end(), - [](const char *A) { return A != nullptr; }); + auto FirstArg = llvm::find_if(llvm::drop_begin(Args), + [](const char *A) { return A != nullptr; }); if (FirstArg != Args.end() && StringRef(*FirstArg).startswith("-cc1")) { // If -cc1 came from a response file, remove the EOL sentinels. if (MarkEOLs) { @@ -416,10 +395,10 @@ int main(int Argc, const char **Argv) { // Skip end-of-line response file markers if (Args[i] == nullptr) continue; - if (StringRef(Args[i]) == "-no-canonical-prefixes") { + if (StringRef(Args[i]) == "-canonical-prefixes") + CanonicalPrefixes = true; + else if (StringRef(Args[i]) == "-no-canonical-prefixes") CanonicalPrefixes = false; - break; - } } // Handle CL and _CL_ which permits additional command line options to be @@ -459,10 +438,15 @@ int main(int Argc, const char **Argv) { // should spawn a new clang subprocess (old behavior). // Not having an additional process saves some execution time of Windows, // and makes debugging and profiling easier. - bool UseNewCC1Process; + bool UseNewCC1Process = CLANG_SPAWN_CC1; + for (const char *Arg : Args) + UseNewCC1Process = llvm::StringSwitch(Arg) + .Case("-fno-integrated-cc1", true) + .Case("-fintegrated-cc1", false) + .Default(UseNewCC1Process); IntrusiveRefCntPtr DiagOpts = - CreateAndPopulateDiagOpts(Args, UseNewCC1Process); + CreateAndPopulateDiagOpts(Args); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); diff --git a/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp b/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp index caced02e1e1..c3735f70136 100644 --- a/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp +++ b/clang/utils/TableGen/ClangASTPropertiesEmitter.cpp @@ -455,7 +455,7 @@ void ASTPropsEmitter::emitPropertiedReaderWriterBody(HasProperties node, // Emit code to read all the properties. visitAllProperties(node, nodeInfo, [&](Property prop) { // Verify that the creation code refers to this property. - if (info.IsReader && creationCode.find(prop.getName()) == StringRef::npos) + if (info.IsReader && !creationCode.contains(prop.getName())) PrintFatalError(nodeInfo.Creator.getLoc(), "creation code for " + node.getName() + " doesn't refer to property \"" diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index d679d58aaef..fe05a3466af 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -2043,7 +2044,7 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { OS << " return None;\n"; OS << "}\n\n"; - std::map> + llvm::MapVector> SubMatchRules; for (const auto &Rule : Rules) { if (!Rule.isSubRule()) @@ -2676,9 +2677,9 @@ static void emitAttrList(raw_ostream &OS, StringRef Class, // Determines if an attribute has a Pragma spelling. static bool AttrHasPragmaSpelling(const Record *R) { std::vector Spellings = GetFlattenedSpellings(*R); - return llvm::find_if(Spellings, [](const FlattenedSpelling &S) { - return S.variety() == "Pragma"; - }) != Spellings.end(); + return llvm::any_of(Spellings, [](const FlattenedSpelling &S) { + return S.variety() == "Pragma"; + }); } namespace { @@ -3803,14 +3804,8 @@ static void GenerateLangOptRequirements(const Record &R, if (LangOpts.empty()) return; - OS << "bool diagLangOpts(Sema &S, const ParsedAttr &Attr) "; - OS << "const override {\n"; - OS << " auto &LangOpts = S.LangOpts;\n"; - OS << " if (" << GenerateTestExpression(LangOpts) << ")\n"; - OS << " return true;\n\n"; - OS << " S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) "; - OS << "<< Attr;\n"; - OS << " return false;\n"; + OS << "bool acceptsLangOpts(const LangOptions &LangOpts) const override {\n"; + OS << " return " << GenerateTestExpression(LangOpts) << ";\n"; OS << "}\n\n"; } @@ -3965,6 +3960,27 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { } OS << "};\n"; } + + std::vector ArgNames; + for (const auto &Arg : Attr.getValueAsListOfDefs("Args")) { + bool UnusedUnset; + if (Arg->getValueAsBitOrUnset("Fake", UnusedUnset)) + continue; + ArgNames.push_back(Arg->getValueAsString("Name").str()); + for (const auto &Class : Arg->getSuperClasses()) { + if (Class.first->getName().startswith("Variadic")) { + ArgNames.back().append("..."); + break; + } + } + } + if (!ArgNames.empty()) { + OS << "static constexpr const char *" << I->first << "ArgNames[] = {\n"; + for (const auto &N : ArgNames) + OS << '"' << N << "\","; + OS << "};\n"; + } + OS << "struct ParsedAttrInfo" << I->first << " final : public ParsedAttrInfo {\n"; OS << " ParsedAttrInfo" << I->first << "() {\n"; @@ -3986,6 +4002,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { OS << PragmaAttributeSupport.isAttributedSupported(*I->second) << ";\n"; if (!Spellings.empty()) OS << " Spellings = " << I->first << "Spellings;\n"; + if (!ArgNames.empty()) + OS << " ArgNames = " << I->first << "ArgNames;\n"; OS << " }\n"; GenerateAppertainsTo(Attr, OS); GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS); @@ -4210,6 +4228,24 @@ void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records, getPragmaAttributeSupport(Records).generateParsingHelpers(OS); } +void EmitClangAttrDocTable(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Clang attribute documentation", OS); + + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); + for (const auto *A : Attrs) { + if (!A->getValueAsBit("ASTNode")) + continue; + std::vector Docs = A->getValueAsListOfDefs("Documentation"); + assert(!Docs.empty()); + // Only look at the first documentation if there are several. + // (Currently there's only one such attr, revisit if this becomes common). + StringRef Text = + Docs.front()->getValueAsOptionalString("Content").getValueOr(""); + OS << "\nstatic const char AttrDoc_" << A->getName() << "[] = " + << "R\"reST(" << Text.trim() << ")reST\";\n"; + } +} + enum class SpellingKind { GNU, CXX11, @@ -4397,7 +4433,13 @@ void EmitClangAttrDocs(RecordKeeper &Records, raw_ostream &OS) { // Gather the Documentation lists from each of the attributes, based on the // category provided. std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - std::map> SplitDocs; + struct CategoryLess { + bool operator()(const Record *L, const Record *R) const { + return L->getValueAsString("Name") < R->getValueAsString("Name"); + } + }; + std::map, CategoryLess> + SplitDocs; for (const auto *A : Attrs) { const Record &Attr = *A; std::vector Docs = Attr.getValueAsListOfDefs("Documentation"); diff --git a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp index eb2f23191c5..a988a5631ac 100644 --- a/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp +++ b/clang/utils/TableGen/ClangCommentCommandInfoEmitter.cpp @@ -83,6 +83,12 @@ static std::string MangleName(StringRef Str) { default: Mangled += Str[i]; break; + case '(': + Mangled += "lparen"; + break; + case ')': + Mangled += "rparen"; + break; case '[': Mangled += "lsquare"; break; diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index 014c1adcd80..547ec2c82cb 100644 --- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -129,6 +129,7 @@ namespace { }; struct GroupInfo { + llvm::StringRef GroupName; std::vector DiagsInGroup; std::vector SubGroups; unsigned IDNo; @@ -174,6 +175,7 @@ static void groupDiagnostics(const std::vector &Diags, Record *Group = DiagGroups[i]; GroupInfo &GI = DiagsInGroup[std::string(Group->getValueAsString("GroupName"))]; + GI.GroupName = Group->getName(); GI.Defs.push_back(Group); std::vector SubGroups = Group->getValueAsListOfDefs("SubGroups"); @@ -614,7 +616,7 @@ struct DiagnosticTextBuilder { return It->second.Root; } - LLVM_ATTRIBUTE_NORETURN void PrintFatalError(llvm::Twine const &Msg) const { + [[noreturn]] void PrintFatalError(llvm::Twine const &Msg) const { assert(EvaluatingRecord && "not evaluating a record?"); llvm::PrintFatalError(EvaluatingRecord->getLoc(), Msg); } @@ -1279,8 +1281,8 @@ void clang::EmitClangDiagsDefs(RecordKeeper &Records, raw_ostream &OS, OS << ", \""; OS.write_escaped(DiagTextBuilder.buildForDefinition(&R)) << '"'; - // Warning associated with the diagnostic. This is stored as an index into - // the alphabetically sorted warning table. + // Warning group associated with the diagnostic. This is stored as an index + // into the alphabetically sorted warning group table. if (DefInit *DI = dyn_cast(R.getValueInit("Group"))) { std::map::iterator I = DiagsInGroup.find( std::string(DI->getDef()->getValueAsString("GroupName"))); @@ -1487,18 +1489,20 @@ static void emitDiagTable(std::map &DiagsInGroup, for (auto const &I: DiagsInGroup) MaxLen = std::max(MaxLen, (unsigned)I.first.size()); - OS << "\n#ifdef GET_DIAG_TABLE\n"; + OS << "\n#ifdef DIAG_ENTRY\n"; unsigned SubGroupIndex = 1, DiagArrayIndex = 1; for (auto const &I: DiagsInGroup) { // Group option string. - OS << " { /* "; + OS << "DIAG_ENTRY("; + OS << I.second.GroupName << " /* "; + if (I.first.find_first_not_of("abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789!@#$%^*-+=:?") != std::string::npos) PrintFatalError("Invalid character in diagnostic group '" + I.first + "'"); - OS << I.first << " */ " << std::string(MaxLen - I.first.size(), ' '); + OS << I.first << " */, "; // Store a pascal-style length byte at the beginning of the string. std::string Name = char(I.first.size()) + I.first; OS << GroupNames.GetOrAddStringOffset(Name, false) << ", "; @@ -1517,7 +1521,7 @@ static void emitDiagTable(std::map &DiagsInGroup, DiagArrayIndex += DiagsInPedantic.size(); DiagArrayIndex += V.size() + 1; } else { - OS << "/* Empty */ 0, "; + OS << "0, "; } // Subgroups. @@ -1530,12 +1534,12 @@ static void emitDiagTable(std::map &DiagsInGroup, SubGroupIndex += GroupsInPedantic.size(); SubGroupIndex += SubGroups.size() + 1; } else { - OS << "/* Empty */ 0"; + OS << "0"; } - OS << " },\n"; + OS << ")\n"; } - OS << "#endif // GET_DIAG_TABLE\n\n"; + OS << "#endif // DIAG_ENTRY\n\n"; } /// Emit the table of diagnostic categories. diff --git a/clang/utils/TableGen/ClangOpcodesEmitter.cpp b/clang/utils/TableGen/ClangOpcodesEmitter.cpp index ffeedcdf0ee..8081096633d 100644 --- a/clang/utils/TableGen/ClangOpcodesEmitter.cpp +++ b/clang/utils/TableGen/ClangOpcodesEmitter.cpp @@ -124,7 +124,7 @@ void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) { for (size_t I = 0, N = Args.size(); I < N; ++I) { OS << " auto V" << I; OS << " = "; - OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n"; + OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n"; } // Emit a call to the template method and pass arguments. @@ -161,8 +161,10 @@ void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) { OS << " PrintName(\"" << ID << "\");\n"; OS << " OS << \"\\t\""; - for (auto *Arg : R->getValueAsListOfDefs("Args")) - OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \""; + for (auto *Arg : R->getValueAsListOfDefs("Args")) { + OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)"; + OS << " << \" \""; + } OS << " << \"\\n\";\n"; OS << " continue;\n"; diff --git a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp index a4cb5b7cacd..4795b008dda 100644 --- a/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp +++ b/clang/utils/TableGen/ClangOpenCLBuiltinEmitter.cpp @@ -233,19 +233,18 @@ private: MapVector SignatureListMap; }; -// OpenCL builtin test generator. This class processes the same TableGen input -// as BuiltinNameEmitter, but generates a .cl file that contains a call to each -// builtin function described in the .td input. -class OpenCLBuiltinTestEmitter { +/// Base class for emitting a file (e.g. header or test) from OpenCLBuiltins.td +class OpenCLBuiltinFileEmitterBase { public: - OpenCLBuiltinTestEmitter(RecordKeeper &Records, raw_ostream &OS) + OpenCLBuiltinFileEmitterBase(RecordKeeper &Records, raw_ostream &OS) : Records(Records), OS(OS) {} + virtual ~OpenCLBuiltinFileEmitterBase() = default; // Entrypoint to generate the functions for testing all OpenCL builtin // functions. - void emit(); + virtual void emit() = 0; -private: +protected: struct TypeFlags { TypeFlags() : IsConst(false), IsVolatile(false), IsPointer(false) {} bool IsConst : 1; @@ -282,6 +281,18 @@ private: expandTypesInSignature(const std::vector &Signature, SmallVectorImpl> &Types); + // Emit extension enabling pragmas. + void emitExtensionSetup(); + + // Emit an #if guard for a Builtin's extension. Return the corresponding + // closing #endif, or an empty string if no extension #if guard was emitted. + std::string emitExtensionGuard(const Record *Builtin); + + // Emit an #if guard for a Builtin's language version. Return the + // corresponding closing #endif, or an empty string if no version #if guard + // was emitted. + std::string emitVersionGuard(const Record *Builtin); + // Contains OpenCL builtin functions and related information, stored as // Record instances. They are coming from the associated TableGen file. RecordKeeper &Records; @@ -290,6 +301,19 @@ private: raw_ostream &OS; }; +// OpenCL builtin test generator. This class processes the same TableGen input +// as BuiltinNameEmitter, but generates a .cl file that contains a call to each +// builtin function described in the .td input. +class OpenCLBuiltinTestEmitter : public OpenCLBuiltinFileEmitterBase { +public: + OpenCLBuiltinTestEmitter(RecordKeeper &Records, raw_ostream &OS) + : OpenCLBuiltinFileEmitterBase(Records, OS) {} + + // Entrypoint to generate the functions for testing all OpenCL builtin + // functions. + void emit() override; +}; + } // namespace void BuiltinNameEmitter::Emit() { @@ -472,10 +496,10 @@ void BuiltinNameEmitter::GetOverloads() { auto Signature = B->getValueAsListOfDefs("Signature"); // Reuse signatures to avoid unnecessary duplicates. auto it = - std::find_if(SignaturesList.begin(), SignaturesList.end(), - [&](const std::pair, unsigned> &a) { - return a.first == Signature; - }); + llvm::find_if(SignaturesList, + [&](const std::pair, unsigned> &a) { + return a.first == Signature; + }); unsigned SignIndex; if (it == SignaturesList.end()) { VerifySignature(Signature, B); @@ -923,9 +947,9 @@ static void OCL2Qual(Sema &S, const OpenCLTypeStruct &Ty, OS << "\n} // OCL2Qual\n"; } -std::string OpenCLBuiltinTestEmitter::getTypeString(const Record *Type, - TypeFlags Flags, - int VectorSize) const { +std::string OpenCLBuiltinFileEmitterBase::getTypeString(const Record *Type, + TypeFlags Flags, + int VectorSize) const { std::string S; if (Type->getValueAsBit("IsConst") || Flags.IsConst) { S += "const "; @@ -970,7 +994,7 @@ std::string OpenCLBuiltinTestEmitter::getTypeString(const Record *Type, return S; } -void OpenCLBuiltinTestEmitter::getTypeLists( +void OpenCLBuiltinFileEmitterBase::getTypeLists( Record *Type, TypeFlags &Flags, std::vector &TypeList, std::vector &VectorList) const { bool isGenType = Type->isSubClassOf("GenericType"); @@ -1003,7 +1027,7 @@ void OpenCLBuiltinTestEmitter::getTypeLists( VectorList.push_back(Type->getValueAsInt("VecWidth")); } -void OpenCLBuiltinTestEmitter::expandTypesInSignature( +void OpenCLBuiltinFileEmitterBase::expandTypesInSignature( const std::vector &Signature, SmallVectorImpl> &Types) { // Find out if there are any GenTypes in this signature, and if so, calculate @@ -1044,10 +1068,7 @@ void OpenCLBuiltinTestEmitter::expandTypesInSignature( } } -void OpenCLBuiltinTestEmitter::emit() { - emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS); - - // Enable some extensions for testing. +void OpenCLBuiltinFileEmitterBase::emitExtensionSetup() { OS << R"( #pragma OPENCL EXTENSION cl_khr_fp16 : enable #pragma OPENCL EXTENSION cl_khr_fp64 : enable @@ -1058,6 +1079,60 @@ void OpenCLBuiltinTestEmitter::emit() { #pragma OPENCL EXTENSION cl_khr_3d_image_writes : enable )"; +} + +std::string +OpenCLBuiltinFileEmitterBase::emitExtensionGuard(const Record *Builtin) { + StringRef Extensions = + Builtin->getValueAsDef("Extension")->getValueAsString("ExtName"); + if (Extensions.empty()) + return ""; + + OS << "#if"; + + SmallVector ExtVec; + Extensions.split(ExtVec, " "); + bool isFirst = true; + for (StringRef Ext : ExtVec) { + if (!isFirst) { + OS << " &&"; + } + OS << " defined(" << Ext << ")"; + isFirst = false; + } + OS << "\n"; + + return "#endif // Extension\n"; +} + +std::string +OpenCLBuiltinFileEmitterBase::emitVersionGuard(const Record *Builtin) { + std::string OptionalEndif; + auto PrintOpenCLVersion = [this](int Version) { + OS << "CL_VERSION_" << (Version / 100) << "_" << ((Version % 100) / 10); + }; + int MinVersion = Builtin->getValueAsDef("MinVersion")->getValueAsInt("ID"); + if (MinVersion != 100) { + // OpenCL 1.0 is the default minimum version. + OS << "#if __OPENCL_C_VERSION__ >= "; + PrintOpenCLVersion(MinVersion); + OS << "\n"; + OptionalEndif = "#endif // MinVersion\n" + OptionalEndif; + } + int MaxVersion = Builtin->getValueAsDef("MaxVersion")->getValueAsInt("ID"); + if (MaxVersion) { + OS << "#if __OPENCL_C_VERSION__ < "; + PrintOpenCLVersion(MaxVersion); + OS << "\n"; + OptionalEndif = "#endif // MaxVersion\n" + OptionalEndif; + } + return OptionalEndif; +} + +void OpenCLBuiltinTestEmitter::emit() { + emitSourceFileHeader("OpenCL Builtin exhaustive testing", OS); + + emitExtensionSetup(); // Ensure each test has a unique name by numbering them. unsigned TestID = 0; @@ -1071,43 +1146,10 @@ void OpenCLBuiltinTestEmitter::emit() { expandTypesInSignature(B->getValueAsListOfDefs("Signature"), FTypes); OS << "// Test " << Name << "\n"; - std::string OptionalEndif; - StringRef Extensions = - B->getValueAsDef("Extension")->getValueAsString("ExtName"); - if (!Extensions.empty()) { - OS << "#if"; - OptionalEndif = "#endif // Extension\n"; - SmallVector ExtVec; - Extensions.split(ExtVec, " "); - bool isFirst = true; - for (StringRef Ext : ExtVec) { - if (!isFirst) { - OS << " &&"; - } - OS << " defined(" << Ext << ")"; - isFirst = false; - } - OS << "\n"; - } - auto PrintOpenCLVersion = [this](int Version) { - OS << "CL_VERSION_" << (Version / 100) << "_" << ((Version % 100) / 10); - }; - int MinVersion = B->getValueAsDef("MinVersion")->getValueAsInt("ID"); - if (MinVersion != 100) { - // OpenCL 1.0 is the default minimum version. - OS << "#if __OPENCL_C_VERSION__ >= "; - PrintOpenCLVersion(MinVersion); - OS << "\n"; - OptionalEndif = "#endif // MinVersion\n" + OptionalEndif; - } - int MaxVersion = B->getValueAsDef("MaxVersion")->getValueAsInt("ID"); - if (MaxVersion) { - OS << "#if __OPENCL_C_VERSION__ < "; - PrintOpenCLVersion(MaxVersion); - OS << "\n"; - OptionalEndif = "#endif // MaxVersion\n" + OptionalEndif; - } + std::string OptionalExtensionEndif = emitExtensionGuard(B); + std::string OptionalVersionEndif = emitVersionGuard(B); + for (const auto &Signature : FTypes) { // Emit function declaration. OS << Signature[0] << " test" << TestID++ << "_" << Name << "("; @@ -1136,7 +1178,9 @@ void OpenCLBuiltinTestEmitter::emit() { // End of function body. OS << "}\n"; } - OS << OptionalEndif << "\n"; + + OS << OptionalVersionEndif; + OS << OptionalExtensionEndif; } } diff --git a/clang/utils/TableGen/MveEmitter.cpp b/clang/utils/TableGen/MveEmitter.cpp index 091af2dc52a..f5b6f4f0168 100644 --- a/clang/utils/TableGen/MveEmitter.cpp +++ b/clang/utils/TableGen/MveEmitter.cpp @@ -1941,8 +1941,8 @@ void MveEmitter::EmitHeader(raw_ostream &OS) { void MveEmitter::EmitBuiltinDef(raw_ostream &OS) { for (const auto &kv : ACLEIntrinsics) { const ACLEIntrinsic &Int = *kv.second; - OS << "TARGET_HEADER_BUILTIN(__builtin_arm_mve_" << Int.fullName() - << ", \"\", \"n\", \"arm_mve.h\", ALL_LANGUAGES, \"\")\n"; + OS << "BUILTIN(__builtin_arm_mve_" << Int.fullName() + << ", \"\", \"n\")\n"; } std::set ShortNamesSeen; @@ -2151,8 +2151,8 @@ void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) { if (kv.second->headerOnly()) continue; const ACLEIntrinsic &Int = *kv.second; - OS << "TARGET_HEADER_BUILTIN(__builtin_arm_cde_" << Int.fullName() - << ", \"\", \"ncU\", \"arm_cde.h\", ALL_LANGUAGES, \"\")\n"; + OS << "BUILTIN(__builtin_arm_cde_" << Int.fullName() + << ", \"\", \"ncU\")\n"; } } diff --git a/clang/utils/TableGen/NeonEmitter.cpp b/clang/utils/TableGen/NeonEmitter.cpp index f0da1a7d2f4..ff552b66c0e 100644 --- a/clang/utils/TableGen/NeonEmitter.cpp +++ b/clang/utils/TableGen/NeonEmitter.cpp @@ -382,7 +382,7 @@ public: StringRef Mods = getNextModifiers(Proto, Pos); while (!Mods.empty()) { Types.emplace_back(InTS, Mods); - if (Mods.find('!') != StringRef::npos) + if (Mods.contains('!')) PolymorphicKeyType = Types.size() - 1; Mods = getNextModifiers(Proto, Pos); @@ -417,8 +417,7 @@ public: /// Return true if the intrinsic takes an immediate operand. bool hasImmediate() const { - return std::any_of(Types.begin(), Types.end(), - [](const Type &T) { return T.isImmediate(); }); + return llvm::any_of(Types, [](const Type &T) { return T.isImmediate(); }); } /// Return the parameter index of the immediate operand. @@ -1271,9 +1270,8 @@ void Intrinsic::emitShadowedArgs() { } bool Intrinsic::protoHasScalar() const { - return std::any_of(Types.begin(), Types.end(), [](const Type &T) { - return T.isScalar() && !T.isImmediate(); - }); + return llvm::any_of( + Types, [](const Type &T) { return T.isScalar() && !T.isImmediate(); }); } void Intrinsic::emitBodyAsBuiltinCall() { @@ -1916,10 +1914,9 @@ Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef Types, continue; unsigned ArgNum = 0; - bool MatchingArgumentTypes = - std::all_of(Types.begin(), Types.end(), [&](const auto &Type) { - return Type == I.getParamType(ArgNum++); - }); + bool MatchingArgumentTypes = llvm::all_of(Types, [&](const auto &Type) { + return Type == I.getParamType(ArgNum++); + }); if (MatchingArgumentTypes) GoodVec.push_back(&I); diff --git a/clang/utils/TableGen/RISCVVEmitter.cpp b/clang/utils/TableGen/RISCVVEmitter.cpp index 24f2250c9ae..62eef830318 100644 --- a/clang/utils/TableGen/RISCVVEmitter.cpp +++ b/clang/utils/TableGen/RISCVVEmitter.cpp @@ -80,7 +80,7 @@ public: // passing to the BUILTIN() macro in Builtins.def. const std::string &getBuiltinStr() const { return BuiltinStr; } - // Return the clang buitlin type for RVV vector type which are used in the + // Return the clang builtin type for RVV vector type which are used in the // riscv_vector.h header file. const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; } @@ -140,8 +140,7 @@ enum RISCVExtension : uint8_t { F = 1 << 1, D = 1 << 2, Zfh = 1 << 3, - Zvamo = 1 << 4, - Zvlsseg = 1 << 5, + Zvlsseg = 1 << 4, }; // TODO refactor RVVIntrinsic class design after support all intrinsic @@ -150,13 +149,13 @@ enum RISCVExtension : uint8_t { class RVVIntrinsic { private: - std::string Name; // Builtin name + std::string BuiltinName; // Builtin name + std::string Name; // C intrinsic name. std::string MangledName; std::string IRName; - bool HasSideEffects; bool IsMask; - bool HasMaskedOffOperand; bool HasVL; + bool HasPolicy; bool HasNoMaskedOverloaded; bool HasAutoDef; // There is automiatic definition in header std::string ManualCodegen; @@ -170,19 +169,19 @@ private: public: RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName, - StringRef MangledSuffix, StringRef IRName, bool HasSideEffects, - bool IsMask, bool HasMaskedOffOperand, bool HasVL, + StringRef MangledSuffix, StringRef IRName, bool IsMask, + bool HasMaskedOffOperand, bool HasVL, bool HasPolicy, bool HasNoMaskedOverloaded, bool HasAutoDef, StringRef ManualCodegen, const RVVTypes &Types, const std::vector &IntrinsicTypes, StringRef RequiredExtension, unsigned NF); ~RVVIntrinsic() = default; + StringRef getBuiltinName() const { return BuiltinName; } StringRef getName() const { return Name; } StringRef getMangledName() const { return MangledName; } - bool hasSideEffects() const { return HasSideEffects; } - bool hasMaskedOffOperand() const { return HasMaskedOffOperand; } bool hasVL() const { return HasVL; } + bool hasPolicy() const { return HasPolicy; } bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; } bool hasManualCodegen() const { return !ManualCodegen.empty(); } bool hasAutoDef() const { return HasAutoDef; } @@ -191,6 +190,9 @@ public: StringRef getManualCodegen() const { return ManualCodegen; } uint8_t getRISCVExtensions() const { return RISCVExtensions; } unsigned getNF() const { return NF; } + const std::vector &getIntrinsicTypes() const { + return IntrinsicTypes; + } // Return the type string for a BUILTIN() macro in Builtins.def. std::string getBuiltinTypeStr() const; @@ -200,7 +202,7 @@ public: void emitCodeGenSwitchBody(raw_ostream &o) const; // Emit the macros for mapping C/C++ intrinsic function to builtin functions. - void emitIntrinsicMacro(raw_ostream &o) const; + void emitIntrinsicFuncDef(raw_ostream &o) const; // Emit the mangled function definition. void emitMangledFuncDef(raw_ostream &o) const; @@ -231,6 +233,8 @@ public: private: /// Create all intrinsics and add them to \p Out void createRVVIntrinsics(std::vector> &Out); + /// Create Headers and add them to \p Out + void createRVVHeaders(raw_ostream &OS); /// Compute output and input types by applying different config (basic type /// and LMUL with type transformers). It also record result of type in legal /// or illegal set to avoid compute the same config again. The result maybe @@ -652,7 +656,7 @@ void RVVType::applyModifier(StringRef Transformer) { assert(Idx != StringRef::npos); StringRef ComplexType = Transformer.slice(1, Idx); Transformer = Transformer.drop_front(Idx + 1); - assert(Transformer.find('(') == StringRef::npos && + assert(!Transformer.contains('(') && "Only allow one complex type transformer"); auto UpdateAndCheckComplexProto = [&]() { @@ -755,19 +759,19 @@ void RVVType::applyModifier(StringRef Transformer) { //===----------------------------------------------------------------------===// RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, StringRef NewMangledName, StringRef MangledSuffix, - StringRef IRName, bool HasSideEffects, bool IsMask, - bool HasMaskedOffOperand, bool HasVL, + StringRef IRName, bool IsMask, + bool HasMaskedOffOperand, bool HasVL, bool HasPolicy, bool HasNoMaskedOverloaded, bool HasAutoDef, StringRef ManualCodegen, const RVVTypes &OutInTypes, const std::vector &NewIntrinsicTypes, StringRef RequiredExtension, unsigned NF) - : IRName(IRName), HasSideEffects(HasSideEffects), IsMask(IsMask), - HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), + : IRName(IRName), IsMask(IsMask), HasVL(HasVL), HasPolicy(HasPolicy), HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef), ManualCodegen(ManualCodegen.str()), NF(NF) { - // Init Name and MangledName - Name = NewName.str(); + // Init BuiltinName, Name and MangledName + BuiltinName = NewName.str(); + Name = BuiltinName; if (NewMangledName.empty()) MangledName = NewName.split("_").first.str(); else @@ -777,8 +781,10 @@ RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, if (!MangledSuffix.empty()) MangledName += "_" + MangledSuffix.str(); if (IsMask) { + BuiltinName += "_m"; Name += "_m"; } + // Init RISC-V extensions for (const auto &T : OutInTypes) { if (T->isFloatVector(16) || T->isFloat(16)) @@ -788,8 +794,6 @@ RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix, else if (T->isFloatVector(64) || T->isFloat(64)) RISCVExtensions |= RISCVExtension::D; } - if (RequiredExtension == "Zvamo") - RISCVExtensions |= RISCVExtension::Zvamo; if (RequiredExtension == "Zvlsseg") RISCVExtensions |= RISCVExtension::Zvlsseg; @@ -831,6 +835,9 @@ void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const { if (isMask()) { if (hasVL()) { OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; + if (hasPolicy()) + OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," + " TAIL_UNDISTURBED));\n"; } else { OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; } @@ -853,34 +860,30 @@ void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const { OS << " break;\n"; } -void RVVIntrinsic::emitIntrinsicMacro(raw_ostream &OS) const { - OS << "#define " << getName() << "("; +void RVVIntrinsic::emitIntrinsicFuncDef(raw_ostream &OS) const { + OS << "__attribute__((__clang_builtin_alias__("; + OS << "__builtin_rvv_" << getBuiltinName() << ")))\n"; + OS << OutputType->getTypeStr() << " " << getName() << "("; + // Emit function arguments if (!InputTypes.empty()) { ListSeparator LS; - for (unsigned i = 0, e = InputTypes.size(); i != e; ++i) - OS << LS << "op" << i; + for (unsigned i = 0; i < InputTypes.size(); ++i) + OS << LS << InputTypes[i]->getTypeStr(); } - OS << ") \\\n"; - OS << "__builtin_rvv_" << getName() << "("; - if (!InputTypes.empty()) { - ListSeparator LS; - for (unsigned i = 0, e = InputTypes.size(); i != e; ++i) - OS << LS << "(" << InputTypes[i]->getTypeStr() << ")(op" << i << ")"; - } - OS << ")\n"; + OS << ");\n"; } void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const { - OS << "__attribute__((clang_builtin_alias("; - OS << "__builtin_rvv_" << getName() << ")))\n"; + OS << "__attribute__((__clang_builtin_alias__("; + OS << "__builtin_rvv_" << getBuiltinName() << ")))\n"; OS << OutputType->getTypeStr() << " " << getMangledName() << "("; // Emit function arguments if (!InputTypes.empty()) { ListSeparator LS; for (unsigned i = 0; i < InputTypes.size(); ++i) - OS << LS << InputTypes[i]->getTypeStr() << " op" << i; + OS << LS << InputTypes[i]->getTypeStr(); } - OS << ");\n\n"; + OS << ");\n"; } //===----------------------------------------------------------------------===// @@ -915,6 +918,8 @@ void RVVEmitter::createHeader(raw_ostream &OS) { OS << "extern \"C\" {\n"; OS << "#endif\n\n"; + createRVVHeaders(OS); + std::vector> Defs; createRVVIntrinsics(Defs); @@ -971,33 +976,39 @@ void RVVEmitter::createHeader(raw_ostream &OS) { OS << "#endif\n\n"; // The same extension include in the same arch guard marco. - std::stable_sort(Defs.begin(), Defs.end(), - [](const std::unique_ptr &A, - const std::unique_ptr &B) { - return A->getRISCVExtensions() < B->getRISCVExtensions(); - }); + llvm::stable_sort(Defs, [](const std::unique_ptr &A, + const std::unique_ptr &B) { + return A->getRISCVExtensions() < B->getRISCVExtensions(); + }); + + OS << "#define __rvv_ai static __inline__\n"; // Print intrinsic functions with macro emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { - Inst.emitIntrinsicMacro(OS); + OS << "__rvv_ai "; + Inst.emitIntrinsicFuncDef(OS); }); + OS << "#undef __rvv_ai\n\n"; + OS << "#define __riscv_v_intrinsic_overloading 1\n"; // Print Overloaded APIs - OS << "#define __rvv_overloaded static inline " - "__attribute__((__always_inline__, __nodebug__, __overloadable__))\n"; + OS << "#define __rvv_aio static __inline__ " + "__attribute__((__overloadable__))\n"; emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded()) return; - OS << "__rvv_overloaded "; + OS << "__rvv_aio "; Inst.emitMangledFuncDef(OS); }); + OS << "#undef __rvv_aio\n"; + OS << "\n#ifdef __cplusplus\n"; OS << "}\n"; - OS << "#endif // __riscv_vector\n"; + OS << "#endif // __cplusplus\n"; OS << "#endif // __RISCV_VECTOR_H\n"; } @@ -1005,17 +1016,31 @@ void RVVEmitter::createBuiltins(raw_ostream &OS) { std::vector> Defs; createRVVIntrinsics(Defs); + // Map to keep track of which builtin names have already been emitted. + StringMap BuiltinMap; + OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " "ATTRS, \"experimental-v\")\n"; OS << "#endif\n"; for (auto &Def : Defs) { - OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getName() << ",\"" - << Def->getBuiltinTypeStr() << "\", "; - if (!Def->hasSideEffects()) - OS << "\"n\")\n"; - else - OS << "\"\")\n"; + auto P = + BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); + if (!P.second) { + // Verify that this would have produced the same builtin definition. + if (P.first->second->hasAutoDef() != Def->hasAutoDef()) { + PrintFatalError("Builtin with same name has different hasAutoDef"); + } else if (!Def->hasAutoDef() && P.first->second->getBuiltinTypeStr() != + Def->getBuiltinTypeStr()) { + PrintFatalError("Builtin with same name has different type string"); + } + continue; + } + + OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; + if (!Def->hasAutoDef()) + OS << Def->getBuiltinTypeStr(); + OS << "\", \"n\")\n"; } OS << "#undef RISCVV_BUILTIN\n"; } @@ -1024,11 +1049,14 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) { std::vector> Defs; createRVVIntrinsics(Defs); // IR name could be empty, use the stable sort preserves the relative order. - std::stable_sort(Defs.begin(), Defs.end(), - [](const std::unique_ptr &A, - const std::unique_ptr &B) { - return A->getIRName() < B->getIRName(); - }); + llvm::stable_sort(Defs, [](const std::unique_ptr &A, + const std::unique_ptr &B) { + return A->getIRName() < B->getIRName(); + }); + + // Map to keep track of which builtin names have already been emitted. + StringMap BuiltinMap; + // Print switch body when the ir name or ManualCodegen changes from previous // iteration. RVVIntrinsic *PrevDef = Defs.begin()->get(); @@ -1039,7 +1067,29 @@ void RVVEmitter::createCodeGen(raw_ostream &OS) { PrevDef->emitCodeGenSwitchBody(OS); } PrevDef = Def.get(); - OS << "case RISCV::BI__builtin_rvv_" << Def->getName() << ":\n"; + + auto P = + BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); + if (P.second) { + OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() + << ":\n"; + continue; + } + + if (P.first->second->getIRName() != Def->getIRName()) + PrintFatalError("Builtin with same name has different IRName"); + else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) + PrintFatalError("Builtin with same name has different ManualCodegen"); + else if (P.first->second->getNF() != Def->getNF()) + PrintFatalError("Builtin with same name has different NF"); + else if (P.first->second->isMask() != Def->isMask()) + PrintFatalError("Builtin with same name has different isMask"); + else if (P.first->second->hasVL() != Def->hasVL()) + PrintFatalError("Builtin with same name has different HasPolicy"); + else if (P.first->second->hasPolicy() != Def->hasPolicy()) + PrintFatalError("Builtin with same name has different HasPolicy"); + else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) + PrintFatalError("Builtin with same name has different IntrinsicTypes"); } Defs.back()->emitCodeGenSwitchBody(OS); OS << "\n"; @@ -1084,8 +1134,8 @@ void RVVEmitter::createRVVIntrinsics( bool HasMask = R->getValueAsBit("HasMask"); bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); bool HasVL = R->getValueAsBit("HasVL"); + bool HasPolicy = R->getValueAsBit("HasPolicy"); bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded"); - bool HasSideEffects = R->getValueAsBit("HasSideEffects"); std::vector Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask"); @@ -1157,16 +1207,16 @@ void RVVEmitter::createRVVIntrinsics( // Create a non-mask intrinsic Out.push_back(std::make_unique( Name, SuffixStr, MangledName, MangledSuffixStr, IRName, - HasSideEffects, /*IsMask=*/false, /*HasMaskedOffOperand=*/false, - HasVL, HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, - Types.getValue(), IntrinsicTypes, RequiredExtension, NF)); + /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, HasPolicy, + HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(), + IntrinsicTypes, RequiredExtension, NF)); if (HasMask) { // Create a mask intrinsic Optional MaskTypes = computeTypes(I, Log2LMUL, NF, ProtoMaskSeq); Out.push_back(std::make_unique( Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask, - HasSideEffects, /*IsMask=*/true, HasMaskedOffOperand, HasVL, + /*IsMask=*/true, HasMaskedOffOperand, HasVL, HasPolicy, HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask, MaskTypes.getValue(), IntrinsicTypes, RequiredExtension, NF)); } @@ -1175,6 +1225,15 @@ void RVVEmitter::createRVVIntrinsics( } } +void RVVEmitter::createRVVHeaders(raw_ostream &OS) { + std::vector RVVHeaders = + Records.getAllDerivedDefinitions("RVVHeader"); + for (auto *R : RVVHeaders) { + StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); + OS << HeaderCodeStr.str(); + } +} + Optional RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF, ArrayRef PrototypeSeq) { @@ -1245,8 +1304,6 @@ bool RVVEmitter::emitExtDefStr(uint8_t Extents, raw_ostream &OS) { OS << LS << "defined(__riscv_d)"; if (Extents & RISCVExtension::Zfh) OS << LS << "defined(__riscv_zfh)"; - if (Extents & RISCVExtension::Zvamo) - OS << LS << "defined(__riscv_zvamo)"; if (Extents & RISCVExtension::Zvlsseg) OS << LS << "defined(__riscv_zvlsseg)"; OS << "\n"; diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index 7fb5d0acc6f..bb9366e2b7f 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -30,6 +30,7 @@ enum ActionType { GenClangAttrSubjectMatchRulesParserStringSwitches, GenClangAttrImpl, GenClangAttrList, + GenClangAttrDocTable, GenClangAttrSubjectMatchRuleList, GenClangAttrPCHRead, GenClangAttrPCHWrite, @@ -115,6 +116,8 @@ cl::opt Action( "Generate clang attribute implementations"), clEnumValN(GenClangAttrList, "gen-clang-attr-list", "Generate a clang attribute list"), + clEnumValN(GenClangAttrDocTable, "gen-clang-attr-doc-table", + "Generate a table of attribute documentation"), clEnumValN(GenClangAttrSubjectMatchRuleList, "gen-clang-attr-subject-match-rule-list", "Generate a clang attribute subject match rule list"), @@ -280,6 +283,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) { case GenClangAttrList: EmitClangAttrList(Records, OS); break; + case GenClangAttrDocTable: + EmitClangAttrDocTable(Records, OS); + break; case GenClangAttrSubjectMatchRuleList: EmitClangAttrSubjectMatchRuleList(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index bf40c7b1d18..fd8b9fcda20 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -61,6 +61,7 @@ void EmitClangAttrTextNodeDump(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangAttrNodeTraverse(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); +void EmitClangAttrDocTable(llvm::RecordKeeper &Records, llvm::raw_ostream &OS); void EmitClangDiagsDefs(llvm::RecordKeeper &Records, llvm::raw_ostream &OS, const std::string &Component); diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc index 08a64246962..008b8dde582 100644 --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -75,9 +75,7 @@ INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), NameRef, \ INSTR_PROF_DATA(const uint64_t, llvm::Type::getInt64Ty(Ctx), FuncHash, \ ConstantInt::get(llvm::Type::getInt64Ty(Ctx), \ Inc->getHash()->getZExtValue())) -INSTR_PROF_DATA(const IntPtrT, llvm::Type::getInt64PtrTy(Ctx), CounterPtr, \ - ConstantExpr::getBitCast(CounterPtr, \ - llvm::Type::getInt64PtrTy(Ctx))) +INSTR_PROF_DATA(const IntPtrT, IntPtrTy, CounterPtr, RelativeCounterPtr) /* This is used to map function pointers for the indirect call targets to * function name hashes during the conversion from raw to merged profile * data. @@ -129,15 +127,16 @@ INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \ #endif INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic()) INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version()) +INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL)) INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters) INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize) INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesAfterCounters, PaddingBytesAfterCounters) INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize) -INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin) +INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, + (uintptr_t)CountersBegin - (uintptr_t)DataBegin) INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin) INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last) -INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL)) #undef INSTR_PROF_RAW_HEADER /* INSTR_PROF_RAW_HEADER end */ @@ -646,7 +645,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, (uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129 /* Raw profile format version (start from 1). */ -#define INSTR_PROF_RAW_VERSION 6 +#define INSTR_PROF_RAW_VERSION 8 /* Indexed profile format version (start from 1). */ #define INSTR_PROF_INDEX_VERSION 7 /* Coverage mapping format version (start from 0). */ diff --git a/compiler-rt/include/sanitizer/asan_interface.h b/compiler-rt/include/sanitizer/asan_interface.h index 792ef9cfaa3..9bff21c117b 100644 --- a/compiler-rt/include/sanitizer/asan_interface.h +++ b/compiler-rt/include/sanitizer/asan_interface.h @@ -316,7 +316,7 @@ void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, void __asan_handle_no_return(void); /// Update allocation stack trace for the given allocation to the current stack -/// trace. Returns 1 if successfull, 0 if not. +/// trace. Returns 1 if successful, 0 if not. int __asan_update_allocation_context(void* addr); #ifdef __cplusplus diff --git a/compiler-rt/include/sanitizer/common_interface_defs.h b/compiler-rt/include/sanitizer/common_interface_defs.h index cd69285b8d4..692b8f70c96 100644 --- a/compiler-rt/include/sanitizer/common_interface_defs.h +++ b/compiler-rt/include/sanitizer/common_interface_defs.h @@ -28,7 +28,7 @@ typedef struct { // Enable sandbox support in sanitizer coverage. int coverage_sandboxed; // File descriptor to write coverage data to. If -1 is passed, a file will - // be pre-opened by __sanitizer_sandobx_on_notify(). This field has no + // be pre-opened by __sanitizer_sandbox_on_notify(). This field has no // effect if coverage_sandboxed == 0. intptr_t coverage_fd; // If non-zero, split the coverage data into well-formed blocks. This is diff --git a/compiler-rt/include/sanitizer/dfsan_interface.h b/compiler-rt/include/sanitizer/dfsan_interface.h index cd3b6d6e2b1..d6209a3ea2b 100644 --- a/compiler-rt/include/sanitizer/dfsan_interface.h +++ b/compiler-rt/include/sanitizer/dfsan_interface.h @@ -150,8 +150,7 @@ int dfsan_get_track_origins(void); #ifdef __cplusplus } // extern "C" -template -void dfsan_set_label(dfsan_label label, T &data) { // NOLINT +template void dfsan_set_label(dfsan_label label, T &data) { dfsan_set_label(label, (void *)&data, sizeof(T)); } diff --git a/compiler-rt/include/sanitizer/linux_syscall_hooks.h b/compiler-rt/include/sanitizer/linux_syscall_hooks.h index 56eae3d40f9..3f3f1e78dfb 100644 --- a/compiler-rt/include/sanitizer/linux_syscall_hooks.h +++ b/compiler-rt/include/sanitizer/linux_syscall_hooks.h @@ -20,1493 +20,1502 @@ #ifndef SANITIZER_LINUX_SYSCALL_HOOKS_H #define SANITIZER_LINUX_SYSCALL_HOOKS_H -#define __sanitizer_syscall_pre_time(tloc) \ +#define __sanitizer_syscall_pre_time(tloc) \ __sanitizer_syscall_pre_impl_time((long)(tloc)) -#define __sanitizer_syscall_post_time(res, tloc) \ +#define __sanitizer_syscall_post_time(res, tloc) \ __sanitizer_syscall_post_impl_time(res, (long)(tloc)) -#define __sanitizer_syscall_pre_stime(tptr) \ +#define __sanitizer_syscall_pre_stime(tptr) \ __sanitizer_syscall_pre_impl_stime((long)(tptr)) -#define __sanitizer_syscall_post_stime(res, tptr) \ +#define __sanitizer_syscall_post_stime(res, tptr) \ __sanitizer_syscall_post_impl_stime(res, (long)(tptr)) -#define __sanitizer_syscall_pre_gettimeofday(tv, tz) \ +#define __sanitizer_syscall_pre_gettimeofday(tv, tz) \ __sanitizer_syscall_pre_impl_gettimeofday((long)(tv), (long)(tz)) -#define __sanitizer_syscall_post_gettimeofday(res, tv, tz) \ +#define __sanitizer_syscall_post_gettimeofday(res, tv, tz) \ __sanitizer_syscall_post_impl_gettimeofday(res, (long)(tv), (long)(tz)) -#define __sanitizer_syscall_pre_settimeofday(tv, tz) \ +#define __sanitizer_syscall_pre_settimeofday(tv, tz) \ __sanitizer_syscall_pre_impl_settimeofday((long)(tv), (long)(tz)) -#define __sanitizer_syscall_post_settimeofday(res, tv, tz) \ +#define __sanitizer_syscall_post_settimeofday(res, tv, tz) \ __sanitizer_syscall_post_impl_settimeofday(res, (long)(tv), (long)(tz)) -#define __sanitizer_syscall_pre_adjtimex(txc_p) \ +#define __sanitizer_syscall_pre_adjtimex(txc_p) \ __sanitizer_syscall_pre_impl_adjtimex((long)(txc_p)) -#define __sanitizer_syscall_post_adjtimex(res, txc_p) \ +#define __sanitizer_syscall_post_adjtimex(res, txc_p) \ __sanitizer_syscall_post_impl_adjtimex(res, (long)(txc_p)) -#define __sanitizer_syscall_pre_times(tbuf) \ +#define __sanitizer_syscall_pre_times(tbuf) \ __sanitizer_syscall_pre_impl_times((long)(tbuf)) -#define __sanitizer_syscall_post_times(res, tbuf) \ +#define __sanitizer_syscall_post_times(res, tbuf) \ __sanitizer_syscall_post_impl_times(res, (long)(tbuf)) #define __sanitizer_syscall_pre_gettid() __sanitizer_syscall_pre_impl_gettid() -#define __sanitizer_syscall_post_gettid(res) \ +#define __sanitizer_syscall_post_gettid(res) \ __sanitizer_syscall_post_impl_gettid(res) -#define __sanitizer_syscall_pre_nanosleep(rqtp, rmtp) \ +#define __sanitizer_syscall_pre_nanosleep(rqtp, rmtp) \ __sanitizer_syscall_pre_impl_nanosleep((long)(rqtp), (long)(rmtp)) -#define __sanitizer_syscall_post_nanosleep(res, rqtp, rmtp) \ +#define __sanitizer_syscall_post_nanosleep(res, rqtp, rmtp) \ __sanitizer_syscall_post_impl_nanosleep(res, (long)(rqtp), (long)(rmtp)) -#define __sanitizer_syscall_pre_alarm(seconds) \ +#define __sanitizer_syscall_pre_alarm(seconds) \ __sanitizer_syscall_pre_impl_alarm((long)(seconds)) -#define __sanitizer_syscall_post_alarm(res, seconds) \ +#define __sanitizer_syscall_post_alarm(res, seconds) \ __sanitizer_syscall_post_impl_alarm(res, (long)(seconds)) #define __sanitizer_syscall_pre_getpid() __sanitizer_syscall_pre_impl_getpid() -#define __sanitizer_syscall_post_getpid(res) \ +#define __sanitizer_syscall_post_getpid(res) \ __sanitizer_syscall_post_impl_getpid(res) #define __sanitizer_syscall_pre_getppid() __sanitizer_syscall_pre_impl_getppid() -#define __sanitizer_syscall_post_getppid(res) \ +#define __sanitizer_syscall_post_getppid(res) \ __sanitizer_syscall_post_impl_getppid(res) #define __sanitizer_syscall_pre_getuid() __sanitizer_syscall_pre_impl_getuid() -#define __sanitizer_syscall_post_getuid(res) \ +#define __sanitizer_syscall_post_getuid(res) \ __sanitizer_syscall_post_impl_getuid(res) #define __sanitizer_syscall_pre_geteuid() __sanitizer_syscall_pre_impl_geteuid() -#define __sanitizer_syscall_post_geteuid(res) \ +#define __sanitizer_syscall_post_geteuid(res) \ __sanitizer_syscall_post_impl_geteuid(res) #define __sanitizer_syscall_pre_getgid() __sanitizer_syscall_pre_impl_getgid() -#define __sanitizer_syscall_post_getgid(res) \ +#define __sanitizer_syscall_post_getgid(res) \ __sanitizer_syscall_post_impl_getgid(res) #define __sanitizer_syscall_pre_getegid() __sanitizer_syscall_pre_impl_getegid() -#define __sanitizer_syscall_post_getegid(res) \ +#define __sanitizer_syscall_post_getegid(res) \ __sanitizer_syscall_post_impl_getegid(res) -#define __sanitizer_syscall_pre_getresuid(ruid, euid, suid) \ - __sanitizer_syscall_pre_impl_getresuid((long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_pre_getresuid(ruid, euid, suid) \ + __sanitizer_syscall_pre_impl_getresuid((long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_post_getresuid(res, ruid, euid, suid) \ - __sanitizer_syscall_post_impl_getresuid(res, (long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_post_getresuid(res, ruid, euid, suid) \ + __sanitizer_syscall_post_impl_getresuid(res, (long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_pre_getresgid(rgid, egid, sgid) \ - __sanitizer_syscall_pre_impl_getresgid((long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_pre_getresgid(rgid, egid, sgid) \ + __sanitizer_syscall_pre_impl_getresgid((long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_post_getresgid(res, rgid, egid, sgid) \ - __sanitizer_syscall_post_impl_getresgid(res, (long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_post_getresgid(res, rgid, egid, sgid) \ + __sanitizer_syscall_post_impl_getresgid(res, (long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_pre_getpgid(pid) \ +#define __sanitizer_syscall_pre_getpgid(pid) \ __sanitizer_syscall_pre_impl_getpgid((long)(pid)) -#define __sanitizer_syscall_post_getpgid(res, pid) \ +#define __sanitizer_syscall_post_getpgid(res, pid) \ __sanitizer_syscall_post_impl_getpgid(res, (long)(pid)) #define __sanitizer_syscall_pre_getpgrp() __sanitizer_syscall_pre_impl_getpgrp() -#define __sanitizer_syscall_post_getpgrp(res) \ +#define __sanitizer_syscall_post_getpgrp(res) \ __sanitizer_syscall_post_impl_getpgrp(res) -#define __sanitizer_syscall_pre_getsid(pid) \ +#define __sanitizer_syscall_pre_getsid(pid) \ __sanitizer_syscall_pre_impl_getsid((long)(pid)) -#define __sanitizer_syscall_post_getsid(res, pid) \ +#define __sanitizer_syscall_post_getsid(res, pid) \ __sanitizer_syscall_post_impl_getsid(res, (long)(pid)) -#define __sanitizer_syscall_pre_getgroups(gidsetsize, grouplist) \ +#define __sanitizer_syscall_pre_getgroups(gidsetsize, grouplist) \ __sanitizer_syscall_pre_impl_getgroups((long)(gidsetsize), (long)(grouplist)) -#define __sanitizer_syscall_post_getgroups(res, gidsetsize, grouplist) \ - __sanitizer_syscall_post_impl_getgroups(res, (long)(gidsetsize), \ +#define __sanitizer_syscall_post_getgroups(res, gidsetsize, grouplist) \ + __sanitizer_syscall_post_impl_getgroups(res, (long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_pre_setregid(rgid, egid) \ +#define __sanitizer_syscall_pre_setregid(rgid, egid) \ __sanitizer_syscall_pre_impl_setregid((long)(rgid), (long)(egid)) -#define __sanitizer_syscall_post_setregid(res, rgid, egid) \ +#define __sanitizer_syscall_post_setregid(res, rgid, egid) \ __sanitizer_syscall_post_impl_setregid(res, (long)(rgid), (long)(egid)) -#define __sanitizer_syscall_pre_setgid(gid) \ +#define __sanitizer_syscall_pre_setgid(gid) \ __sanitizer_syscall_pre_impl_setgid((long)(gid)) -#define __sanitizer_syscall_post_setgid(res, gid) \ +#define __sanitizer_syscall_post_setgid(res, gid) \ __sanitizer_syscall_post_impl_setgid(res, (long)(gid)) -#define __sanitizer_syscall_pre_setreuid(ruid, euid) \ +#define __sanitizer_syscall_pre_setreuid(ruid, euid) \ __sanitizer_syscall_pre_impl_setreuid((long)(ruid), (long)(euid)) -#define __sanitizer_syscall_post_setreuid(res, ruid, euid) \ +#define __sanitizer_syscall_post_setreuid(res, ruid, euid) \ __sanitizer_syscall_post_impl_setreuid(res, (long)(ruid), (long)(euid)) -#define __sanitizer_syscall_pre_setuid(uid) \ +#define __sanitizer_syscall_pre_setuid(uid) \ __sanitizer_syscall_pre_impl_setuid((long)(uid)) -#define __sanitizer_syscall_post_setuid(res, uid) \ +#define __sanitizer_syscall_post_setuid(res, uid) \ __sanitizer_syscall_post_impl_setuid(res, (long)(uid)) -#define __sanitizer_syscall_pre_setresuid(ruid, euid, suid) \ - __sanitizer_syscall_pre_impl_setresuid((long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_pre_setresuid(ruid, euid, suid) \ + __sanitizer_syscall_pre_impl_setresuid((long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_post_setresuid(res, ruid, euid, suid) \ - __sanitizer_syscall_post_impl_setresuid(res, (long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_post_setresuid(res, ruid, euid, suid) \ + __sanitizer_syscall_post_impl_setresuid(res, (long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_pre_setresgid(rgid, egid, sgid) \ - __sanitizer_syscall_pre_impl_setresgid((long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_pre_setresgid(rgid, egid, sgid) \ + __sanitizer_syscall_pre_impl_setresgid((long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_post_setresgid(res, rgid, egid, sgid) \ - __sanitizer_syscall_post_impl_setresgid(res, (long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_post_setresgid(res, rgid, egid, sgid) \ + __sanitizer_syscall_post_impl_setresgid(res, (long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_pre_setfsuid(uid) \ +#define __sanitizer_syscall_pre_setfsuid(uid) \ __sanitizer_syscall_pre_impl_setfsuid((long)(uid)) -#define __sanitizer_syscall_post_setfsuid(res, uid) \ +#define __sanitizer_syscall_post_setfsuid(res, uid) \ __sanitizer_syscall_post_impl_setfsuid(res, (long)(uid)) -#define __sanitizer_syscall_pre_setfsgid(gid) \ +#define __sanitizer_syscall_pre_setfsgid(gid) \ __sanitizer_syscall_pre_impl_setfsgid((long)(gid)) -#define __sanitizer_syscall_post_setfsgid(res, gid) \ +#define __sanitizer_syscall_post_setfsgid(res, gid) \ __sanitizer_syscall_post_impl_setfsgid(res, (long)(gid)) -#define __sanitizer_syscall_pre_setpgid(pid, pgid) \ +#define __sanitizer_syscall_pre_setpgid(pid, pgid) \ __sanitizer_syscall_pre_impl_setpgid((long)(pid), (long)(pgid)) -#define __sanitizer_syscall_post_setpgid(res, pid, pgid) \ +#define __sanitizer_syscall_post_setpgid(res, pid, pgid) \ __sanitizer_syscall_post_impl_setpgid(res, (long)(pid), (long)(pgid)) #define __sanitizer_syscall_pre_setsid() __sanitizer_syscall_pre_impl_setsid() -#define __sanitizer_syscall_post_setsid(res) \ +#define __sanitizer_syscall_post_setsid(res) \ __sanitizer_syscall_post_impl_setsid(res) -#define __sanitizer_syscall_pre_setgroups(gidsetsize, grouplist) \ +#define __sanitizer_syscall_pre_setgroups(gidsetsize, grouplist) \ __sanitizer_syscall_pre_impl_setgroups((long)(gidsetsize), (long)(grouplist)) -#define __sanitizer_syscall_post_setgroups(res, gidsetsize, grouplist) \ - __sanitizer_syscall_post_impl_setgroups(res, (long)(gidsetsize), \ +#define __sanitizer_syscall_post_setgroups(res, gidsetsize, grouplist) \ + __sanitizer_syscall_post_impl_setgroups(res, (long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_pre_acct(name) \ +#define __sanitizer_syscall_pre_acct(name) \ __sanitizer_syscall_pre_impl_acct((long)(name)) -#define __sanitizer_syscall_post_acct(res, name) \ +#define __sanitizer_syscall_post_acct(res, name) \ __sanitizer_syscall_post_impl_acct(res, (long)(name)) -#define __sanitizer_syscall_pre_capget(header, dataptr) \ +#define __sanitizer_syscall_pre_capget(header, dataptr) \ __sanitizer_syscall_pre_impl_capget((long)(header), (long)(dataptr)) -#define __sanitizer_syscall_post_capget(res, header, dataptr) \ +#define __sanitizer_syscall_post_capget(res, header, dataptr) \ __sanitizer_syscall_post_impl_capget(res, (long)(header), (long)(dataptr)) -#define __sanitizer_syscall_pre_capset(header, data) \ +#define __sanitizer_syscall_pre_capset(header, data) \ __sanitizer_syscall_pre_impl_capset((long)(header), (long)(data)) -#define __sanitizer_syscall_post_capset(res, header, data) \ +#define __sanitizer_syscall_post_capset(res, header, data) \ __sanitizer_syscall_post_impl_capset(res, (long)(header), (long)(data)) -#define __sanitizer_syscall_pre_personality(personality) \ +#define __sanitizer_syscall_pre_personality(personality) \ __sanitizer_syscall_pre_impl_personality((long)(personality)) -#define __sanitizer_syscall_post_personality(res, personality) \ +#define __sanitizer_syscall_post_personality(res, personality) \ __sanitizer_syscall_post_impl_personality(res, (long)(personality)) -#define __sanitizer_syscall_pre_sigpending(set) \ +#define __sanitizer_syscall_pre_sigpending(set) \ __sanitizer_syscall_pre_impl_sigpending((long)(set)) -#define __sanitizer_syscall_post_sigpending(res, set) \ +#define __sanitizer_syscall_post_sigpending(res, set) \ __sanitizer_syscall_post_impl_sigpending(res, (long)(set)) -#define __sanitizer_syscall_pre_sigprocmask(how, set, oset) \ - __sanitizer_syscall_pre_impl_sigprocmask((long)(how), (long)(set), \ +#define __sanitizer_syscall_pre_sigprocmask(how, set, oset) \ + __sanitizer_syscall_pre_impl_sigprocmask((long)(how), (long)(set), \ (long)(oset)) -#define __sanitizer_syscall_post_sigprocmask(res, how, set, oset) \ - __sanitizer_syscall_post_impl_sigprocmask(res, (long)(how), (long)(set), \ +#define __sanitizer_syscall_post_sigprocmask(res, how, set, oset) \ + __sanitizer_syscall_post_impl_sigprocmask(res, (long)(how), (long)(set), \ (long)(oset)) -#define __sanitizer_syscall_pre_getitimer(which, value) \ +#define __sanitizer_syscall_pre_getitimer(which, value) \ __sanitizer_syscall_pre_impl_getitimer((long)(which), (long)(value)) -#define __sanitizer_syscall_post_getitimer(res, which, value) \ +#define __sanitizer_syscall_post_getitimer(res, which, value) \ __sanitizer_syscall_post_impl_getitimer(res, (long)(which), (long)(value)) -#define __sanitizer_syscall_pre_setitimer(which, value, ovalue) \ - __sanitizer_syscall_pre_impl_setitimer((long)(which), (long)(value), \ +#define __sanitizer_syscall_pre_setitimer(which, value, ovalue) \ + __sanitizer_syscall_pre_impl_setitimer((long)(which), (long)(value), \ (long)(ovalue)) -#define __sanitizer_syscall_post_setitimer(res, which, value, ovalue) \ - __sanitizer_syscall_post_impl_setitimer(res, (long)(which), (long)(value), \ +#define __sanitizer_syscall_post_setitimer(res, which, value, ovalue) \ + __sanitizer_syscall_post_impl_setitimer(res, (long)(which), (long)(value), \ (long)(ovalue)) -#define __sanitizer_syscall_pre_timer_create(which_clock, timer_event_spec, \ - created_timer_id) \ - __sanitizer_syscall_pre_impl_timer_create( \ +#define __sanitizer_syscall_pre_timer_create(which_clock, timer_event_spec, \ + created_timer_id) \ + __sanitizer_syscall_pre_impl_timer_create( \ (long)(which_clock), (long)(timer_event_spec), (long)(created_timer_id)) -#define __sanitizer_syscall_post_timer_create( \ - res, which_clock, timer_event_spec, created_timer_id) \ - __sanitizer_syscall_post_impl_timer_create(res, (long)(which_clock), \ - (long)(timer_event_spec), \ +#define __sanitizer_syscall_post_timer_create( \ + res, which_clock, timer_event_spec, created_timer_id) \ + __sanitizer_syscall_post_impl_timer_create(res, (long)(which_clock), \ + (long)(timer_event_spec), \ (long)(created_timer_id)) -#define __sanitizer_syscall_pre_timer_gettime(timer_id, setting) \ +#define __sanitizer_syscall_pre_timer_gettime(timer_id, setting) \ __sanitizer_syscall_pre_impl_timer_gettime((long)(timer_id), (long)(setting)) -#define __sanitizer_syscall_post_timer_gettime(res, timer_id, setting) \ - __sanitizer_syscall_post_impl_timer_gettime(res, (long)(timer_id), \ +#define __sanitizer_syscall_post_timer_gettime(res, timer_id, setting) \ + __sanitizer_syscall_post_impl_timer_gettime(res, (long)(timer_id), \ (long)(setting)) -#define __sanitizer_syscall_pre_timer_getoverrun(timer_id) \ +#define __sanitizer_syscall_pre_timer_getoverrun(timer_id) \ __sanitizer_syscall_pre_impl_timer_getoverrun((long)(timer_id)) -#define __sanitizer_syscall_post_timer_getoverrun(res, timer_id) \ +#define __sanitizer_syscall_post_timer_getoverrun(res, timer_id) \ __sanitizer_syscall_post_impl_timer_getoverrun(res, (long)(timer_id)) -#define __sanitizer_syscall_pre_timer_settime(timer_id, flags, new_setting, \ - old_setting) \ - __sanitizer_syscall_pre_impl_timer_settime((long)(timer_id), (long)(flags), \ - (long)(new_setting), \ +#define __sanitizer_syscall_pre_timer_settime(timer_id, flags, new_setting, \ + old_setting) \ + __sanitizer_syscall_pre_impl_timer_settime((long)(timer_id), (long)(flags), \ + (long)(new_setting), \ (long)(old_setting)) -#define __sanitizer_syscall_post_timer_settime(res, timer_id, flags, \ - new_setting, old_setting) \ - __sanitizer_syscall_post_impl_timer_settime( \ - res, (long)(timer_id), (long)(flags), (long)(new_setting), \ +#define __sanitizer_syscall_post_timer_settime(res, timer_id, flags, \ + new_setting, old_setting) \ + __sanitizer_syscall_post_impl_timer_settime( \ + res, (long)(timer_id), (long)(flags), (long)(new_setting), \ (long)(old_setting)) -#define __sanitizer_syscall_pre_timer_delete(timer_id) \ +#define __sanitizer_syscall_pre_timer_delete(timer_id) \ __sanitizer_syscall_pre_impl_timer_delete((long)(timer_id)) -#define __sanitizer_syscall_post_timer_delete(res, timer_id) \ +#define __sanitizer_syscall_post_timer_delete(res, timer_id) \ __sanitizer_syscall_post_impl_timer_delete(res, (long)(timer_id)) -#define __sanitizer_syscall_pre_clock_settime(which_clock, tp) \ +#define __sanitizer_syscall_pre_clock_settime(which_clock, tp) \ __sanitizer_syscall_pre_impl_clock_settime((long)(which_clock), (long)(tp)) -#define __sanitizer_syscall_post_clock_settime(res, which_clock, tp) \ - __sanitizer_syscall_post_impl_clock_settime(res, (long)(which_clock), \ +#define __sanitizer_syscall_post_clock_settime(res, which_clock, tp) \ + __sanitizer_syscall_post_impl_clock_settime(res, (long)(which_clock), \ (long)(tp)) -#define __sanitizer_syscall_pre_clock_gettime(which_clock, tp) \ +#define __sanitizer_syscall_pre_clock_gettime(which_clock, tp) \ __sanitizer_syscall_pre_impl_clock_gettime((long)(which_clock), (long)(tp)) -#define __sanitizer_syscall_post_clock_gettime(res, which_clock, tp) \ - __sanitizer_syscall_post_impl_clock_gettime(res, (long)(which_clock), \ +#define __sanitizer_syscall_post_clock_gettime(res, which_clock, tp) \ + __sanitizer_syscall_post_impl_clock_gettime(res, (long)(which_clock), \ (long)(tp)) -#define __sanitizer_syscall_pre_clock_adjtime(which_clock, tx) \ +#define __sanitizer_syscall_pre_clock_adjtime(which_clock, tx) \ __sanitizer_syscall_pre_impl_clock_adjtime((long)(which_clock), (long)(tx)) -#define __sanitizer_syscall_post_clock_adjtime(res, which_clock, tx) \ - __sanitizer_syscall_post_impl_clock_adjtime(res, (long)(which_clock), \ +#define __sanitizer_syscall_post_clock_adjtime(res, which_clock, tx) \ + __sanitizer_syscall_post_impl_clock_adjtime(res, (long)(which_clock), \ (long)(tx)) -#define __sanitizer_syscall_pre_clock_getres(which_clock, tp) \ +#define __sanitizer_syscall_pre_clock_getres(which_clock, tp) \ __sanitizer_syscall_pre_impl_clock_getres((long)(which_clock), (long)(tp)) -#define __sanitizer_syscall_post_clock_getres(res, which_clock, tp) \ - __sanitizer_syscall_post_impl_clock_getres(res, (long)(which_clock), \ +#define __sanitizer_syscall_post_clock_getres(res, which_clock, tp) \ + __sanitizer_syscall_post_impl_clock_getres(res, (long)(which_clock), \ (long)(tp)) -#define __sanitizer_syscall_pre_clock_nanosleep(which_clock, flags, rqtp, \ - rmtp) \ - __sanitizer_syscall_pre_impl_clock_nanosleep( \ +#define __sanitizer_syscall_pre_clock_nanosleep(which_clock, flags, rqtp, \ + rmtp) \ + __sanitizer_syscall_pre_impl_clock_nanosleep( \ (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp)) -#define __sanitizer_syscall_post_clock_nanosleep(res, which_clock, flags, \ - rqtp, rmtp) \ - __sanitizer_syscall_post_impl_clock_nanosleep( \ +#define __sanitizer_syscall_post_clock_nanosleep(res, which_clock, flags, \ + rqtp, rmtp) \ + __sanitizer_syscall_post_impl_clock_nanosleep( \ res, (long)(which_clock), (long)(flags), (long)(rqtp), (long)(rmtp)) -#define __sanitizer_syscall_pre_nice(increment) \ +#define __sanitizer_syscall_pre_nice(increment) \ __sanitizer_syscall_pre_impl_nice((long)(increment)) -#define __sanitizer_syscall_post_nice(res, increment) \ +#define __sanitizer_syscall_post_nice(res, increment) \ __sanitizer_syscall_post_impl_nice(res, (long)(increment)) #define __sanitizer_syscall_pre_sched_setscheduler(pid, policy, param) \ __sanitizer_syscall_pre_impl_sched_setscheduler((long)(pid), (long)(policy), \ (long)(param)) -#define __sanitizer_syscall_post_sched_setscheduler(res, pid, policy, param) \ - __sanitizer_syscall_post_impl_sched_setscheduler( \ +#define __sanitizer_syscall_post_sched_setscheduler(res, pid, policy, param) \ + __sanitizer_syscall_post_impl_sched_setscheduler( \ res, (long)(pid), (long)(policy), (long)(param)) -#define __sanitizer_syscall_pre_sched_setparam(pid, param) \ +#define __sanitizer_syscall_pre_sched_setparam(pid, param) \ __sanitizer_syscall_pre_impl_sched_setparam((long)(pid), (long)(param)) -#define __sanitizer_syscall_post_sched_setparam(res, pid, param) \ +#define __sanitizer_syscall_post_sched_setparam(res, pid, param) \ __sanitizer_syscall_post_impl_sched_setparam(res, (long)(pid), (long)(param)) -#define __sanitizer_syscall_pre_sched_getscheduler(pid) \ +#define __sanitizer_syscall_pre_sched_getscheduler(pid) \ __sanitizer_syscall_pre_impl_sched_getscheduler((long)(pid)) -#define __sanitizer_syscall_post_sched_getscheduler(res, pid) \ +#define __sanitizer_syscall_post_sched_getscheduler(res, pid) \ __sanitizer_syscall_post_impl_sched_getscheduler(res, (long)(pid)) -#define __sanitizer_syscall_pre_sched_getparam(pid, param) \ +#define __sanitizer_syscall_pre_sched_getparam(pid, param) \ __sanitizer_syscall_pre_impl_sched_getparam((long)(pid), (long)(param)) -#define __sanitizer_syscall_post_sched_getparam(res, pid, param) \ +#define __sanitizer_syscall_post_sched_getparam(res, pid, param) \ __sanitizer_syscall_post_impl_sched_getparam(res, (long)(pid), (long)(param)) -#define __sanitizer_syscall_pre_sched_setaffinity(pid, len, user_mask_ptr) \ - __sanitizer_syscall_pre_impl_sched_setaffinity((long)(pid), (long)(len), \ +#define __sanitizer_syscall_pre_sched_setaffinity(pid, len, user_mask_ptr) \ + __sanitizer_syscall_pre_impl_sched_setaffinity((long)(pid), (long)(len), \ (long)(user_mask_ptr)) -#define __sanitizer_syscall_post_sched_setaffinity(res, pid, len, \ - user_mask_ptr) \ - __sanitizer_syscall_post_impl_sched_setaffinity( \ +#define __sanitizer_syscall_post_sched_setaffinity(res, pid, len, \ + user_mask_ptr) \ + __sanitizer_syscall_post_impl_sched_setaffinity( \ res, (long)(pid), (long)(len), (long)(user_mask_ptr)) -#define __sanitizer_syscall_pre_sched_getaffinity(pid, len, user_mask_ptr) \ - __sanitizer_syscall_pre_impl_sched_getaffinity((long)(pid), (long)(len), \ +#define __sanitizer_syscall_pre_sched_getaffinity(pid, len, user_mask_ptr) \ + __sanitizer_syscall_pre_impl_sched_getaffinity((long)(pid), (long)(len), \ (long)(user_mask_ptr)) -#define __sanitizer_syscall_post_sched_getaffinity(res, pid, len, \ - user_mask_ptr) \ - __sanitizer_syscall_post_impl_sched_getaffinity( \ +#define __sanitizer_syscall_post_sched_getaffinity(res, pid, len, \ + user_mask_ptr) \ + __sanitizer_syscall_post_impl_sched_getaffinity( \ res, (long)(pid), (long)(len), (long)(user_mask_ptr)) -#define __sanitizer_syscall_pre_sched_yield() \ +#define __sanitizer_syscall_pre_sched_yield() \ __sanitizer_syscall_pre_impl_sched_yield() -#define __sanitizer_syscall_post_sched_yield(res) \ +#define __sanitizer_syscall_post_sched_yield(res) \ __sanitizer_syscall_post_impl_sched_yield(res) -#define __sanitizer_syscall_pre_sched_get_priority_max(policy) \ +#define __sanitizer_syscall_pre_sched_get_priority_max(policy) \ __sanitizer_syscall_pre_impl_sched_get_priority_max((long)(policy)) -#define __sanitizer_syscall_post_sched_get_priority_max(res, policy) \ +#define __sanitizer_syscall_post_sched_get_priority_max(res, policy) \ __sanitizer_syscall_post_impl_sched_get_priority_max(res, (long)(policy)) -#define __sanitizer_syscall_pre_sched_get_priority_min(policy) \ +#define __sanitizer_syscall_pre_sched_get_priority_min(policy) \ __sanitizer_syscall_pre_impl_sched_get_priority_min((long)(policy)) -#define __sanitizer_syscall_post_sched_get_priority_min(res, policy) \ +#define __sanitizer_syscall_post_sched_get_priority_min(res, policy) \ __sanitizer_syscall_post_impl_sched_get_priority_min(res, (long)(policy)) -#define __sanitizer_syscall_pre_sched_rr_get_interval(pid, interval) \ - __sanitizer_syscall_pre_impl_sched_rr_get_interval((long)(pid), \ +#define __sanitizer_syscall_pre_sched_rr_get_interval(pid, interval) \ + __sanitizer_syscall_pre_impl_sched_rr_get_interval((long)(pid), \ (long)(interval)) -#define __sanitizer_syscall_post_sched_rr_get_interval(res, pid, interval) \ - __sanitizer_syscall_post_impl_sched_rr_get_interval(res, (long)(pid), \ +#define __sanitizer_syscall_post_sched_rr_get_interval(res, pid, interval) \ + __sanitizer_syscall_post_impl_sched_rr_get_interval(res, (long)(pid), \ (long)(interval)) -#define __sanitizer_syscall_pre_setpriority(which, who, niceval) \ - __sanitizer_syscall_pre_impl_setpriority((long)(which), (long)(who), \ +#define __sanitizer_syscall_pre_setpriority(which, who, niceval) \ + __sanitizer_syscall_pre_impl_setpriority((long)(which), (long)(who), \ (long)(niceval)) -#define __sanitizer_syscall_post_setpriority(res, which, who, niceval) \ - __sanitizer_syscall_post_impl_setpriority(res, (long)(which), (long)(who), \ +#define __sanitizer_syscall_post_setpriority(res, which, who, niceval) \ + __sanitizer_syscall_post_impl_setpriority(res, (long)(which), (long)(who), \ (long)(niceval)) -#define __sanitizer_syscall_pre_getpriority(which, who) \ +#define __sanitizer_syscall_pre_getpriority(which, who) \ __sanitizer_syscall_pre_impl_getpriority((long)(which), (long)(who)) -#define __sanitizer_syscall_post_getpriority(res, which, who) \ +#define __sanitizer_syscall_post_getpriority(res, which, who) \ __sanitizer_syscall_post_impl_getpriority(res, (long)(which), (long)(who)) -#define __sanitizer_syscall_pre_shutdown(arg0, arg1) \ +#define __sanitizer_syscall_pre_shutdown(arg0, arg1) \ __sanitizer_syscall_pre_impl_shutdown((long)(arg0), (long)(arg1)) -#define __sanitizer_syscall_post_shutdown(res, arg0, arg1) \ +#define __sanitizer_syscall_post_shutdown(res, arg0, arg1) \ __sanitizer_syscall_post_impl_shutdown(res, (long)(arg0), (long)(arg1)) -#define __sanitizer_syscall_pre_reboot(magic1, magic2, cmd, arg) \ - __sanitizer_syscall_pre_impl_reboot((long)(magic1), (long)(magic2), \ +#define __sanitizer_syscall_pre_reboot(magic1, magic2, cmd, arg) \ + __sanitizer_syscall_pre_impl_reboot((long)(magic1), (long)(magic2), \ (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_post_reboot(res, magic1, magic2, cmd, arg) \ - __sanitizer_syscall_post_impl_reboot(res, (long)(magic1), (long)(magic2), \ +#define __sanitizer_syscall_post_reboot(res, magic1, magic2, cmd, arg) \ + __sanitizer_syscall_post_impl_reboot(res, (long)(magic1), (long)(magic2), \ (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_pre_restart_syscall() \ +#define __sanitizer_syscall_pre_restart_syscall() \ __sanitizer_syscall_pre_impl_restart_syscall() -#define __sanitizer_syscall_post_restart_syscall(res) \ +#define __sanitizer_syscall_post_restart_syscall(res) \ __sanitizer_syscall_post_impl_restart_syscall(res) -#define __sanitizer_syscall_pre_kexec_load(entry, nr_segments, segments, \ - flags) \ - __sanitizer_syscall_pre_impl_kexec_load((long)(entry), (long)(nr_segments), \ +#define __sanitizer_syscall_pre_kexec_load(entry, nr_segments, segments, \ + flags) \ + __sanitizer_syscall_pre_impl_kexec_load((long)(entry), (long)(nr_segments), \ (long)(segments), (long)(flags)) #define __sanitizer_syscall_post_kexec_load(res, entry, nr_segments, segments, \ flags) \ __sanitizer_syscall_post_impl_kexec_load(res, (long)(entry), \ (long)(nr_segments), \ (long)(segments), (long)(flags)) -#define __sanitizer_syscall_pre_exit(error_code) \ +#define __sanitizer_syscall_pre_exit(error_code) \ __sanitizer_syscall_pre_impl_exit((long)(error_code)) -#define __sanitizer_syscall_post_exit(res, error_code) \ +#define __sanitizer_syscall_post_exit(res, error_code) \ __sanitizer_syscall_post_impl_exit(res, (long)(error_code)) -#define __sanitizer_syscall_pre_exit_group(error_code) \ +#define __sanitizer_syscall_pre_exit_group(error_code) \ __sanitizer_syscall_pre_impl_exit_group((long)(error_code)) -#define __sanitizer_syscall_post_exit_group(res, error_code) \ +#define __sanitizer_syscall_post_exit_group(res, error_code) \ __sanitizer_syscall_post_impl_exit_group(res, (long)(error_code)) -#define __sanitizer_syscall_pre_wait4(pid, stat_addr, options, ru) \ - __sanitizer_syscall_pre_impl_wait4((long)(pid), (long)(stat_addr), \ +#define __sanitizer_syscall_pre_wait4(pid, stat_addr, options, ru) \ + __sanitizer_syscall_pre_impl_wait4((long)(pid), (long)(stat_addr), \ (long)(options), (long)(ru)) -#define __sanitizer_syscall_post_wait4(res, pid, stat_addr, options, ru) \ - __sanitizer_syscall_post_impl_wait4(res, (long)(pid), (long)(stat_addr), \ +#define __sanitizer_syscall_post_wait4(res, pid, stat_addr, options, ru) \ + __sanitizer_syscall_post_impl_wait4(res, (long)(pid), (long)(stat_addr), \ (long)(options), (long)(ru)) -#define __sanitizer_syscall_pre_waitid(which, pid, infop, options, ru) \ - __sanitizer_syscall_pre_impl_waitid( \ +#define __sanitizer_syscall_pre_waitid(which, pid, infop, options, ru) \ + __sanitizer_syscall_pre_impl_waitid( \ (long)(which), (long)(pid), (long)(infop), (long)(options), (long)(ru)) -#define __sanitizer_syscall_post_waitid(res, which, pid, infop, options, ru) \ - __sanitizer_syscall_post_impl_waitid(res, (long)(which), (long)(pid), \ - (long)(infop), (long)(options), \ +#define __sanitizer_syscall_post_waitid(res, which, pid, infop, options, ru) \ + __sanitizer_syscall_post_impl_waitid(res, (long)(which), (long)(pid), \ + (long)(infop), (long)(options), \ (long)(ru)) -#define __sanitizer_syscall_pre_waitpid(pid, stat_addr, options) \ - __sanitizer_syscall_pre_impl_waitpid((long)(pid), (long)(stat_addr), \ +#define __sanitizer_syscall_pre_waitpid(pid, stat_addr, options) \ + __sanitizer_syscall_pre_impl_waitpid((long)(pid), (long)(stat_addr), \ (long)(options)) -#define __sanitizer_syscall_post_waitpid(res, pid, stat_addr, options) \ - __sanitizer_syscall_post_impl_waitpid(res, (long)(pid), (long)(stat_addr), \ +#define __sanitizer_syscall_post_waitpid(res, pid, stat_addr, options) \ + __sanitizer_syscall_post_impl_waitpid(res, (long)(pid), (long)(stat_addr), \ (long)(options)) -#define __sanitizer_syscall_pre_set_tid_address(tidptr) \ +#define __sanitizer_syscall_pre_set_tid_address(tidptr) \ __sanitizer_syscall_pre_impl_set_tid_address((long)(tidptr)) -#define __sanitizer_syscall_post_set_tid_address(res, tidptr) \ +#define __sanitizer_syscall_post_set_tid_address(res, tidptr) \ __sanitizer_syscall_post_impl_set_tid_address(res, (long)(tidptr)) -#define __sanitizer_syscall_pre_init_module(umod, len, uargs) \ - __sanitizer_syscall_pre_impl_init_module((long)(umod), (long)(len), \ +#define __sanitizer_syscall_pre_init_module(umod, len, uargs) \ + __sanitizer_syscall_pre_impl_init_module((long)(umod), (long)(len), \ (long)(uargs)) -#define __sanitizer_syscall_post_init_module(res, umod, len, uargs) \ - __sanitizer_syscall_post_impl_init_module(res, (long)(umod), (long)(len), \ +#define __sanitizer_syscall_post_init_module(res, umod, len, uargs) \ + __sanitizer_syscall_post_impl_init_module(res, (long)(umod), (long)(len), \ (long)(uargs)) -#define __sanitizer_syscall_pre_delete_module(name_user, flags) \ +#define __sanitizer_syscall_pre_delete_module(name_user, flags) \ __sanitizer_syscall_pre_impl_delete_module((long)(name_user), (long)(flags)) -#define __sanitizer_syscall_post_delete_module(res, name_user, flags) \ - __sanitizer_syscall_post_impl_delete_module(res, (long)(name_user), \ +#define __sanitizer_syscall_post_delete_module(res, name_user, flags) \ + __sanitizer_syscall_post_impl_delete_module(res, (long)(name_user), \ (long)(flags)) -#define __sanitizer_syscall_pre_rt_sigprocmask(how, set, oset, sigsetsize) \ - __sanitizer_syscall_pre_impl_rt_sigprocmask( \ +#define __sanitizer_syscall_pre_rt_sigprocmask(how, set, oset, sigsetsize) \ + __sanitizer_syscall_pre_impl_rt_sigprocmask( \ (long)(how), (long)(set), (long)(oset), (long)(sigsetsize)) -#define __sanitizer_syscall_post_rt_sigprocmask(res, how, set, oset, \ - sigsetsize) \ - __sanitizer_syscall_post_impl_rt_sigprocmask( \ +#define __sanitizer_syscall_post_rt_sigprocmask(res, how, set, oset, \ + sigsetsize) \ + __sanitizer_syscall_post_impl_rt_sigprocmask( \ res, (long)(how), (long)(set), (long)(oset), (long)(sigsetsize)) -#define __sanitizer_syscall_pre_rt_sigpending(set, sigsetsize) \ +#define __sanitizer_syscall_pre_rt_sigpending(set, sigsetsize) \ __sanitizer_syscall_pre_impl_rt_sigpending((long)(set), (long)(sigsetsize)) -#define __sanitizer_syscall_post_rt_sigpending(res, set, sigsetsize) \ - __sanitizer_syscall_post_impl_rt_sigpending(res, (long)(set), \ +#define __sanitizer_syscall_post_rt_sigpending(res, set, sigsetsize) \ + __sanitizer_syscall_post_impl_rt_sigpending(res, (long)(set), \ (long)(sigsetsize)) -#define __sanitizer_syscall_pre_rt_sigtimedwait(uthese, uinfo, uts, \ - sigsetsize) \ - __sanitizer_syscall_pre_impl_rt_sigtimedwait( \ +#define __sanitizer_syscall_pre_rt_sigtimedwait(uthese, uinfo, uts, \ + sigsetsize) \ + __sanitizer_syscall_pre_impl_rt_sigtimedwait( \ (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize)) -#define __sanitizer_syscall_post_rt_sigtimedwait(res, uthese, uinfo, uts, \ - sigsetsize) \ - __sanitizer_syscall_post_impl_rt_sigtimedwait( \ +#define __sanitizer_syscall_post_rt_sigtimedwait(res, uthese, uinfo, uts, \ + sigsetsize) \ + __sanitizer_syscall_post_impl_rt_sigtimedwait( \ res, (long)(uthese), (long)(uinfo), (long)(uts), (long)(sigsetsize)) -#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(tgid, pid, sig, uinfo) \ - __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo((long)(tgid), (long)(pid), \ +#define __sanitizer_syscall_pre_rt_tgsigqueueinfo(tgid, pid, sig, uinfo) \ + __sanitizer_syscall_pre_impl_rt_tgsigqueueinfo((long)(tgid), (long)(pid), \ (long)(sig), (long)(uinfo)) #define __sanitizer_syscall_post_rt_tgsigqueueinfo(res, tgid, pid, sig, uinfo) \ __sanitizer_syscall_post_impl_rt_tgsigqueueinfo( \ res, (long)(tgid), (long)(pid), (long)(sig), (long)(uinfo)) -#define __sanitizer_syscall_pre_kill(pid, sig) \ +#define __sanitizer_syscall_pre_kill(pid, sig) \ __sanitizer_syscall_pre_impl_kill((long)(pid), (long)(sig)) -#define __sanitizer_syscall_post_kill(res, pid, sig) \ +#define __sanitizer_syscall_post_kill(res, pid, sig) \ __sanitizer_syscall_post_impl_kill(res, (long)(pid), (long)(sig)) -#define __sanitizer_syscall_pre_tgkill(tgid, pid, sig) \ +#define __sanitizer_syscall_pre_tgkill(tgid, pid, sig) \ __sanitizer_syscall_pre_impl_tgkill((long)(tgid), (long)(pid), (long)(sig)) -#define __sanitizer_syscall_post_tgkill(res, tgid, pid, sig) \ - __sanitizer_syscall_post_impl_tgkill(res, (long)(tgid), (long)(pid), \ +#define __sanitizer_syscall_post_tgkill(res, tgid, pid, sig) \ + __sanitizer_syscall_post_impl_tgkill(res, (long)(tgid), (long)(pid), \ (long)(sig)) -#define __sanitizer_syscall_pre_tkill(pid, sig) \ +#define __sanitizer_syscall_pre_tkill(pid, sig) \ __sanitizer_syscall_pre_impl_tkill((long)(pid), (long)(sig)) -#define __sanitizer_syscall_post_tkill(res, pid, sig) \ +#define __sanitizer_syscall_post_tkill(res, pid, sig) \ __sanitizer_syscall_post_impl_tkill(res, (long)(pid), (long)(sig)) -#define __sanitizer_syscall_pre_rt_sigqueueinfo(pid, sig, uinfo) \ - __sanitizer_syscall_pre_impl_rt_sigqueueinfo((long)(pid), (long)(sig), \ +#define __sanitizer_syscall_pre_rt_sigqueueinfo(pid, sig, uinfo) \ + __sanitizer_syscall_pre_impl_rt_sigqueueinfo((long)(pid), (long)(sig), \ (long)(uinfo)) #define __sanitizer_syscall_post_rt_sigqueueinfo(res, pid, sig, uinfo) \ __sanitizer_syscall_post_impl_rt_sigqueueinfo(res, (long)(pid), (long)(sig), \ (long)(uinfo)) -#define __sanitizer_syscall_pre_sgetmask() \ +#define __sanitizer_syscall_pre_sgetmask() \ __sanitizer_syscall_pre_impl_sgetmask() -#define __sanitizer_syscall_post_sgetmask(res) \ +#define __sanitizer_syscall_post_sgetmask(res) \ __sanitizer_syscall_post_impl_sgetmask(res) -#define __sanitizer_syscall_pre_ssetmask(newmask) \ +#define __sanitizer_syscall_pre_ssetmask(newmask) \ __sanitizer_syscall_pre_impl_ssetmask((long)(newmask)) -#define __sanitizer_syscall_post_ssetmask(res, newmask) \ +#define __sanitizer_syscall_post_ssetmask(res, newmask) \ __sanitizer_syscall_post_impl_ssetmask(res, (long)(newmask)) -#define __sanitizer_syscall_pre_signal(sig, handler) \ +#define __sanitizer_syscall_pre_signal(sig, handler) \ __sanitizer_syscall_pre_impl_signal((long)(sig), (long)(handler)) -#define __sanitizer_syscall_post_signal(res, sig, handler) \ +#define __sanitizer_syscall_post_signal(res, sig, handler) \ __sanitizer_syscall_post_impl_signal(res, (long)(sig), (long)(handler)) #define __sanitizer_syscall_pre_pause() __sanitizer_syscall_pre_impl_pause() -#define __sanitizer_syscall_post_pause(res) \ +#define __sanitizer_syscall_post_pause(res) \ __sanitizer_syscall_post_impl_pause(res) #define __sanitizer_syscall_pre_sync() __sanitizer_syscall_pre_impl_sync() -#define __sanitizer_syscall_post_sync(res) \ +#define __sanitizer_syscall_post_sync(res) \ __sanitizer_syscall_post_impl_sync(res) -#define __sanitizer_syscall_pre_fsync(fd) \ +#define __sanitizer_syscall_pre_fsync(fd) \ __sanitizer_syscall_pre_impl_fsync((long)(fd)) -#define __sanitizer_syscall_post_fsync(res, fd) \ +#define __sanitizer_syscall_post_fsync(res, fd) \ __sanitizer_syscall_post_impl_fsync(res, (long)(fd)) -#define __sanitizer_syscall_pre_fdatasync(fd) \ +#define __sanitizer_syscall_pre_fdatasync(fd) \ __sanitizer_syscall_pre_impl_fdatasync((long)(fd)) -#define __sanitizer_syscall_post_fdatasync(res, fd) \ +#define __sanitizer_syscall_post_fdatasync(res, fd) \ __sanitizer_syscall_post_impl_fdatasync(res, (long)(fd)) -#define __sanitizer_syscall_pre_bdflush(func, data) \ +#define __sanitizer_syscall_pre_bdflush(func, data) \ __sanitizer_syscall_pre_impl_bdflush((long)(func), (long)(data)) -#define __sanitizer_syscall_post_bdflush(res, func, data) \ +#define __sanitizer_syscall_post_bdflush(res, func, data) \ __sanitizer_syscall_post_impl_bdflush(res, (long)(func), (long)(data)) -#define __sanitizer_syscall_pre_mount(dev_name, dir_name, type, flags, data) \ - __sanitizer_syscall_pre_impl_mount((long)(dev_name), (long)(dir_name), \ - (long)(type), (long)(flags), \ +#define __sanitizer_syscall_pre_mount(dev_name, dir_name, type, flags, data) \ + __sanitizer_syscall_pre_impl_mount((long)(dev_name), (long)(dir_name), \ + (long)(type), (long)(flags), \ (long)(data)) #define __sanitizer_syscall_post_mount(res, dev_name, dir_name, type, flags, \ data) \ __sanitizer_syscall_post_impl_mount(res, (long)(dev_name), (long)(dir_name), \ (long)(type), (long)(flags), \ (long)(data)) -#define __sanitizer_syscall_pre_umount(name, flags) \ +#define __sanitizer_syscall_pre_umount(name, flags) \ __sanitizer_syscall_pre_impl_umount((long)(name), (long)(flags)) -#define __sanitizer_syscall_post_umount(res, name, flags) \ +#define __sanitizer_syscall_post_umount(res, name, flags) \ __sanitizer_syscall_post_impl_umount(res, (long)(name), (long)(flags)) -#define __sanitizer_syscall_pre_oldumount(name) \ +#define __sanitizer_syscall_pre_oldumount(name) \ __sanitizer_syscall_pre_impl_oldumount((long)(name)) -#define __sanitizer_syscall_post_oldumount(res, name) \ +#define __sanitizer_syscall_post_oldumount(res, name) \ __sanitizer_syscall_post_impl_oldumount(res, (long)(name)) -#define __sanitizer_syscall_pre_truncate(path, length) \ +#define __sanitizer_syscall_pre_truncate(path, length) \ __sanitizer_syscall_pre_impl_truncate((long)(path), (long)(length)) -#define __sanitizer_syscall_post_truncate(res, path, length) \ +#define __sanitizer_syscall_post_truncate(res, path, length) \ __sanitizer_syscall_post_impl_truncate(res, (long)(path), (long)(length)) -#define __sanitizer_syscall_pre_ftruncate(fd, length) \ +#define __sanitizer_syscall_pre_ftruncate(fd, length) \ __sanitizer_syscall_pre_impl_ftruncate((long)(fd), (long)(length)) -#define __sanitizer_syscall_post_ftruncate(res, fd, length) \ +#define __sanitizer_syscall_post_ftruncate(res, fd, length) \ __sanitizer_syscall_post_impl_ftruncate(res, (long)(fd), (long)(length)) -#define __sanitizer_syscall_pre_stat(filename, statbuf) \ +#define __sanitizer_syscall_pre_stat(filename, statbuf) \ __sanitizer_syscall_pre_impl_stat((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_stat(res, filename, statbuf) \ +#define __sanitizer_syscall_post_stat(res, filename, statbuf) \ __sanitizer_syscall_post_impl_stat(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_statfs(path, buf) \ +#define __sanitizer_syscall_pre_statfs(path, buf) \ __sanitizer_syscall_pre_impl_statfs((long)(path), (long)(buf)) -#define __sanitizer_syscall_post_statfs(res, path, buf) \ +#define __sanitizer_syscall_post_statfs(res, path, buf) \ __sanitizer_syscall_post_impl_statfs(res, (long)(path), (long)(buf)) -#define __sanitizer_syscall_pre_statfs64(path, sz, buf) \ +#define __sanitizer_syscall_pre_statfs64(path, sz, buf) \ __sanitizer_syscall_pre_impl_statfs64((long)(path), (long)(sz), (long)(buf)) -#define __sanitizer_syscall_post_statfs64(res, path, sz, buf) \ - __sanitizer_syscall_post_impl_statfs64(res, (long)(path), (long)(sz), \ +#define __sanitizer_syscall_post_statfs64(res, path, sz, buf) \ + __sanitizer_syscall_post_impl_statfs64(res, (long)(path), (long)(sz), \ (long)(buf)) -#define __sanitizer_syscall_pre_fstatfs(fd, buf) \ +#define __sanitizer_syscall_pre_fstatfs(fd, buf) \ __sanitizer_syscall_pre_impl_fstatfs((long)(fd), (long)(buf)) -#define __sanitizer_syscall_post_fstatfs(res, fd, buf) \ +#define __sanitizer_syscall_post_fstatfs(res, fd, buf) \ __sanitizer_syscall_post_impl_fstatfs(res, (long)(fd), (long)(buf)) -#define __sanitizer_syscall_pre_fstatfs64(fd, sz, buf) \ +#define __sanitizer_syscall_pre_fstatfs64(fd, sz, buf) \ __sanitizer_syscall_pre_impl_fstatfs64((long)(fd), (long)(sz), (long)(buf)) -#define __sanitizer_syscall_post_fstatfs64(res, fd, sz, buf) \ - __sanitizer_syscall_post_impl_fstatfs64(res, (long)(fd), (long)(sz), \ +#define __sanitizer_syscall_post_fstatfs64(res, fd, sz, buf) \ + __sanitizer_syscall_post_impl_fstatfs64(res, (long)(fd), (long)(sz), \ (long)(buf)) -#define __sanitizer_syscall_pre_lstat(filename, statbuf) \ +#define __sanitizer_syscall_pre_lstat(filename, statbuf) \ __sanitizer_syscall_pre_impl_lstat((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_lstat(res, filename, statbuf) \ +#define __sanitizer_syscall_post_lstat(res, filename, statbuf) \ __sanitizer_syscall_post_impl_lstat(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_fstat(fd, statbuf) \ +#define __sanitizer_syscall_pre_fstat(fd, statbuf) \ __sanitizer_syscall_pre_impl_fstat((long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_post_fstat(res, fd, statbuf) \ +#define __sanitizer_syscall_post_fstat(res, fd, statbuf) \ __sanitizer_syscall_post_impl_fstat(res, (long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_pre_newstat(filename, statbuf) \ +#define __sanitizer_syscall_pre_newstat(filename, statbuf) \ __sanitizer_syscall_pre_impl_newstat((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_newstat(res, filename, statbuf) \ +#define __sanitizer_syscall_post_newstat(res, filename, statbuf) \ __sanitizer_syscall_post_impl_newstat(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_newlstat(filename, statbuf) \ +#define __sanitizer_syscall_pre_newlstat(filename, statbuf) \ __sanitizer_syscall_pre_impl_newlstat((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_newlstat(res, filename, statbuf) \ +#define __sanitizer_syscall_post_newlstat(res, filename, statbuf) \ __sanitizer_syscall_post_impl_newlstat(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_newfstat(fd, statbuf) \ +#define __sanitizer_syscall_pre_newfstat(fd, statbuf) \ __sanitizer_syscall_pre_impl_newfstat((long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_post_newfstat(res, fd, statbuf) \ +#define __sanitizer_syscall_post_newfstat(res, fd, statbuf) \ __sanitizer_syscall_post_impl_newfstat(res, (long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_pre_ustat(dev, ubuf) \ +#define __sanitizer_syscall_pre_ustat(dev, ubuf) \ __sanitizer_syscall_pre_impl_ustat((long)(dev), (long)(ubuf)) -#define __sanitizer_syscall_post_ustat(res, dev, ubuf) \ +#define __sanitizer_syscall_post_ustat(res, dev, ubuf) \ __sanitizer_syscall_post_impl_ustat(res, (long)(dev), (long)(ubuf)) -#define __sanitizer_syscall_pre_stat64(filename, statbuf) \ +#define __sanitizer_syscall_pre_stat64(filename, statbuf) \ __sanitizer_syscall_pre_impl_stat64((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_stat64(res, filename, statbuf) \ +#define __sanitizer_syscall_post_stat64(res, filename, statbuf) \ __sanitizer_syscall_post_impl_stat64(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_fstat64(fd, statbuf) \ +#define __sanitizer_syscall_pre_fstat64(fd, statbuf) \ __sanitizer_syscall_pre_impl_fstat64((long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_post_fstat64(res, fd, statbuf) \ +#define __sanitizer_syscall_post_fstat64(res, fd, statbuf) \ __sanitizer_syscall_post_impl_fstat64(res, (long)(fd), (long)(statbuf)) -#define __sanitizer_syscall_pre_lstat64(filename, statbuf) \ +#define __sanitizer_syscall_pre_lstat64(filename, statbuf) \ __sanitizer_syscall_pre_impl_lstat64((long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_post_lstat64(res, filename, statbuf) \ +#define __sanitizer_syscall_post_lstat64(res, filename, statbuf) \ __sanitizer_syscall_post_impl_lstat64(res, (long)(filename), (long)(statbuf)) -#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags) \ - __sanitizer_syscall_pre_impl_setxattr( \ +#define __sanitizer_syscall_pre_setxattr(path, name, value, size, flags) \ + __sanitizer_syscall_pre_impl_setxattr( \ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags)) #define __sanitizer_syscall_post_setxattr(res, path, name, value, size, flags) \ __sanitizer_syscall_post_impl_setxattr(res, (long)(path), (long)(name), \ (long)(value), (long)(size), \ (long)(flags)) -#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags) \ - __sanitizer_syscall_pre_impl_lsetxattr( \ +#define __sanitizer_syscall_pre_lsetxattr(path, name, value, size, flags) \ + __sanitizer_syscall_pre_impl_lsetxattr( \ (long)(path), (long)(name), (long)(value), (long)(size), (long)(flags)) -#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size, \ - flags) \ - __sanitizer_syscall_post_impl_lsetxattr(res, (long)(path), (long)(name), \ - (long)(value), (long)(size), \ +#define __sanitizer_syscall_post_lsetxattr(res, path, name, value, size, \ + flags) \ + __sanitizer_syscall_post_impl_lsetxattr(res, (long)(path), (long)(name), \ + (long)(value), (long)(size), \ (long)(flags)) -#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags) \ - __sanitizer_syscall_pre_impl_fsetxattr( \ +#define __sanitizer_syscall_pre_fsetxattr(fd, name, value, size, flags) \ + __sanitizer_syscall_pre_impl_fsetxattr( \ (long)(fd), (long)(name), (long)(value), (long)(size), (long)(flags)) -#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags) \ - __sanitizer_syscall_post_impl_fsetxattr(res, (long)(fd), (long)(name), \ - (long)(value), (long)(size), \ +#define __sanitizer_syscall_post_fsetxattr(res, fd, name, value, size, flags) \ + __sanitizer_syscall_post_impl_fsetxattr(res, (long)(fd), (long)(name), \ + (long)(value), (long)(size), \ (long)(flags)) -#define __sanitizer_syscall_pre_getxattr(path, name, value, size) \ - __sanitizer_syscall_pre_impl_getxattr((long)(path), (long)(name), \ +#define __sanitizer_syscall_pre_getxattr(path, name, value, size) \ + __sanitizer_syscall_pre_impl_getxattr((long)(path), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_post_getxattr(res, path, name, value, size) \ - __sanitizer_syscall_post_impl_getxattr(res, (long)(path), (long)(name), \ +#define __sanitizer_syscall_post_getxattr(res, path, name, value, size) \ + __sanitizer_syscall_post_impl_getxattr(res, (long)(path), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size) \ - __sanitizer_syscall_pre_impl_lgetxattr((long)(path), (long)(name), \ +#define __sanitizer_syscall_pre_lgetxattr(path, name, value, size) \ + __sanitizer_syscall_pre_impl_lgetxattr((long)(path), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size) \ - __sanitizer_syscall_post_impl_lgetxattr(res, (long)(path), (long)(name), \ +#define __sanitizer_syscall_post_lgetxattr(res, path, name, value, size) \ + __sanitizer_syscall_post_impl_lgetxattr(res, (long)(path), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size) \ - __sanitizer_syscall_pre_impl_fgetxattr((long)(fd), (long)(name), \ +#define __sanitizer_syscall_pre_fgetxattr(fd, name, value, size) \ + __sanitizer_syscall_pre_impl_fgetxattr((long)(fd), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size) \ - __sanitizer_syscall_post_impl_fgetxattr(res, (long)(fd), (long)(name), \ +#define __sanitizer_syscall_post_fgetxattr(res, fd, name, value, size) \ + __sanitizer_syscall_post_impl_fgetxattr(res, (long)(fd), (long)(name), \ (long)(value), (long)(size)) -#define __sanitizer_syscall_pre_listxattr(path, list, size) \ - __sanitizer_syscall_pre_impl_listxattr((long)(path), (long)(list), \ +#define __sanitizer_syscall_pre_listxattr(path, list, size) \ + __sanitizer_syscall_pre_impl_listxattr((long)(path), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_post_listxattr(res, path, list, size) \ - __sanitizer_syscall_post_impl_listxattr(res, (long)(path), (long)(list), \ +#define __sanitizer_syscall_post_listxattr(res, path, list, size) \ + __sanitizer_syscall_post_impl_listxattr(res, (long)(path), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_pre_llistxattr(path, list, size) \ - __sanitizer_syscall_pre_impl_llistxattr((long)(path), (long)(list), \ +#define __sanitizer_syscall_pre_llistxattr(path, list, size) \ + __sanitizer_syscall_pre_impl_llistxattr((long)(path), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_post_llistxattr(res, path, list, size) \ - __sanitizer_syscall_post_impl_llistxattr(res, (long)(path), (long)(list), \ +#define __sanitizer_syscall_post_llistxattr(res, path, list, size) \ + __sanitizer_syscall_post_impl_llistxattr(res, (long)(path), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_pre_flistxattr(fd, list, size) \ - __sanitizer_syscall_pre_impl_flistxattr((long)(fd), (long)(list), \ +#define __sanitizer_syscall_pre_flistxattr(fd, list, size) \ + __sanitizer_syscall_pre_impl_flistxattr((long)(fd), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_post_flistxattr(res, fd, list, size) \ - __sanitizer_syscall_post_impl_flistxattr(res, (long)(fd), (long)(list), \ +#define __sanitizer_syscall_post_flistxattr(res, fd, list, size) \ + __sanitizer_syscall_post_impl_flistxattr(res, (long)(fd), (long)(list), \ (long)(size)) -#define __sanitizer_syscall_pre_removexattr(path, name) \ +#define __sanitizer_syscall_pre_removexattr(path, name) \ __sanitizer_syscall_pre_impl_removexattr((long)(path), (long)(name)) -#define __sanitizer_syscall_post_removexattr(res, path, name) \ +#define __sanitizer_syscall_post_removexattr(res, path, name) \ __sanitizer_syscall_post_impl_removexattr(res, (long)(path), (long)(name)) -#define __sanitizer_syscall_pre_lremovexattr(path, name) \ +#define __sanitizer_syscall_pre_lremovexattr(path, name) \ __sanitizer_syscall_pre_impl_lremovexattr((long)(path), (long)(name)) -#define __sanitizer_syscall_post_lremovexattr(res, path, name) \ +#define __sanitizer_syscall_post_lremovexattr(res, path, name) \ __sanitizer_syscall_post_impl_lremovexattr(res, (long)(path), (long)(name)) -#define __sanitizer_syscall_pre_fremovexattr(fd, name) \ +#define __sanitizer_syscall_pre_fremovexattr(fd, name) \ __sanitizer_syscall_pre_impl_fremovexattr((long)(fd), (long)(name)) -#define __sanitizer_syscall_post_fremovexattr(res, fd, name) \ +#define __sanitizer_syscall_post_fremovexattr(res, fd, name) \ __sanitizer_syscall_post_impl_fremovexattr(res, (long)(fd), (long)(name)) -#define __sanitizer_syscall_pre_brk(brk) \ +#define __sanitizer_syscall_pre_brk(brk) \ __sanitizer_syscall_pre_impl_brk((long)(brk)) -#define __sanitizer_syscall_post_brk(res, brk) \ +#define __sanitizer_syscall_post_brk(res, brk) \ __sanitizer_syscall_post_impl_brk(res, (long)(brk)) -#define __sanitizer_syscall_pre_mprotect(start, len, prot) \ - __sanitizer_syscall_pre_impl_mprotect((long)(start), (long)(len), \ +#define __sanitizer_syscall_pre_mprotect(start, len, prot) \ + __sanitizer_syscall_pre_impl_mprotect((long)(start), (long)(len), \ (long)(prot)) -#define __sanitizer_syscall_post_mprotect(res, start, len, prot) \ - __sanitizer_syscall_post_impl_mprotect(res, (long)(start), (long)(len), \ +#define __sanitizer_syscall_post_mprotect(res, start, len, prot) \ + __sanitizer_syscall_post_impl_mprotect(res, (long)(start), (long)(len), \ (long)(prot)) -#define __sanitizer_syscall_pre_mremap(addr, old_len, new_len, flags, \ - new_addr) \ - __sanitizer_syscall_pre_impl_mremap((long)(addr), (long)(old_len), \ - (long)(new_len), (long)(flags), \ +#define __sanitizer_syscall_pre_mremap(addr, old_len, new_len, flags, \ + new_addr) \ + __sanitizer_syscall_pre_impl_mremap((long)(addr), (long)(old_len), \ + (long)(new_len), (long)(flags), \ (long)(new_addr)) -#define __sanitizer_syscall_post_mremap(res, addr, old_len, new_len, flags, \ - new_addr) \ - __sanitizer_syscall_post_impl_mremap(res, (long)(addr), (long)(old_len), \ - (long)(new_len), (long)(flags), \ +#define __sanitizer_syscall_post_mremap(res, addr, old_len, new_len, flags, \ + new_addr) \ + __sanitizer_syscall_post_impl_mremap(res, (long)(addr), (long)(old_len), \ + (long)(new_len), (long)(flags), \ (long)(new_addr)) -#define __sanitizer_syscall_pre_remap_file_pages(start, size, prot, pgoff, \ - flags) \ - __sanitizer_syscall_pre_impl_remap_file_pages( \ +#define __sanitizer_syscall_pre_remap_file_pages(start, size, prot, pgoff, \ + flags) \ + __sanitizer_syscall_pre_impl_remap_file_pages( \ (long)(start), (long)(size), (long)(prot), (long)(pgoff), (long)(flags)) -#define __sanitizer_syscall_post_remap_file_pages(res, start, size, prot, \ - pgoff, flags) \ - __sanitizer_syscall_post_impl_remap_file_pages(res, (long)(start), \ - (long)(size), (long)(prot), \ +#define __sanitizer_syscall_post_remap_file_pages(res, start, size, prot, \ + pgoff, flags) \ + __sanitizer_syscall_post_impl_remap_file_pages(res, (long)(start), \ + (long)(size), (long)(prot), \ (long)(pgoff), (long)(flags)) -#define __sanitizer_syscall_pre_msync(start, len, flags) \ +#define __sanitizer_syscall_pre_msync(start, len, flags) \ __sanitizer_syscall_pre_impl_msync((long)(start), (long)(len), (long)(flags)) -#define __sanitizer_syscall_post_msync(res, start, len, flags) \ - __sanitizer_syscall_post_impl_msync(res, (long)(start), (long)(len), \ +#define __sanitizer_syscall_post_msync(res, start, len, flags) \ + __sanitizer_syscall_post_impl_msync(res, (long)(start), (long)(len), \ (long)(flags)) -#define __sanitizer_syscall_pre_munmap(addr, len) \ +#define __sanitizer_syscall_pre_munmap(addr, len) \ __sanitizer_syscall_pre_impl_munmap((long)(addr), (long)(len)) -#define __sanitizer_syscall_post_munmap(res, addr, len) \ +#define __sanitizer_syscall_post_munmap(res, addr, len) \ __sanitizer_syscall_post_impl_munmap(res, (long)(addr), (long)(len)) -#define __sanitizer_syscall_pre_mlock(start, len) \ +#define __sanitizer_syscall_pre_mlock(start, len) \ __sanitizer_syscall_pre_impl_mlock((long)(start), (long)(len)) -#define __sanitizer_syscall_post_mlock(res, start, len) \ +#define __sanitizer_syscall_post_mlock(res, start, len) \ __sanitizer_syscall_post_impl_mlock(res, (long)(start), (long)(len)) -#define __sanitizer_syscall_pre_munlock(start, len) \ +#define __sanitizer_syscall_pre_munlock(start, len) \ __sanitizer_syscall_pre_impl_munlock((long)(start), (long)(len)) -#define __sanitizer_syscall_post_munlock(res, start, len) \ +#define __sanitizer_syscall_post_munlock(res, start, len) \ __sanitizer_syscall_post_impl_munlock(res, (long)(start), (long)(len)) -#define __sanitizer_syscall_pre_mlockall(flags) \ +#define __sanitizer_syscall_pre_mlockall(flags) \ __sanitizer_syscall_pre_impl_mlockall((long)(flags)) -#define __sanitizer_syscall_post_mlockall(res, flags) \ +#define __sanitizer_syscall_post_mlockall(res, flags) \ __sanitizer_syscall_post_impl_mlockall(res, (long)(flags)) -#define __sanitizer_syscall_pre_munlockall() \ +#define __sanitizer_syscall_pre_munlockall() \ __sanitizer_syscall_pre_impl_munlockall() -#define __sanitizer_syscall_post_munlockall(res) \ +#define __sanitizer_syscall_post_munlockall(res) \ __sanitizer_syscall_post_impl_munlockall(res) -#define __sanitizer_syscall_pre_madvise(start, len, behavior) \ - __sanitizer_syscall_pre_impl_madvise((long)(start), (long)(len), \ +#define __sanitizer_syscall_pre_madvise(start, len, behavior) \ + __sanitizer_syscall_pre_impl_madvise((long)(start), (long)(len), \ (long)(behavior)) -#define __sanitizer_syscall_post_madvise(res, start, len, behavior) \ - __sanitizer_syscall_post_impl_madvise(res, (long)(start), (long)(len), \ +#define __sanitizer_syscall_post_madvise(res, start, len, behavior) \ + __sanitizer_syscall_post_impl_madvise(res, (long)(start), (long)(len), \ (long)(behavior)) -#define __sanitizer_syscall_pre_mincore(start, len, vec) \ +#define __sanitizer_syscall_pre_mincore(start, len, vec) \ __sanitizer_syscall_pre_impl_mincore((long)(start), (long)(len), (long)(vec)) -#define __sanitizer_syscall_post_mincore(res, start, len, vec) \ - __sanitizer_syscall_post_impl_mincore(res, (long)(start), (long)(len), \ +#define __sanitizer_syscall_post_mincore(res, start, len, vec) \ + __sanitizer_syscall_post_impl_mincore(res, (long)(start), (long)(len), \ (long)(vec)) -#define __sanitizer_syscall_pre_pivot_root(new_root, put_old) \ +#define __sanitizer_syscall_pre_pivot_root(new_root, put_old) \ __sanitizer_syscall_pre_impl_pivot_root((long)(new_root), (long)(put_old)) -#define __sanitizer_syscall_post_pivot_root(res, new_root, put_old) \ - __sanitizer_syscall_post_impl_pivot_root(res, (long)(new_root), \ +#define __sanitizer_syscall_post_pivot_root(res, new_root, put_old) \ + __sanitizer_syscall_post_impl_pivot_root(res, (long)(new_root), \ (long)(put_old)) -#define __sanitizer_syscall_pre_chroot(filename) \ +#define __sanitizer_syscall_pre_chroot(filename) \ __sanitizer_syscall_pre_impl_chroot((long)(filename)) -#define __sanitizer_syscall_post_chroot(res, filename) \ +#define __sanitizer_syscall_post_chroot(res, filename) \ __sanitizer_syscall_post_impl_chroot(res, (long)(filename)) -#define __sanitizer_syscall_pre_mknod(filename, mode, dev) \ - __sanitizer_syscall_pre_impl_mknod((long)(filename), (long)(mode), \ +#define __sanitizer_syscall_pre_mknod(filename, mode, dev) \ + __sanitizer_syscall_pre_impl_mknod((long)(filename), (long)(mode), \ (long)(dev)) -#define __sanitizer_syscall_post_mknod(res, filename, mode, dev) \ - __sanitizer_syscall_post_impl_mknod(res, (long)(filename), (long)(mode), \ +#define __sanitizer_syscall_post_mknod(res, filename, mode, dev) \ + __sanitizer_syscall_post_impl_mknod(res, (long)(filename), (long)(mode), \ (long)(dev)) -#define __sanitizer_syscall_pre_link(oldname, newname) \ +#define __sanitizer_syscall_pre_link(oldname, newname) \ __sanitizer_syscall_pre_impl_link((long)(oldname), (long)(newname)) -#define __sanitizer_syscall_post_link(res, oldname, newname) \ +#define __sanitizer_syscall_post_link(res, oldname, newname) \ __sanitizer_syscall_post_impl_link(res, (long)(oldname), (long)(newname)) -#define __sanitizer_syscall_pre_symlink(old, new_) \ +#define __sanitizer_syscall_pre_symlink(old, new_) \ __sanitizer_syscall_pre_impl_symlink((long)(old), (long)(new_)) -#define __sanitizer_syscall_post_symlink(res, old, new_) \ +#define __sanitizer_syscall_post_symlink(res, old, new_) \ __sanitizer_syscall_post_impl_symlink(res, (long)(old), (long)(new_)) -#define __sanitizer_syscall_pre_unlink(pathname) \ +#define __sanitizer_syscall_pre_unlink(pathname) \ __sanitizer_syscall_pre_impl_unlink((long)(pathname)) -#define __sanitizer_syscall_post_unlink(res, pathname) \ +#define __sanitizer_syscall_post_unlink(res, pathname) \ __sanitizer_syscall_post_impl_unlink(res, (long)(pathname)) -#define __sanitizer_syscall_pre_rename(oldname, newname) \ +#define __sanitizer_syscall_pre_rename(oldname, newname) \ __sanitizer_syscall_pre_impl_rename((long)(oldname), (long)(newname)) -#define __sanitizer_syscall_post_rename(res, oldname, newname) \ +#define __sanitizer_syscall_post_rename(res, oldname, newname) \ __sanitizer_syscall_post_impl_rename(res, (long)(oldname), (long)(newname)) -#define __sanitizer_syscall_pre_chmod(filename, mode) \ +#define __sanitizer_syscall_pre_chmod(filename, mode) \ __sanitizer_syscall_pre_impl_chmod((long)(filename), (long)(mode)) -#define __sanitizer_syscall_post_chmod(res, filename, mode) \ +#define __sanitizer_syscall_post_chmod(res, filename, mode) \ __sanitizer_syscall_post_impl_chmod(res, (long)(filename), (long)(mode)) -#define __sanitizer_syscall_pre_fchmod(fd, mode) \ +#define __sanitizer_syscall_pre_fchmod(fd, mode) \ __sanitizer_syscall_pre_impl_fchmod((long)(fd), (long)(mode)) -#define __sanitizer_syscall_post_fchmod(res, fd, mode) \ +#define __sanitizer_syscall_post_fchmod(res, fd, mode) \ __sanitizer_syscall_post_impl_fchmod(res, (long)(fd), (long)(mode)) -#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \ +#define __sanitizer_syscall_pre_fcntl(fd, cmd, arg) \ __sanitizer_syscall_pre_impl_fcntl((long)(fd), (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg) \ +#define __sanitizer_syscall_post_fcntl(res, fd, cmd, arg) \ __sanitizer_syscall_post_impl_fcntl(res, (long)(fd), (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_pre_fcntl64(fd, cmd, arg) \ +#define __sanitizer_syscall_pre_fcntl64(fd, cmd, arg) \ __sanitizer_syscall_pre_impl_fcntl64((long)(fd), (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_post_fcntl64(res, fd, cmd, arg) \ - __sanitizer_syscall_post_impl_fcntl64(res, (long)(fd), (long)(cmd), \ +#define __sanitizer_syscall_post_fcntl64(res, fd, cmd, arg) \ + __sanitizer_syscall_post_impl_fcntl64(res, (long)(fd), (long)(cmd), \ (long)(arg)) -#define __sanitizer_syscall_pre_pipe(fildes) \ +#define __sanitizer_syscall_pre_pipe(fildes) \ __sanitizer_syscall_pre_impl_pipe((long)(fildes)) -#define __sanitizer_syscall_post_pipe(res, fildes) \ +#define __sanitizer_syscall_post_pipe(res, fildes) \ __sanitizer_syscall_post_impl_pipe(res, (long)(fildes)) -#define __sanitizer_syscall_pre_pipe2(fildes, flags) \ +#define __sanitizer_syscall_pre_pipe2(fildes, flags) \ __sanitizer_syscall_pre_impl_pipe2((long)(fildes), (long)(flags)) -#define __sanitizer_syscall_post_pipe2(res, fildes, flags) \ +#define __sanitizer_syscall_post_pipe2(res, fildes, flags) \ __sanitizer_syscall_post_impl_pipe2(res, (long)(fildes), (long)(flags)) -#define __sanitizer_syscall_pre_dup(fildes) \ +#define __sanitizer_syscall_pre_dup(fildes) \ __sanitizer_syscall_pre_impl_dup((long)(fildes)) -#define __sanitizer_syscall_post_dup(res, fildes) \ +#define __sanitizer_syscall_post_dup(res, fildes) \ __sanitizer_syscall_post_impl_dup(res, (long)(fildes)) -#define __sanitizer_syscall_pre_dup2(oldfd, newfd) \ +#define __sanitizer_syscall_pre_dup2(oldfd, newfd) \ __sanitizer_syscall_pre_impl_dup2((long)(oldfd), (long)(newfd)) -#define __sanitizer_syscall_post_dup2(res, oldfd, newfd) \ +#define __sanitizer_syscall_post_dup2(res, oldfd, newfd) \ __sanitizer_syscall_post_impl_dup2(res, (long)(oldfd), (long)(newfd)) -#define __sanitizer_syscall_pre_dup3(oldfd, newfd, flags) \ +#define __sanitizer_syscall_pre_dup3(oldfd, newfd, flags) \ __sanitizer_syscall_pre_impl_dup3((long)(oldfd), (long)(newfd), (long)(flags)) -#define __sanitizer_syscall_post_dup3(res, oldfd, newfd, flags) \ - __sanitizer_syscall_post_impl_dup3(res, (long)(oldfd), (long)(newfd), \ +#define __sanitizer_syscall_post_dup3(res, oldfd, newfd, flags) \ + __sanitizer_syscall_post_impl_dup3(res, (long)(oldfd), (long)(newfd), \ (long)(flags)) -#define __sanitizer_syscall_pre_ioperm(from, num, on) \ +#define __sanitizer_syscall_pre_ioperm(from, num, on) \ __sanitizer_syscall_pre_impl_ioperm((long)(from), (long)(num), (long)(on)) -#define __sanitizer_syscall_post_ioperm(res, from, num, on) \ - __sanitizer_syscall_post_impl_ioperm(res, (long)(from), (long)(num), \ +#define __sanitizer_syscall_post_ioperm(res, from, num, on) \ + __sanitizer_syscall_post_impl_ioperm(res, (long)(from), (long)(num), \ (long)(on)) -#define __sanitizer_syscall_pre_ioctl(fd, cmd, arg) \ +#define __sanitizer_syscall_pre_ioctl(fd, cmd, arg) \ __sanitizer_syscall_pre_impl_ioctl((long)(fd), (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_post_ioctl(res, fd, cmd, arg) \ +#define __sanitizer_syscall_post_ioctl(res, fd, cmd, arg) \ __sanitizer_syscall_post_impl_ioctl(res, (long)(fd), (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_pre_flock(fd, cmd) \ +#define __sanitizer_syscall_pre_flock(fd, cmd) \ __sanitizer_syscall_pre_impl_flock((long)(fd), (long)(cmd)) -#define __sanitizer_syscall_post_flock(res, fd, cmd) \ +#define __sanitizer_syscall_post_flock(res, fd, cmd) \ __sanitizer_syscall_post_impl_flock(res, (long)(fd), (long)(cmd)) -#define __sanitizer_syscall_pre_io_setup(nr_reqs, ctx) \ +#define __sanitizer_syscall_pre_io_setup(nr_reqs, ctx) \ __sanitizer_syscall_pre_impl_io_setup((long)(nr_reqs), (long)(ctx)) -#define __sanitizer_syscall_post_io_setup(res, nr_reqs, ctx) \ +#define __sanitizer_syscall_post_io_setup(res, nr_reqs, ctx) \ __sanitizer_syscall_post_impl_io_setup(res, (long)(nr_reqs), (long)(ctx)) -#define __sanitizer_syscall_pre_io_destroy(ctx) \ +#define __sanitizer_syscall_pre_io_destroy(ctx) \ __sanitizer_syscall_pre_impl_io_destroy((long)(ctx)) -#define __sanitizer_syscall_post_io_destroy(res, ctx) \ +#define __sanitizer_syscall_post_io_destroy(res, ctx) \ __sanitizer_syscall_post_impl_io_destroy(res, (long)(ctx)) -#define __sanitizer_syscall_pre_io_getevents(ctx_id, min_nr, nr, events, \ - timeout) \ - __sanitizer_syscall_pre_impl_io_getevents((long)(ctx_id), (long)(min_nr), \ - (long)(nr), (long)(events), \ +#define __sanitizer_syscall_pre_io_getevents(ctx_id, min_nr, nr, events, \ + timeout) \ + __sanitizer_syscall_pre_impl_io_getevents((long)(ctx_id), (long)(min_nr), \ + (long)(nr), (long)(events), \ (long)(timeout)) #define __sanitizer_syscall_post_io_getevents(res, ctx_id, min_nr, nr, events, \ timeout) \ __sanitizer_syscall_post_impl_io_getevents(res, (long)(ctx_id), \ (long)(min_nr), (long)(nr), \ (long)(events), (long)(timeout)) -#define __sanitizer_syscall_pre_io_submit(ctx_id, arg1, arg2) \ - __sanitizer_syscall_pre_impl_io_submit((long)(ctx_id), (long)(arg1), \ +#define __sanitizer_syscall_pre_io_submit(ctx_id, arg1, arg2) \ + __sanitizer_syscall_pre_impl_io_submit((long)(ctx_id), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_post_io_submit(res, ctx_id, arg1, arg2) \ - __sanitizer_syscall_post_impl_io_submit(res, (long)(ctx_id), (long)(arg1), \ +#define __sanitizer_syscall_post_io_submit(res, ctx_id, arg1, arg2) \ + __sanitizer_syscall_post_impl_io_submit(res, (long)(ctx_id), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_io_cancel(ctx_id, iocb, result) \ - __sanitizer_syscall_pre_impl_io_cancel((long)(ctx_id), (long)(iocb), \ +#define __sanitizer_syscall_pre_io_cancel(ctx_id, iocb, result) \ + __sanitizer_syscall_pre_impl_io_cancel((long)(ctx_id), (long)(iocb), \ (long)(result)) -#define __sanitizer_syscall_post_io_cancel(res, ctx_id, iocb, result) \ - __sanitizer_syscall_post_impl_io_cancel(res, (long)(ctx_id), (long)(iocb), \ +#define __sanitizer_syscall_post_io_cancel(res, ctx_id, iocb, result) \ + __sanitizer_syscall_post_impl_io_cancel(res, (long)(ctx_id), (long)(iocb), \ (long)(result)) -#define __sanitizer_syscall_pre_sendfile(out_fd, in_fd, offset, count) \ - __sanitizer_syscall_pre_impl_sendfile((long)(out_fd), (long)(in_fd), \ +#define __sanitizer_syscall_pre_sendfile(out_fd, in_fd, offset, count) \ + __sanitizer_syscall_pre_impl_sendfile((long)(out_fd), (long)(in_fd), \ (long)(offset), (long)(count)) -#define __sanitizer_syscall_post_sendfile(res, out_fd, in_fd, offset, count) \ - __sanitizer_syscall_post_impl_sendfile(res, (long)(out_fd), (long)(in_fd), \ +#define __sanitizer_syscall_post_sendfile(res, out_fd, in_fd, offset, count) \ + __sanitizer_syscall_post_impl_sendfile(res, (long)(out_fd), (long)(in_fd), \ (long)(offset), (long)(count)) -#define __sanitizer_syscall_pre_sendfile64(out_fd, in_fd, offset, count) \ - __sanitizer_syscall_pre_impl_sendfile64((long)(out_fd), (long)(in_fd), \ +#define __sanitizer_syscall_pre_sendfile64(out_fd, in_fd, offset, count) \ + __sanitizer_syscall_pre_impl_sendfile64((long)(out_fd), (long)(in_fd), \ (long)(offset), (long)(count)) #define __sanitizer_syscall_post_sendfile64(res, out_fd, in_fd, offset, count) \ __sanitizer_syscall_post_impl_sendfile64(res, (long)(out_fd), (long)(in_fd), \ (long)(offset), (long)(count)) -#define __sanitizer_syscall_pre_readlink(path, buf, bufsiz) \ - __sanitizer_syscall_pre_impl_readlink((long)(path), (long)(buf), \ +#define __sanitizer_syscall_pre_readlink(path, buf, bufsiz) \ + __sanitizer_syscall_pre_impl_readlink((long)(path), (long)(buf), \ (long)(bufsiz)) -#define __sanitizer_syscall_post_readlink(res, path, buf, bufsiz) \ - __sanitizer_syscall_post_impl_readlink(res, (long)(path), (long)(buf), \ +#define __sanitizer_syscall_post_readlink(res, path, buf, bufsiz) \ + __sanitizer_syscall_post_impl_readlink(res, (long)(path), (long)(buf), \ (long)(bufsiz)) -#define __sanitizer_syscall_pre_creat(pathname, mode) \ +#define __sanitizer_syscall_pre_creat(pathname, mode) \ __sanitizer_syscall_pre_impl_creat((long)(pathname), (long)(mode)) -#define __sanitizer_syscall_post_creat(res, pathname, mode) \ +#define __sanitizer_syscall_post_creat(res, pathname, mode) \ __sanitizer_syscall_post_impl_creat(res, (long)(pathname), (long)(mode)) -#define __sanitizer_syscall_pre_open(filename, flags, mode) \ - __sanitizer_syscall_pre_impl_open((long)(filename), (long)(flags), \ +#define __sanitizer_syscall_pre_open(filename, flags, mode) \ + __sanitizer_syscall_pre_impl_open((long)(filename), (long)(flags), \ (long)(mode)) -#define __sanitizer_syscall_post_open(res, filename, flags, mode) \ - __sanitizer_syscall_post_impl_open(res, (long)(filename), (long)(flags), \ +#define __sanitizer_syscall_post_open(res, filename, flags, mode) \ + __sanitizer_syscall_post_impl_open(res, (long)(filename), (long)(flags), \ (long)(mode)) -#define __sanitizer_syscall_pre_close(fd) \ +#define __sanitizer_syscall_pre_close(fd) \ __sanitizer_syscall_pre_impl_close((long)(fd)) -#define __sanitizer_syscall_post_close(res, fd) \ +#define __sanitizer_syscall_post_close(res, fd) \ __sanitizer_syscall_post_impl_close(res, (long)(fd)) -#define __sanitizer_syscall_pre_access(filename, mode) \ +#define __sanitizer_syscall_pre_access(filename, mode) \ __sanitizer_syscall_pre_impl_access((long)(filename), (long)(mode)) -#define __sanitizer_syscall_post_access(res, filename, mode) \ +#define __sanitizer_syscall_post_access(res, filename, mode) \ __sanitizer_syscall_post_impl_access(res, (long)(filename), (long)(mode)) #define __sanitizer_syscall_pre_vhangup() __sanitizer_syscall_pre_impl_vhangup() -#define __sanitizer_syscall_post_vhangup(res) \ +#define __sanitizer_syscall_post_vhangup(res) \ __sanitizer_syscall_post_impl_vhangup(res) -#define __sanitizer_syscall_pre_chown(filename, user, group) \ - __sanitizer_syscall_pre_impl_chown((long)(filename), (long)(user), \ +#define __sanitizer_syscall_pre_chown(filename, user, group) \ + __sanitizer_syscall_pre_impl_chown((long)(filename), (long)(user), \ (long)(group)) -#define __sanitizer_syscall_post_chown(res, filename, user, group) \ - __sanitizer_syscall_post_impl_chown(res, (long)(filename), (long)(user), \ +#define __sanitizer_syscall_post_chown(res, filename, user, group) \ + __sanitizer_syscall_post_impl_chown(res, (long)(filename), (long)(user), \ (long)(group)) -#define __sanitizer_syscall_pre_lchown(filename, user, group) \ - __sanitizer_syscall_pre_impl_lchown((long)(filename), (long)(user), \ +#define __sanitizer_syscall_pre_lchown(filename, user, group) \ + __sanitizer_syscall_pre_impl_lchown((long)(filename), (long)(user), \ (long)(group)) -#define __sanitizer_syscall_post_lchown(res, filename, user, group) \ - __sanitizer_syscall_post_impl_lchown(res, (long)(filename), (long)(user), \ +#define __sanitizer_syscall_post_lchown(res, filename, user, group) \ + __sanitizer_syscall_post_impl_lchown(res, (long)(filename), (long)(user), \ (long)(group)) -#define __sanitizer_syscall_pre_fchown(fd, user, group) \ +#define __sanitizer_syscall_pre_fchown(fd, user, group) \ __sanitizer_syscall_pre_impl_fchown((long)(fd), (long)(user), (long)(group)) -#define __sanitizer_syscall_post_fchown(res, fd, user, group) \ - __sanitizer_syscall_post_impl_fchown(res, (long)(fd), (long)(user), \ +#define __sanitizer_syscall_post_fchown(res, fd, user, group) \ + __sanitizer_syscall_post_impl_fchown(res, (long)(fd), (long)(user), \ (long)(group)) -#define __sanitizer_syscall_pre_chown16(filename, user, group) \ - __sanitizer_syscall_pre_impl_chown16((long)(filename), (long)user, \ +#define __sanitizer_syscall_pre_chown16(filename, user, group) \ + __sanitizer_syscall_pre_impl_chown16((long)(filename), (long)user, \ (long)group) -#define __sanitizer_syscall_post_chown16(res, filename, user, group) \ - __sanitizer_syscall_post_impl_chown16(res, (long)(filename), (long)user, \ +#define __sanitizer_syscall_post_chown16(res, filename, user, group) \ + __sanitizer_syscall_post_impl_chown16(res, (long)(filename), (long)user, \ (long)group) -#define __sanitizer_syscall_pre_lchown16(filename, user, group) \ - __sanitizer_syscall_pre_impl_lchown16((long)(filename), (long)user, \ +#define __sanitizer_syscall_pre_lchown16(filename, user, group) \ + __sanitizer_syscall_pre_impl_lchown16((long)(filename), (long)user, \ (long)group) -#define __sanitizer_syscall_post_lchown16(res, filename, user, group) \ - __sanitizer_syscall_post_impl_lchown16(res, (long)(filename), (long)user, \ +#define __sanitizer_syscall_post_lchown16(res, filename, user, group) \ + __sanitizer_syscall_post_impl_lchown16(res, (long)(filename), (long)user, \ (long)group) -#define __sanitizer_syscall_pre_fchown16(fd, user, group) \ +#define __sanitizer_syscall_pre_fchown16(fd, user, group) \ __sanitizer_syscall_pre_impl_fchown16((long)(fd), (long)user, (long)group) -#define __sanitizer_syscall_post_fchown16(res, fd, user, group) \ - __sanitizer_syscall_post_impl_fchown16(res, (long)(fd), (long)user, \ +#define __sanitizer_syscall_post_fchown16(res, fd, user, group) \ + __sanitizer_syscall_post_impl_fchown16(res, (long)(fd), (long)user, \ (long)group) -#define __sanitizer_syscall_pre_setregid16(rgid, egid) \ +#define __sanitizer_syscall_pre_setregid16(rgid, egid) \ __sanitizer_syscall_pre_impl_setregid16((long)rgid, (long)egid) -#define __sanitizer_syscall_post_setregid16(res, rgid, egid) \ +#define __sanitizer_syscall_post_setregid16(res, rgid, egid) \ __sanitizer_syscall_post_impl_setregid16(res, (long)rgid, (long)egid) -#define __sanitizer_syscall_pre_setgid16(gid) \ +#define __sanitizer_syscall_pre_setgid16(gid) \ __sanitizer_syscall_pre_impl_setgid16((long)gid) -#define __sanitizer_syscall_post_setgid16(res, gid) \ +#define __sanitizer_syscall_post_setgid16(res, gid) \ __sanitizer_syscall_post_impl_setgid16(res, (long)gid) -#define __sanitizer_syscall_pre_setreuid16(ruid, euid) \ +#define __sanitizer_syscall_pre_setreuid16(ruid, euid) \ __sanitizer_syscall_pre_impl_setreuid16((long)ruid, (long)euid) -#define __sanitizer_syscall_post_setreuid16(res, ruid, euid) \ +#define __sanitizer_syscall_post_setreuid16(res, ruid, euid) \ __sanitizer_syscall_post_impl_setreuid16(res, (long)ruid, (long)euid) -#define __sanitizer_syscall_pre_setuid16(uid) \ +#define __sanitizer_syscall_pre_setuid16(uid) \ __sanitizer_syscall_pre_impl_setuid16((long)uid) -#define __sanitizer_syscall_post_setuid16(res, uid) \ +#define __sanitizer_syscall_post_setuid16(res, uid) \ __sanitizer_syscall_post_impl_setuid16(res, (long)uid) -#define __sanitizer_syscall_pre_setresuid16(ruid, euid, suid) \ +#define __sanitizer_syscall_pre_setresuid16(ruid, euid, suid) \ __sanitizer_syscall_pre_impl_setresuid16((long)ruid, (long)euid, (long)suid) -#define __sanitizer_syscall_post_setresuid16(res, ruid, euid, suid) \ - __sanitizer_syscall_post_impl_setresuid16(res, (long)ruid, (long)euid, \ +#define __sanitizer_syscall_post_setresuid16(res, ruid, euid, suid) \ + __sanitizer_syscall_post_impl_setresuid16(res, (long)ruid, (long)euid, \ (long)suid) -#define __sanitizer_syscall_pre_getresuid16(ruid, euid, suid) \ - __sanitizer_syscall_pre_impl_getresuid16((long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_pre_getresuid16(ruid, euid, suid) \ + __sanitizer_syscall_pre_impl_getresuid16((long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_post_getresuid16(res, ruid, euid, suid) \ - __sanitizer_syscall_post_impl_getresuid16(res, (long)(ruid), (long)(euid), \ +#define __sanitizer_syscall_post_getresuid16(res, ruid, euid, suid) \ + __sanitizer_syscall_post_impl_getresuid16(res, (long)(ruid), (long)(euid), \ (long)(suid)) -#define __sanitizer_syscall_pre_setresgid16(rgid, egid, sgid) \ +#define __sanitizer_syscall_pre_setresgid16(rgid, egid, sgid) \ __sanitizer_syscall_pre_impl_setresgid16((long)rgid, (long)egid, (long)sgid) -#define __sanitizer_syscall_post_setresgid16(res, rgid, egid, sgid) \ - __sanitizer_syscall_post_impl_setresgid16(res, (long)rgid, (long)egid, \ +#define __sanitizer_syscall_post_setresgid16(res, rgid, egid, sgid) \ + __sanitizer_syscall_post_impl_setresgid16(res, (long)rgid, (long)egid, \ (long)sgid) -#define __sanitizer_syscall_pre_getresgid16(rgid, egid, sgid) \ - __sanitizer_syscall_pre_impl_getresgid16((long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_pre_getresgid16(rgid, egid, sgid) \ + __sanitizer_syscall_pre_impl_getresgid16((long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_post_getresgid16(res, rgid, egid, sgid) \ - __sanitizer_syscall_post_impl_getresgid16(res, (long)(rgid), (long)(egid), \ +#define __sanitizer_syscall_post_getresgid16(res, rgid, egid, sgid) \ + __sanitizer_syscall_post_impl_getresgid16(res, (long)(rgid), (long)(egid), \ (long)(sgid)) -#define __sanitizer_syscall_pre_setfsuid16(uid) \ +#define __sanitizer_syscall_pre_setfsuid16(uid) \ __sanitizer_syscall_pre_impl_setfsuid16((long)uid) -#define __sanitizer_syscall_post_setfsuid16(res, uid) \ +#define __sanitizer_syscall_post_setfsuid16(res, uid) \ __sanitizer_syscall_post_impl_setfsuid16(res, (long)uid) -#define __sanitizer_syscall_pre_setfsgid16(gid) \ +#define __sanitizer_syscall_pre_setfsgid16(gid) \ __sanitizer_syscall_pre_impl_setfsgid16((long)gid) -#define __sanitizer_syscall_post_setfsgid16(res, gid) \ +#define __sanitizer_syscall_post_setfsgid16(res, gid) \ __sanitizer_syscall_post_impl_setfsgid16(res, (long)gid) -#define __sanitizer_syscall_pre_getgroups16(gidsetsize, grouplist) \ - __sanitizer_syscall_pre_impl_getgroups16((long)(gidsetsize), \ +#define __sanitizer_syscall_pre_getgroups16(gidsetsize, grouplist) \ + __sanitizer_syscall_pre_impl_getgroups16((long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_post_getgroups16(res, gidsetsize, grouplist) \ - __sanitizer_syscall_post_impl_getgroups16(res, (long)(gidsetsize), \ +#define __sanitizer_syscall_post_getgroups16(res, gidsetsize, grouplist) \ + __sanitizer_syscall_post_impl_getgroups16(res, (long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_pre_setgroups16(gidsetsize, grouplist) \ - __sanitizer_syscall_pre_impl_setgroups16((long)(gidsetsize), \ +#define __sanitizer_syscall_pre_setgroups16(gidsetsize, grouplist) \ + __sanitizer_syscall_pre_impl_setgroups16((long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_post_setgroups16(res, gidsetsize, grouplist) \ - __sanitizer_syscall_post_impl_setgroups16(res, (long)(gidsetsize), \ +#define __sanitizer_syscall_post_setgroups16(res, gidsetsize, grouplist) \ + __sanitizer_syscall_post_impl_setgroups16(res, (long)(gidsetsize), \ (long)(grouplist)) -#define __sanitizer_syscall_pre_getuid16() \ +#define __sanitizer_syscall_pre_getuid16() \ __sanitizer_syscall_pre_impl_getuid16() -#define __sanitizer_syscall_post_getuid16(res) \ +#define __sanitizer_syscall_post_getuid16(res) \ __sanitizer_syscall_post_impl_getuid16(res) -#define __sanitizer_syscall_pre_geteuid16() \ +#define __sanitizer_syscall_pre_geteuid16() \ __sanitizer_syscall_pre_impl_geteuid16() -#define __sanitizer_syscall_post_geteuid16(res) \ +#define __sanitizer_syscall_post_geteuid16(res) \ __sanitizer_syscall_post_impl_geteuid16(res) -#define __sanitizer_syscall_pre_getgid16() \ +#define __sanitizer_syscall_pre_getgid16() \ __sanitizer_syscall_pre_impl_getgid16() -#define __sanitizer_syscall_post_getgid16(res) \ +#define __sanitizer_syscall_post_getgid16(res) \ __sanitizer_syscall_post_impl_getgid16(res) -#define __sanitizer_syscall_pre_getegid16() \ +#define __sanitizer_syscall_pre_getegid16() \ __sanitizer_syscall_pre_impl_getegid16() -#define __sanitizer_syscall_post_getegid16(res) \ +#define __sanitizer_syscall_post_getegid16(res) \ __sanitizer_syscall_post_impl_getegid16(res) -#define __sanitizer_syscall_pre_utime(filename, times) \ +#define __sanitizer_syscall_pre_utime(filename, times) \ __sanitizer_syscall_pre_impl_utime((long)(filename), (long)(times)) -#define __sanitizer_syscall_post_utime(res, filename, times) \ +#define __sanitizer_syscall_post_utime(res, filename, times) \ __sanitizer_syscall_post_impl_utime(res, (long)(filename), (long)(times)) -#define __sanitizer_syscall_pre_utimes(filename, utimes) \ +#define __sanitizer_syscall_pre_utimes(filename, utimes) \ __sanitizer_syscall_pre_impl_utimes((long)(filename), (long)(utimes)) -#define __sanitizer_syscall_post_utimes(res, filename, utimes) \ +#define __sanitizer_syscall_post_utimes(res, filename, utimes) \ __sanitizer_syscall_post_impl_utimes(res, (long)(filename), (long)(utimes)) -#define __sanitizer_syscall_pre_lseek(fd, offset, origin) \ +#define __sanitizer_syscall_pre_lseek(fd, offset, origin) \ __sanitizer_syscall_pre_impl_lseek((long)(fd), (long)(offset), (long)(origin)) -#define __sanitizer_syscall_post_lseek(res, fd, offset, origin) \ - __sanitizer_syscall_post_impl_lseek(res, (long)(fd), (long)(offset), \ +#define __sanitizer_syscall_post_lseek(res, fd, offset, origin) \ + __sanitizer_syscall_post_impl_lseek(res, (long)(fd), (long)(offset), \ (long)(origin)) -#define __sanitizer_syscall_pre_llseek(fd, offset_high, offset_low, result, \ - origin) \ - __sanitizer_syscall_pre_impl_llseek((long)(fd), (long)(offset_high), \ - (long)(offset_low), (long)(result), \ +#define __sanitizer_syscall_pre_llseek(fd, offset_high, offset_low, result, \ + origin) \ + __sanitizer_syscall_pre_impl_llseek((long)(fd), (long)(offset_high), \ + (long)(offset_low), (long)(result), \ (long)(origin)) -#define __sanitizer_syscall_post_llseek(res, fd, offset_high, offset_low, \ - result, origin) \ - __sanitizer_syscall_post_impl_llseek(res, (long)(fd), (long)(offset_high), \ - (long)(offset_low), (long)(result), \ +#define __sanitizer_syscall_post_llseek(res, fd, offset_high, offset_low, \ + result, origin) \ + __sanitizer_syscall_post_impl_llseek(res, (long)(fd), (long)(offset_high), \ + (long)(offset_low), (long)(result), \ (long)(origin)) -#define __sanitizer_syscall_pre_read(fd, buf, count) \ +#define __sanitizer_syscall_pre_read(fd, buf, count) \ __sanitizer_syscall_pre_impl_read((long)(fd), (long)(buf), (long)(count)) -#define __sanitizer_syscall_post_read(res, fd, buf, count) \ - __sanitizer_syscall_post_impl_read(res, (long)(fd), (long)(buf), \ +#define __sanitizer_syscall_post_read(res, fd, buf, count) \ + __sanitizer_syscall_post_impl_read(res, (long)(fd), (long)(buf), \ (long)(count)) -#define __sanitizer_syscall_pre_readv(fd, vec, vlen) \ +#define __sanitizer_syscall_pre_readv(fd, vec, vlen) \ __sanitizer_syscall_pre_impl_readv((long)(fd), (long)(vec), (long)(vlen)) -#define __sanitizer_syscall_post_readv(res, fd, vec, vlen) \ - __sanitizer_syscall_post_impl_readv(res, (long)(fd), (long)(vec), \ +#define __sanitizer_syscall_post_readv(res, fd, vec, vlen) \ + __sanitizer_syscall_post_impl_readv(res, (long)(fd), (long)(vec), \ (long)(vlen)) -#define __sanitizer_syscall_pre_write(fd, buf, count) \ +#define __sanitizer_syscall_pre_write(fd, buf, count) \ __sanitizer_syscall_pre_impl_write((long)(fd), (long)(buf), (long)(count)) -#define __sanitizer_syscall_post_write(res, fd, buf, count) \ - __sanitizer_syscall_post_impl_write(res, (long)(fd), (long)(buf), \ +#define __sanitizer_syscall_post_write(res, fd, buf, count) \ + __sanitizer_syscall_post_impl_write(res, (long)(fd), (long)(buf), \ (long)(count)) -#define __sanitizer_syscall_pre_writev(fd, vec, vlen) \ +#define __sanitizer_syscall_pre_writev(fd, vec, vlen) \ __sanitizer_syscall_pre_impl_writev((long)(fd), (long)(vec), (long)(vlen)) -#define __sanitizer_syscall_post_writev(res, fd, vec, vlen) \ - __sanitizer_syscall_post_impl_writev(res, (long)(fd), (long)(vec), \ +#define __sanitizer_syscall_post_writev(res, fd, vec, vlen) \ + __sanitizer_syscall_post_impl_writev(res, (long)(fd), (long)(vec), \ (long)(vlen)) #ifdef _LP64 #define __sanitizer_syscall_pre_pread64(fd, buf, count, pos) \ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \ (long)(pos)) -#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos) \ - __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \ +#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos) \ + __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \ (long)(count), (long)(pos)) -#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos) \ - __sanitizer_syscall_pre_impl_pwrite64((long)(fd), (long)(buf), \ +#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos) \ + __sanitizer_syscall_pre_impl_pwrite64((long)(fd), (long)(buf), \ (long)(count), (long)(pos)) -#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos) \ - __sanitizer_syscall_post_impl_pwrite64(res, (long)(fd), (long)(buf), \ +#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos) \ + __sanitizer_syscall_post_impl_pwrite64(res, (long)(fd), (long)(buf), \ (long)(count), (long)(pos)) #else #define __sanitizer_syscall_pre_pread64(fd, buf, count, pos0, pos1) \ __sanitizer_syscall_pre_impl_pread64((long)(fd), (long)(buf), (long)(count), \ (long)(pos0), (long)(pos1)) -#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \ - __sanitizer_syscall_post_impl_pread64(res, (long)(fd), (long)(buf), \ - (long)(count), (long)(pos0), \ - (long)(pos1)) -#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \ - __sanitizer_syscall_pre_impl_pwrite64( \ +#define __sanitizer_syscall_post_pread64(res, fd, buf, count, pos0, pos1) \ + __sanitizer_syscall_post_impl_pread64( \ + res, (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1)) +#define __sanitizer_syscall_pre_pwrite64(fd, buf, count, pos0, pos1) \ + __sanitizer_syscall_pre_impl_pwrite64( \ (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1)) -#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos0, pos1) \ - __sanitizer_syscall_post_impl_pwrite64( \ +#define __sanitizer_syscall_post_pwrite64(res, fd, buf, count, pos0, pos1) \ + __sanitizer_syscall_post_impl_pwrite64( \ res, (long)(fd), (long)(buf), (long)(count), (long)(pos0), (long)(pos1)) #endif -#define __sanitizer_syscall_pre_preadv(fd, vec, vlen, pos_l, pos_h) \ - __sanitizer_syscall_pre_impl_preadv((long)(fd), (long)(vec), (long)(vlen), \ +#define __sanitizer_syscall_pre_preadv(fd, vec, vlen, pos_l, pos_h) \ + __sanitizer_syscall_pre_impl_preadv((long)(fd), (long)(vec), (long)(vlen), \ (long)(pos_l), (long)(pos_h)) -#define __sanitizer_syscall_post_preadv(res, fd, vec, vlen, pos_l, pos_h) \ - __sanitizer_syscall_post_impl_preadv(res, (long)(fd), (long)(vec), \ - (long)(vlen), (long)(pos_l), \ +#define __sanitizer_syscall_post_preadv(res, fd, vec, vlen, pos_l, pos_h) \ + __sanitizer_syscall_post_impl_preadv(res, (long)(fd), (long)(vec), \ + (long)(vlen), (long)(pos_l), \ (long)(pos_h)) -#define __sanitizer_syscall_pre_pwritev(fd, vec, vlen, pos_l, pos_h) \ - __sanitizer_syscall_pre_impl_pwritev((long)(fd), (long)(vec), (long)(vlen), \ +#define __sanitizer_syscall_pre_pwritev(fd, vec, vlen, pos_l, pos_h) \ + __sanitizer_syscall_pre_impl_pwritev((long)(fd), (long)(vec), (long)(vlen), \ (long)(pos_l), (long)(pos_h)) -#define __sanitizer_syscall_post_pwritev(res, fd, vec, vlen, pos_l, pos_h) \ - __sanitizer_syscall_post_impl_pwritev(res, (long)(fd), (long)(vec), \ - (long)(vlen), (long)(pos_l), \ +#define __sanitizer_syscall_post_pwritev(res, fd, vec, vlen, pos_l, pos_h) \ + __sanitizer_syscall_post_impl_pwritev(res, (long)(fd), (long)(vec), \ + (long)(vlen), (long)(pos_l), \ (long)(pos_h)) -#define __sanitizer_syscall_pre_getcwd(buf, size) \ +#define __sanitizer_syscall_pre_getcwd(buf, size) \ __sanitizer_syscall_pre_impl_getcwd((long)(buf), (long)(size)) -#define __sanitizer_syscall_post_getcwd(res, buf, size) \ +#define __sanitizer_syscall_post_getcwd(res, buf, size) \ __sanitizer_syscall_post_impl_getcwd(res, (long)(buf), (long)(size)) -#define __sanitizer_syscall_pre_mkdir(pathname, mode) \ +#define __sanitizer_syscall_pre_mkdir(pathname, mode) \ __sanitizer_syscall_pre_impl_mkdir((long)(pathname), (long)(mode)) -#define __sanitizer_syscall_post_mkdir(res, pathname, mode) \ +#define __sanitizer_syscall_post_mkdir(res, pathname, mode) \ __sanitizer_syscall_post_impl_mkdir(res, (long)(pathname), (long)(mode)) -#define __sanitizer_syscall_pre_chdir(filename) \ +#define __sanitizer_syscall_pre_chdir(filename) \ __sanitizer_syscall_pre_impl_chdir((long)(filename)) -#define __sanitizer_syscall_post_chdir(res, filename) \ +#define __sanitizer_syscall_post_chdir(res, filename) \ __sanitizer_syscall_post_impl_chdir(res, (long)(filename)) -#define __sanitizer_syscall_pre_fchdir(fd) \ +#define __sanitizer_syscall_pre_fchdir(fd) \ __sanitizer_syscall_pre_impl_fchdir((long)(fd)) -#define __sanitizer_syscall_post_fchdir(res, fd) \ +#define __sanitizer_syscall_post_fchdir(res, fd) \ __sanitizer_syscall_post_impl_fchdir(res, (long)(fd)) -#define __sanitizer_syscall_pre_rmdir(pathname) \ +#define __sanitizer_syscall_pre_rmdir(pathname) \ __sanitizer_syscall_pre_impl_rmdir((long)(pathname)) -#define __sanitizer_syscall_post_rmdir(res, pathname) \ +#define __sanitizer_syscall_post_rmdir(res, pathname) \ __sanitizer_syscall_post_impl_rmdir(res, (long)(pathname)) -#define __sanitizer_syscall_pre_lookup_dcookie(cookie64, buf, len) \ - __sanitizer_syscall_pre_impl_lookup_dcookie((long)(cookie64), (long)(buf), \ +#define __sanitizer_syscall_pre_lookup_dcookie(cookie64, buf, len) \ + __sanitizer_syscall_pre_impl_lookup_dcookie((long)(cookie64), (long)(buf), \ (long)(len)) -#define __sanitizer_syscall_post_lookup_dcookie(res, cookie64, buf, len) \ - __sanitizer_syscall_post_impl_lookup_dcookie(res, (long)(cookie64), \ +#define __sanitizer_syscall_post_lookup_dcookie(res, cookie64, buf, len) \ + __sanitizer_syscall_post_impl_lookup_dcookie(res, (long)(cookie64), \ (long)(buf), (long)(len)) -#define __sanitizer_syscall_pre_quotactl(cmd, special, id, addr) \ - __sanitizer_syscall_pre_impl_quotactl((long)(cmd), (long)(special), \ +#define __sanitizer_syscall_pre_quotactl(cmd, special, id, addr) \ + __sanitizer_syscall_pre_impl_quotactl((long)(cmd), (long)(special), \ (long)(id), (long)(addr)) -#define __sanitizer_syscall_post_quotactl(res, cmd, special, id, addr) \ - __sanitizer_syscall_post_impl_quotactl(res, (long)(cmd), (long)(special), \ +#define __sanitizer_syscall_post_quotactl(res, cmd, special, id, addr) \ + __sanitizer_syscall_post_impl_quotactl(res, (long)(cmd), (long)(special), \ (long)(id), (long)(addr)) -#define __sanitizer_syscall_pre_getdents(fd, dirent, count) \ - __sanitizer_syscall_pre_impl_getdents((long)(fd), (long)(dirent), \ +#define __sanitizer_syscall_pre_getdents(fd, dirent, count) \ + __sanitizer_syscall_pre_impl_getdents((long)(fd), (long)(dirent), \ (long)(count)) -#define __sanitizer_syscall_post_getdents(res, fd, dirent, count) \ - __sanitizer_syscall_post_impl_getdents(res, (long)(fd), (long)(dirent), \ +#define __sanitizer_syscall_post_getdents(res, fd, dirent, count) \ + __sanitizer_syscall_post_impl_getdents(res, (long)(fd), (long)(dirent), \ (long)(count)) -#define __sanitizer_syscall_pre_getdents64(fd, dirent, count) \ - __sanitizer_syscall_pre_impl_getdents64((long)(fd), (long)(dirent), \ +#define __sanitizer_syscall_pre_getdents64(fd, dirent, count) \ + __sanitizer_syscall_pre_impl_getdents64((long)(fd), (long)(dirent), \ (long)(count)) -#define __sanitizer_syscall_post_getdents64(res, fd, dirent, count) \ - __sanitizer_syscall_post_impl_getdents64(res, (long)(fd), (long)(dirent), \ +#define __sanitizer_syscall_post_getdents64(res, fd, dirent, count) \ + __sanitizer_syscall_post_impl_getdents64(res, (long)(fd), (long)(dirent), \ (long)(count)) #define __sanitizer_syscall_pre_setsockopt(fd, level, optname, optval, optlen) \ __sanitizer_syscall_pre_impl_setsockopt((long)(fd), (long)(level), \ (long)(optname), (long)(optval), \ (long)(optlen)) -#define __sanitizer_syscall_post_setsockopt(res, fd, level, optname, optval, \ - optlen) \ - __sanitizer_syscall_post_impl_setsockopt(res, (long)(fd), (long)(level), \ - (long)(optname), (long)(optval), \ +#define __sanitizer_syscall_post_setsockopt(res, fd, level, optname, optval, \ + optlen) \ + __sanitizer_syscall_post_impl_setsockopt(res, (long)(fd), (long)(level), \ + (long)(optname), (long)(optval), \ (long)(optlen)) #define __sanitizer_syscall_pre_getsockopt(fd, level, optname, optval, optlen) \ __sanitizer_syscall_pre_impl_getsockopt((long)(fd), (long)(level), \ (long)(optname), (long)(optval), \ (long)(optlen)) -#define __sanitizer_syscall_post_getsockopt(res, fd, level, optname, optval, \ - optlen) \ - __sanitizer_syscall_post_impl_getsockopt(res, (long)(fd), (long)(level), \ - (long)(optname), (long)(optval), \ +#define __sanitizer_syscall_post_getsockopt(res, fd, level, optname, optval, \ + optlen) \ + __sanitizer_syscall_post_impl_getsockopt(res, (long)(fd), (long)(level), \ + (long)(optname), (long)(optval), \ (long)(optlen)) -#define __sanitizer_syscall_pre_bind(arg0, arg1, arg2) \ +#define __sanitizer_syscall_pre_bind(arg0, arg1, arg2) \ __sanitizer_syscall_pre_impl_bind((long)(arg0), (long)(arg1), (long)(arg2)) -#define __sanitizer_syscall_post_bind(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_bind(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_bind(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_bind(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_connect(arg0, arg1, arg2) \ +#define __sanitizer_syscall_pre_connect(arg0, arg1, arg2) \ __sanitizer_syscall_pre_impl_connect((long)(arg0), (long)(arg1), (long)(arg2)) -#define __sanitizer_syscall_post_connect(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_connect(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_connect(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_connect(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_accept(arg0, arg1, arg2) \ +#define __sanitizer_syscall_pre_accept(arg0, arg1, arg2) \ __sanitizer_syscall_pre_impl_accept((long)(arg0), (long)(arg1), (long)(arg2)) -#define __sanitizer_syscall_post_accept(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_accept(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_accept(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_accept(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_accept4(arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_pre_impl_accept4((long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_pre_accept4(arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_pre_impl_accept4((long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_post_accept4(res, arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_post_impl_accept4(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_accept4(res, arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_post_impl_accept4(res, (long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_pre_getsockname(arg0, arg1, arg2) \ - __sanitizer_syscall_pre_impl_getsockname((long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_pre_getsockname(arg0, arg1, arg2) \ + __sanitizer_syscall_pre_impl_getsockname((long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_post_getsockname(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_getsockname(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_getsockname(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_getsockname(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_getpeername(arg0, arg1, arg2) \ - __sanitizer_syscall_pre_impl_getpeername((long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_pre_getpeername(arg0, arg1, arg2) \ + __sanitizer_syscall_pre_impl_getpeername((long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_post_getpeername(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_getpeername(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_getpeername(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_getpeername(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_send(arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_pre_impl_send((long)(arg0), (long)(arg1), (long)(arg2), \ +#define __sanitizer_syscall_pre_send(arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_pre_impl_send((long)(arg0), (long)(arg1), (long)(arg2), \ (long)(arg3)) -#define __sanitizer_syscall_post_send(res, arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_post_impl_send(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_send(res, arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_post_impl_send(res, (long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_pre_sendto(arg0, arg1, arg2, arg3, arg4, arg5) \ - __sanitizer_syscall_pre_impl_sendto((long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_pre_sendto(arg0, arg1, arg2, arg3, arg4, arg5) \ + __sanitizer_syscall_pre_impl_sendto((long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_post_sendto(res, arg0, arg1, arg2, arg3, arg4, \ - arg5) \ - __sanitizer_syscall_post_impl_sendto(res, (long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_post_sendto(res, arg0, arg1, arg2, arg3, arg4, \ + arg5) \ + __sanitizer_syscall_post_impl_sendto(res, (long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_pre_sendmsg(fd, msg, flags) \ +#define __sanitizer_syscall_pre_sendmsg(fd, msg, flags) \ __sanitizer_syscall_pre_impl_sendmsg((long)(fd), (long)(msg), (long)(flags)) -#define __sanitizer_syscall_post_sendmsg(res, fd, msg, flags) \ - __sanitizer_syscall_post_impl_sendmsg(res, (long)(fd), (long)(msg), \ +#define __sanitizer_syscall_post_sendmsg(res, fd, msg, flags) \ + __sanitizer_syscall_post_impl_sendmsg(res, (long)(fd), (long)(msg), \ (long)(flags)) #define __sanitizer_syscall_pre_sendmmsg(fd, msg, vlen, flags) \ __sanitizer_syscall_pre_impl_sendmmsg((long)(fd), (long)(msg), (long)(vlen), \ (long)(flags)) -#define __sanitizer_syscall_post_sendmmsg(res, fd, msg, vlen, flags) \ - __sanitizer_syscall_post_impl_sendmmsg(res, (long)(fd), (long)(msg), \ +#define __sanitizer_syscall_post_sendmmsg(res, fd, msg, vlen, flags) \ + __sanitizer_syscall_post_impl_sendmmsg(res, (long)(fd), (long)(msg), \ (long)(vlen), (long)(flags)) -#define __sanitizer_syscall_pre_recv(arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_pre_impl_recv((long)(arg0), (long)(arg1), (long)(arg2), \ +#define __sanitizer_syscall_pre_recv(arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_pre_impl_recv((long)(arg0), (long)(arg1), (long)(arg2), \ (long)(arg3)) -#define __sanitizer_syscall_post_recv(res, arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_post_impl_recv(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_recv(res, arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_post_impl_recv(res, (long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_pre_recvfrom(arg0, arg1, arg2, arg3, arg4, arg5) \ - __sanitizer_syscall_pre_impl_recvfrom((long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_pre_recvfrom(arg0, arg1, arg2, arg3, arg4, arg5) \ + __sanitizer_syscall_pre_impl_recvfrom((long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_post_recvfrom(res, arg0, arg1, arg2, arg3, arg4, \ - arg5) \ - __sanitizer_syscall_post_impl_recvfrom(res, (long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_post_recvfrom(res, arg0, arg1, arg2, arg3, arg4, \ + arg5) \ + __sanitizer_syscall_post_impl_recvfrom(res, (long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_pre_recvmsg(fd, msg, flags) \ +#define __sanitizer_syscall_pre_recvmsg(fd, msg, flags) \ __sanitizer_syscall_pre_impl_recvmsg((long)(fd), (long)(msg), (long)(flags)) -#define __sanitizer_syscall_post_recvmsg(res, fd, msg, flags) \ - __sanitizer_syscall_post_impl_recvmsg(res, (long)(fd), (long)(msg), \ +#define __sanitizer_syscall_post_recvmsg(res, fd, msg, flags) \ + __sanitizer_syscall_post_impl_recvmsg(res, (long)(fd), (long)(msg), \ (long)(flags)) #define __sanitizer_syscall_pre_recvmmsg(fd, msg, vlen, flags, timeout) \ __sanitizer_syscall_pre_impl_recvmmsg((long)(fd), (long)(msg), (long)(vlen), \ (long)(flags), (long)(timeout)) -#define __sanitizer_syscall_post_recvmmsg(res, fd, msg, vlen, flags, timeout) \ - __sanitizer_syscall_post_impl_recvmmsg(res, (long)(fd), (long)(msg), \ - (long)(vlen), (long)(flags), \ +#define __sanitizer_syscall_post_recvmmsg(res, fd, msg, vlen, flags, timeout) \ + __sanitizer_syscall_post_impl_recvmmsg(res, (long)(fd), (long)(msg), \ + (long)(vlen), (long)(flags), \ (long)(timeout)) -#define __sanitizer_syscall_pre_socket(arg0, arg1, arg2) \ +#define __sanitizer_syscall_pre_socket(arg0, arg1, arg2) \ __sanitizer_syscall_pre_impl_socket((long)(arg0), (long)(arg1), (long)(arg2)) -#define __sanitizer_syscall_post_socket(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_socket(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_socket(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_socket(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_socketpair(arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_pre_impl_socketpair((long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_pre_socketpair(arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_pre_impl_socketpair((long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_post_socketpair(res, arg0, arg1, arg2, arg3) \ - __sanitizer_syscall_post_impl_socketpair(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_socketpair(res, arg0, arg1, arg2, arg3) \ + __sanitizer_syscall_post_impl_socketpair(res, (long)(arg0), (long)(arg1), \ (long)(arg2), (long)(arg3)) -#define __sanitizer_syscall_pre_socketcall(call, args) \ +#define __sanitizer_syscall_pre_socketcall(call, args) \ __sanitizer_syscall_pre_impl_socketcall((long)(call), (long)(args)) -#define __sanitizer_syscall_post_socketcall(res, call, args) \ +#define __sanitizer_syscall_post_socketcall(res, call, args) \ __sanitizer_syscall_post_impl_socketcall(res, (long)(call), (long)(args)) -#define __sanitizer_syscall_pre_listen(arg0, arg1) \ +#define __sanitizer_syscall_pre_listen(arg0, arg1) \ __sanitizer_syscall_pre_impl_listen((long)(arg0), (long)(arg1)) -#define __sanitizer_syscall_post_listen(res, arg0, arg1) \ +#define __sanitizer_syscall_post_listen(res, arg0, arg1) \ __sanitizer_syscall_post_impl_listen(res, (long)(arg0), (long)(arg1)) -#define __sanitizer_syscall_pre_poll(ufds, nfds, timeout) \ +#define __sanitizer_syscall_pre_poll(ufds, nfds, timeout) \ __sanitizer_syscall_pre_impl_poll((long)(ufds), (long)(nfds), (long)(timeout)) -#define __sanitizer_syscall_post_poll(res, ufds, nfds, timeout) \ - __sanitizer_syscall_post_impl_poll(res, (long)(ufds), (long)(nfds), \ +#define __sanitizer_syscall_post_poll(res, ufds, nfds, timeout) \ + __sanitizer_syscall_post_impl_poll(res, (long)(ufds), (long)(nfds), \ (long)(timeout)) -#define __sanitizer_syscall_pre_select(n, inp, outp, exp, tvp) \ - __sanitizer_syscall_pre_impl_select((long)(n), (long)(inp), (long)(outp), \ +#define __sanitizer_syscall_pre_select(n, inp, outp, exp, tvp) \ + __sanitizer_syscall_pre_impl_select((long)(n), (long)(inp), (long)(outp), \ (long)(exp), (long)(tvp)) -#define __sanitizer_syscall_post_select(res, n, inp, outp, exp, tvp) \ - __sanitizer_syscall_post_impl_select(res, (long)(n), (long)(inp), \ +#define __sanitizer_syscall_post_select(res, n, inp, outp, exp, tvp) \ + __sanitizer_syscall_post_impl_select(res, (long)(n), (long)(inp), \ (long)(outp), (long)(exp), (long)(tvp)) -#define __sanitizer_syscall_pre_old_select(arg) \ +#define __sanitizer_syscall_pre_old_select(arg) \ __sanitizer_syscall_pre_impl_old_select((long)(arg)) -#define __sanitizer_syscall_post_old_select(res, arg) \ +#define __sanitizer_syscall_post_old_select(res, arg) \ __sanitizer_syscall_post_impl_old_select(res, (long)(arg)) -#define __sanitizer_syscall_pre_epoll_create(size) \ +#define __sanitizer_syscall_pre_epoll_create(size) \ __sanitizer_syscall_pre_impl_epoll_create((long)(size)) -#define __sanitizer_syscall_post_epoll_create(res, size) \ +#define __sanitizer_syscall_post_epoll_create(res, size) \ __sanitizer_syscall_post_impl_epoll_create(res, (long)(size)) -#define __sanitizer_syscall_pre_epoll_create1(flags) \ +#define __sanitizer_syscall_pre_epoll_create1(flags) \ __sanitizer_syscall_pre_impl_epoll_create1((long)(flags)) -#define __sanitizer_syscall_post_epoll_create1(res, flags) \ +#define __sanitizer_syscall_post_epoll_create1(res, flags) \ __sanitizer_syscall_post_impl_epoll_create1(res, (long)(flags)) #define __sanitizer_syscall_pre_epoll_ctl(epfd, op, fd, event) \ __sanitizer_syscall_pre_impl_epoll_ctl((long)(epfd), (long)(op), (long)(fd), \ (long)(event)) -#define __sanitizer_syscall_post_epoll_ctl(res, epfd, op, fd, event) \ - __sanitizer_syscall_post_impl_epoll_ctl(res, (long)(epfd), (long)(op), \ +#define __sanitizer_syscall_post_epoll_ctl(res, epfd, op, fd, event) \ + __sanitizer_syscall_post_impl_epoll_ctl(res, (long)(epfd), (long)(op), \ (long)(fd), (long)(event)) -#define __sanitizer_syscall_pre_epoll_wait(epfd, events, maxevents, timeout) \ - __sanitizer_syscall_pre_impl_epoll_wait((long)(epfd), (long)(events), \ +#define __sanitizer_syscall_pre_epoll_wait(epfd, events, maxevents, timeout) \ + __sanitizer_syscall_pre_impl_epoll_wait((long)(epfd), (long)(events), \ (long)(maxevents), (long)(timeout)) -#define __sanitizer_syscall_post_epoll_wait(res, epfd, events, maxevents, \ - timeout) \ - __sanitizer_syscall_post_impl_epoll_wait(res, (long)(epfd), (long)(events), \ +#define __sanitizer_syscall_post_epoll_wait(res, epfd, events, maxevents, \ + timeout) \ + __sanitizer_syscall_post_impl_epoll_wait(res, (long)(epfd), (long)(events), \ (long)(maxevents), (long)(timeout)) -#define __sanitizer_syscall_pre_epoll_pwait(epfd, events, maxevents, timeout, \ - sigmask, sigsetsize) \ - __sanitizer_syscall_pre_impl_epoll_pwait( \ - (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ +#define __sanitizer_syscall_pre_epoll_pwait(epfd, events, maxevents, timeout, \ + sigmask, sigsetsize) \ + __sanitizer_syscall_pre_impl_epoll_pwait( \ + (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ (long)(sigmask), (long)(sigsetsize)) -#define __sanitizer_syscall_post_epoll_pwait(res, epfd, events, maxevents, \ - timeout, sigmask, sigsetsize) \ - __sanitizer_syscall_post_impl_epoll_pwait( \ - res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ +#define __sanitizer_syscall_post_epoll_pwait(res, epfd, events, maxevents, \ + timeout, sigmask, sigsetsize) \ + __sanitizer_syscall_post_impl_epoll_pwait( \ + res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ (long)(sigmask), (long)(sigsetsize)) -#define __sanitizer_syscall_pre_gethostname(name, len) \ +#define __sanitizer_syscall_pre_epoll_pwait2(epfd, events, maxevents, timeout, \ + sigmask, sigsetsize) \ + __sanitizer_syscall_pre_impl_epoll_pwait2( \ + (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ + (long)(sigmask), (long)(sigsetsize)) +#define __sanitizer_syscall_post_epoll_pwait2(res, epfd, events, maxevents, \ + timeout, sigmask, sigsetsize) \ + __sanitizer_syscall_post_impl_epoll_pwait2( \ + res, (long)(epfd), (long)(events), (long)(maxevents), (long)(timeout), \ + (long)(sigmask), (long)(sigsetsize)) +#define __sanitizer_syscall_pre_gethostname(name, len) \ __sanitizer_syscall_pre_impl_gethostname((long)(name), (long)(len)) -#define __sanitizer_syscall_post_gethostname(res, name, len) \ +#define __sanitizer_syscall_post_gethostname(res, name, len) \ __sanitizer_syscall_post_impl_gethostname(res, (long)(name), (long)(len)) -#define __sanitizer_syscall_pre_sethostname(name, len) \ +#define __sanitizer_syscall_pre_sethostname(name, len) \ __sanitizer_syscall_pre_impl_sethostname((long)(name), (long)(len)) -#define __sanitizer_syscall_post_sethostname(res, name, len) \ +#define __sanitizer_syscall_post_sethostname(res, name, len) \ __sanitizer_syscall_post_impl_sethostname(res, (long)(name), (long)(len)) -#define __sanitizer_syscall_pre_setdomainname(name, len) \ +#define __sanitizer_syscall_pre_setdomainname(name, len) \ __sanitizer_syscall_pre_impl_setdomainname((long)(name), (long)(len)) -#define __sanitizer_syscall_post_setdomainname(res, name, len) \ +#define __sanitizer_syscall_post_setdomainname(res, name, len) \ __sanitizer_syscall_post_impl_setdomainname(res, (long)(name), (long)(len)) -#define __sanitizer_syscall_pre_newuname(name) \ +#define __sanitizer_syscall_pre_newuname(name) \ __sanitizer_syscall_pre_impl_newuname((long)(name)) -#define __sanitizer_syscall_post_newuname(res, name) \ +#define __sanitizer_syscall_post_newuname(res, name) \ __sanitizer_syscall_post_impl_newuname(res, (long)(name)) -#define __sanitizer_syscall_pre_uname(arg0) \ +#define __sanitizer_syscall_pre_uname(arg0) \ __sanitizer_syscall_pre_impl_uname((long)(arg0)) -#define __sanitizer_syscall_post_uname(res, arg0) \ +#define __sanitizer_syscall_post_uname(res, arg0) \ __sanitizer_syscall_post_impl_uname(res, (long)(arg0)) -#define __sanitizer_syscall_pre_olduname(arg0) \ +#define __sanitizer_syscall_pre_olduname(arg0) \ __sanitizer_syscall_pre_impl_olduname((long)(arg0)) -#define __sanitizer_syscall_post_olduname(res, arg0) \ +#define __sanitizer_syscall_post_olduname(res, arg0) \ __sanitizer_syscall_post_impl_olduname(res, (long)(arg0)) -#define __sanitizer_syscall_pre_getrlimit(resource, rlim) \ +#define __sanitizer_syscall_pre_getrlimit(resource, rlim) \ __sanitizer_syscall_pre_impl_getrlimit((long)(resource), (long)(rlim)) -#define __sanitizer_syscall_post_getrlimit(res, resource, rlim) \ +#define __sanitizer_syscall_post_getrlimit(res, resource, rlim) \ __sanitizer_syscall_post_impl_getrlimit(res, (long)(resource), (long)(rlim)) -#define __sanitizer_syscall_pre_old_getrlimit(resource, rlim) \ +#define __sanitizer_syscall_pre_old_getrlimit(resource, rlim) \ __sanitizer_syscall_pre_impl_old_getrlimit((long)(resource), (long)(rlim)) -#define __sanitizer_syscall_post_old_getrlimit(res, resource, rlim) \ - __sanitizer_syscall_post_impl_old_getrlimit(res, (long)(resource), \ +#define __sanitizer_syscall_post_old_getrlimit(res, resource, rlim) \ + __sanitizer_syscall_post_impl_old_getrlimit(res, (long)(resource), \ (long)(rlim)) -#define __sanitizer_syscall_pre_setrlimit(resource, rlim) \ +#define __sanitizer_syscall_pre_setrlimit(resource, rlim) \ __sanitizer_syscall_pre_impl_setrlimit((long)(resource), (long)(rlim)) -#define __sanitizer_syscall_post_setrlimit(res, resource, rlim) \ +#define __sanitizer_syscall_post_setrlimit(res, resource, rlim) \ __sanitizer_syscall_post_impl_setrlimit(res, (long)(resource), (long)(rlim)) -#define __sanitizer_syscall_pre_prlimit64(pid, resource, new_rlim, old_rlim) \ - __sanitizer_syscall_pre_impl_prlimit64((long)(pid), (long)(resource), \ +#define __sanitizer_syscall_pre_prlimit64(pid, resource, new_rlim, old_rlim) \ + __sanitizer_syscall_pre_impl_prlimit64((long)(pid), (long)(resource), \ (long)(new_rlim), (long)(old_rlim)) -#define __sanitizer_syscall_post_prlimit64(res, pid, resource, new_rlim, \ - old_rlim) \ - __sanitizer_syscall_post_impl_prlimit64(res, (long)(pid), (long)(resource), \ +#define __sanitizer_syscall_post_prlimit64(res, pid, resource, new_rlim, \ + old_rlim) \ + __sanitizer_syscall_post_impl_prlimit64(res, (long)(pid), (long)(resource), \ (long)(new_rlim), (long)(old_rlim)) -#define __sanitizer_syscall_pre_getrusage(who, ru) \ +#define __sanitizer_syscall_pre_getrusage(who, ru) \ __sanitizer_syscall_pre_impl_getrusage((long)(who), (long)(ru)) -#define __sanitizer_syscall_post_getrusage(res, who, ru) \ +#define __sanitizer_syscall_post_getrusage(res, who, ru) \ __sanitizer_syscall_post_impl_getrusage(res, (long)(who), (long)(ru)) -#define __sanitizer_syscall_pre_umask(mask) \ +#define __sanitizer_syscall_pre_umask(mask) \ __sanitizer_syscall_pre_impl_umask((long)(mask)) -#define __sanitizer_syscall_post_umask(res, mask) \ +#define __sanitizer_syscall_post_umask(res, mask) \ __sanitizer_syscall_post_impl_umask(res, (long)(mask)) -#define __sanitizer_syscall_pre_msgget(key, msgflg) \ +#define __sanitizer_syscall_pre_msgget(key, msgflg) \ __sanitizer_syscall_pre_impl_msgget((long)(key), (long)(msgflg)) -#define __sanitizer_syscall_post_msgget(res, key, msgflg) \ +#define __sanitizer_syscall_post_msgget(res, key, msgflg) \ __sanitizer_syscall_post_impl_msgget(res, (long)(key), (long)(msgflg)) -#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg) \ - __sanitizer_syscall_pre_impl_msgsnd((long)(msqid), (long)(msgp), \ +#define __sanitizer_syscall_pre_msgsnd(msqid, msgp, msgsz, msgflg) \ + __sanitizer_syscall_pre_impl_msgsnd((long)(msqid), (long)(msgp), \ (long)(msgsz), (long)(msgflg)) -#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg) \ - __sanitizer_syscall_post_impl_msgsnd(res, (long)(msqid), (long)(msgp), \ +#define __sanitizer_syscall_post_msgsnd(res, msqid, msgp, msgsz, msgflg) \ + __sanitizer_syscall_post_impl_msgsnd(res, (long)(msqid), (long)(msgp), \ (long)(msgsz), (long)(msgflg)) -#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) \ - __sanitizer_syscall_pre_impl_msgrcv((long)(msqid), (long)(msgp), \ - (long)(msgsz), (long)(msgtyp), \ +#define __sanitizer_syscall_pre_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg) \ + __sanitizer_syscall_pre_impl_msgrcv((long)(msqid), (long)(msgp), \ + (long)(msgsz), (long)(msgtyp), \ (long)(msgflg)) -#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp, \ - msgflg) \ - __sanitizer_syscall_post_impl_msgrcv(res, (long)(msqid), (long)(msgp), \ - (long)(msgsz), (long)(msgtyp), \ +#define __sanitizer_syscall_post_msgrcv(res, msqid, msgp, msgsz, msgtyp, \ + msgflg) \ + __sanitizer_syscall_post_impl_msgrcv(res, (long)(msqid), (long)(msgp), \ + (long)(msgsz), (long)(msgtyp), \ (long)(msgflg)) -#define __sanitizer_syscall_pre_msgctl(msqid, cmd, buf) \ +#define __sanitizer_syscall_pre_msgctl(msqid, cmd, buf) \ __sanitizer_syscall_pre_impl_msgctl((long)(msqid), (long)(cmd), (long)(buf)) -#define __sanitizer_syscall_post_msgctl(res, msqid, cmd, buf) \ - __sanitizer_syscall_post_impl_msgctl(res, (long)(msqid), (long)(cmd), \ +#define __sanitizer_syscall_post_msgctl(res, msqid, cmd, buf) \ + __sanitizer_syscall_post_impl_msgctl(res, (long)(msqid), (long)(cmd), \ (long)(buf)) -#define __sanitizer_syscall_pre_semget(key, nsems, semflg) \ - __sanitizer_syscall_pre_impl_semget((long)(key), (long)(nsems), \ +#define __sanitizer_syscall_pre_semget(key, nsems, semflg) \ + __sanitizer_syscall_pre_impl_semget((long)(key), (long)(nsems), \ (long)(semflg)) -#define __sanitizer_syscall_post_semget(res, key, nsems, semflg) \ - __sanitizer_syscall_post_impl_semget(res, (long)(key), (long)(nsems), \ +#define __sanitizer_syscall_post_semget(res, key, nsems, semflg) \ + __sanitizer_syscall_post_impl_semget(res, (long)(key), (long)(nsems), \ (long)(semflg)) -#define __sanitizer_syscall_pre_semop(semid, sops, nsops) \ +#define __sanitizer_syscall_pre_semop(semid, sops, nsops) \ __sanitizer_syscall_pre_impl_semop((long)(semid), (long)(sops), (long)(nsops)) -#define __sanitizer_syscall_post_semop(res, semid, sops, nsops) \ - __sanitizer_syscall_post_impl_semop(res, (long)(semid), (long)(sops), \ +#define __sanitizer_syscall_post_semop(res, semid, sops, nsops) \ + __sanitizer_syscall_post_impl_semop(res, (long)(semid), (long)(sops), \ (long)(nsops)) -#define __sanitizer_syscall_pre_semctl(semid, semnum, cmd, arg) \ - __sanitizer_syscall_pre_impl_semctl((long)(semid), (long)(semnum), \ +#define __sanitizer_syscall_pre_semctl(semid, semnum, cmd, arg) \ + __sanitizer_syscall_pre_impl_semctl((long)(semid), (long)(semnum), \ (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_post_semctl(res, semid, semnum, cmd, arg) \ - __sanitizer_syscall_post_impl_semctl(res, (long)(semid), (long)(semnum), \ +#define __sanitizer_syscall_post_semctl(res, semid, semnum, cmd, arg) \ + __sanitizer_syscall_post_impl_semctl(res, (long)(semid), (long)(semnum), \ (long)(cmd), (long)(arg)) -#define __sanitizer_syscall_pre_semtimedop(semid, sops, nsops, timeout) \ - __sanitizer_syscall_pre_impl_semtimedop((long)(semid), (long)(sops), \ +#define __sanitizer_syscall_pre_semtimedop(semid, sops, nsops, timeout) \ + __sanitizer_syscall_pre_impl_semtimedop((long)(semid), (long)(sops), \ (long)(nsops), (long)(timeout)) -#define __sanitizer_syscall_post_semtimedop(res, semid, sops, nsops, timeout) \ - __sanitizer_syscall_post_impl_semtimedop(res, (long)(semid), (long)(sops), \ +#define __sanitizer_syscall_post_semtimedop(res, semid, sops, nsops, timeout) \ + __sanitizer_syscall_post_impl_semtimedop(res, (long)(semid), (long)(sops), \ (long)(nsops), (long)(timeout)) -#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg) \ - __sanitizer_syscall_pre_impl_shmat((long)(shmid), (long)(shmaddr), \ +#define __sanitizer_syscall_pre_shmat(shmid, shmaddr, shmflg) \ + __sanitizer_syscall_pre_impl_shmat((long)(shmid), (long)(shmaddr), \ (long)(shmflg)) -#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg) \ - __sanitizer_syscall_post_impl_shmat(res, (long)(shmid), (long)(shmaddr), \ +#define __sanitizer_syscall_post_shmat(res, shmid, shmaddr, shmflg) \ + __sanitizer_syscall_post_impl_shmat(res, (long)(shmid), (long)(shmaddr), \ (long)(shmflg)) -#define __sanitizer_syscall_pre_shmget(key, size, flag) \ +#define __sanitizer_syscall_pre_shmget(key, size, flag) \ __sanitizer_syscall_pre_impl_shmget((long)(key), (long)(size), (long)(flag)) -#define __sanitizer_syscall_post_shmget(res, key, size, flag) \ - __sanitizer_syscall_post_impl_shmget(res, (long)(key), (long)(size), \ +#define __sanitizer_syscall_post_shmget(res, key, size, flag) \ + __sanitizer_syscall_post_impl_shmget(res, (long)(key), (long)(size), \ (long)(flag)) -#define __sanitizer_syscall_pre_shmdt(shmaddr) \ +#define __sanitizer_syscall_pre_shmdt(shmaddr) \ __sanitizer_syscall_pre_impl_shmdt((long)(shmaddr)) -#define __sanitizer_syscall_post_shmdt(res, shmaddr) \ +#define __sanitizer_syscall_post_shmdt(res, shmaddr) \ __sanitizer_syscall_post_impl_shmdt(res, (long)(shmaddr)) -#define __sanitizer_syscall_pre_shmctl(shmid, cmd, buf) \ +#define __sanitizer_syscall_pre_shmctl(shmid, cmd, buf) \ __sanitizer_syscall_pre_impl_shmctl((long)(shmid), (long)(cmd), (long)(buf)) -#define __sanitizer_syscall_post_shmctl(res, shmid, cmd, buf) \ - __sanitizer_syscall_post_impl_shmctl(res, (long)(shmid), (long)(cmd), \ +#define __sanitizer_syscall_post_shmctl(res, shmid, cmd, buf) \ + __sanitizer_syscall_post_impl_shmctl(res, (long)(shmid), (long)(cmd), \ (long)(buf)) #define __sanitizer_syscall_pre_ipc(call, first, second, third, ptr, fifth) \ __sanitizer_syscall_pre_impl_ipc((long)(call), (long)(first), \ (long)(second), (long)(third), (long)(ptr), \ (long)(fifth)) -#define __sanitizer_syscall_post_ipc(res, call, first, second, third, ptr, \ - fifth) \ - __sanitizer_syscall_post_impl_ipc(res, (long)(call), (long)(first), \ - (long)(second), (long)(third), \ +#define __sanitizer_syscall_post_ipc(res, call, first, second, third, ptr, \ + fifth) \ + __sanitizer_syscall_post_impl_ipc(res, (long)(call), (long)(first), \ + (long)(second), (long)(third), \ (long)(ptr), (long)(fifth)) -#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr) \ - __sanitizer_syscall_pre_impl_mq_open((long)(name), (long)(oflag), \ +#define __sanitizer_syscall_pre_mq_open(name, oflag, mode, attr) \ + __sanitizer_syscall_pre_impl_mq_open((long)(name), (long)(oflag), \ (long)(mode), (long)(attr)) -#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr) \ - __sanitizer_syscall_post_impl_mq_open(res, (long)(name), (long)(oflag), \ +#define __sanitizer_syscall_post_mq_open(res, name, oflag, mode, attr) \ + __sanitizer_syscall_post_impl_mq_open(res, (long)(name), (long)(oflag), \ (long)(mode), (long)(attr)) -#define __sanitizer_syscall_pre_mq_unlink(name) \ +#define __sanitizer_syscall_pre_mq_unlink(name) \ __sanitizer_syscall_pre_impl_mq_unlink((long)(name)) -#define __sanitizer_syscall_post_mq_unlink(res, name) \ +#define __sanitizer_syscall_post_mq_unlink(res, name) \ __sanitizer_syscall_post_impl_mq_unlink(res, (long)(name)) #define __sanitizer_syscall_pre_mq_timedsend(mqdes, msg_ptr, msg_len, \ msg_prio, abs_timeout) \ __sanitizer_syscall_pre_impl_mq_timedsend((long)(mqdes), (long)(msg_ptr), \ (long)(msg_len), (long)(msg_prio), \ (long)(abs_timeout)) -#define __sanitizer_syscall_post_mq_timedsend(res, mqdes, msg_ptr, msg_len, \ - msg_prio, abs_timeout) \ - __sanitizer_syscall_post_impl_mq_timedsend( \ - res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \ +#define __sanitizer_syscall_post_mq_timedsend(res, mqdes, msg_ptr, msg_len, \ + msg_prio, abs_timeout) \ + __sanitizer_syscall_post_impl_mq_timedsend( \ + res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \ (long)(abs_timeout)) -#define __sanitizer_syscall_pre_mq_timedreceive(mqdes, msg_ptr, msg_len, \ - msg_prio, abs_timeout) \ - __sanitizer_syscall_pre_impl_mq_timedreceive( \ - (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \ +#define __sanitizer_syscall_pre_mq_timedreceive(mqdes, msg_ptr, msg_len, \ + msg_prio, abs_timeout) \ + __sanitizer_syscall_pre_impl_mq_timedreceive( \ + (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \ (long)(abs_timeout)) #define __sanitizer_syscall_post_mq_timedreceive(res, mqdes, msg_ptr, msg_len, \ msg_prio, abs_timeout) \ __sanitizer_syscall_post_impl_mq_timedreceive( \ res, (long)(mqdes), (long)(msg_ptr), (long)(msg_len), (long)(msg_prio), \ (long)(abs_timeout)) -#define __sanitizer_syscall_pre_mq_notify(mqdes, notification) \ +#define __sanitizer_syscall_pre_mq_notify(mqdes, notification) \ __sanitizer_syscall_pre_impl_mq_notify((long)(mqdes), (long)(notification)) -#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification) \ - __sanitizer_syscall_post_impl_mq_notify(res, (long)(mqdes), \ +#define __sanitizer_syscall_post_mq_notify(res, mqdes, notification) \ + __sanitizer_syscall_post_impl_mq_notify(res, (long)(mqdes), \ (long)(notification)) -#define __sanitizer_syscall_pre_mq_getsetattr(mqdes, mqstat, omqstat) \ - __sanitizer_syscall_pre_impl_mq_getsetattr((long)(mqdes), (long)(mqstat), \ +#define __sanitizer_syscall_pre_mq_getsetattr(mqdes, mqstat, omqstat) \ + __sanitizer_syscall_pre_impl_mq_getsetattr((long)(mqdes), (long)(mqstat), \ (long)(omqstat)) -#define __sanitizer_syscall_post_mq_getsetattr(res, mqdes, mqstat, omqstat) \ - __sanitizer_syscall_post_impl_mq_getsetattr(res, (long)(mqdes), \ +#define __sanitizer_syscall_post_mq_getsetattr(res, mqdes, mqstat, omqstat) \ + __sanitizer_syscall_post_impl_mq_getsetattr(res, (long)(mqdes), \ (long)(mqstat), (long)(omqstat)) -#define __sanitizer_syscall_pre_pciconfig_iobase(which, bus, devfn) \ - __sanitizer_syscall_pre_impl_pciconfig_iobase((long)(which), (long)(bus), \ +#define __sanitizer_syscall_pre_pciconfig_iobase(which, bus, devfn) \ + __sanitizer_syscall_pre_impl_pciconfig_iobase((long)(which), (long)(bus), \ (long)(devfn)) -#define __sanitizer_syscall_post_pciconfig_iobase(res, which, bus, devfn) \ - __sanitizer_syscall_post_impl_pciconfig_iobase(res, (long)(which), \ +#define __sanitizer_syscall_post_pciconfig_iobase(res, which, bus, devfn) \ + __sanitizer_syscall_post_impl_pciconfig_iobase(res, (long)(which), \ (long)(bus), (long)(devfn)) -#define __sanitizer_syscall_pre_pciconfig_read(bus, dfn, off, len, buf) \ - __sanitizer_syscall_pre_impl_pciconfig_read( \ +#define __sanitizer_syscall_pre_pciconfig_read(bus, dfn, off, len, buf) \ + __sanitizer_syscall_pre_impl_pciconfig_read( \ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf)) -#define __sanitizer_syscall_post_pciconfig_read(res, bus, dfn, off, len, buf) \ - __sanitizer_syscall_post_impl_pciconfig_read( \ +#define __sanitizer_syscall_post_pciconfig_read(res, bus, dfn, off, len, buf) \ + __sanitizer_syscall_post_impl_pciconfig_read( \ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf)) -#define __sanitizer_syscall_pre_pciconfig_write(bus, dfn, off, len, buf) \ - __sanitizer_syscall_pre_impl_pciconfig_write( \ +#define __sanitizer_syscall_pre_pciconfig_write(bus, dfn, off, len, buf) \ + __sanitizer_syscall_pre_impl_pciconfig_write( \ (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf)) #define __sanitizer_syscall_post_pciconfig_write(res, bus, dfn, off, len, buf) \ __sanitizer_syscall_post_impl_pciconfig_write( \ res, (long)(bus), (long)(dfn), (long)(off), (long)(len), (long)(buf)) -#define __sanitizer_syscall_pre_swapon(specialfile, swap_flags) \ +#define __sanitizer_syscall_pre_swapon(specialfile, swap_flags) \ __sanitizer_syscall_pre_impl_swapon((long)(specialfile), (long)(swap_flags)) -#define __sanitizer_syscall_post_swapon(res, specialfile, swap_flags) \ - __sanitizer_syscall_post_impl_swapon(res, (long)(specialfile), \ +#define __sanitizer_syscall_post_swapon(res, specialfile, swap_flags) \ + __sanitizer_syscall_post_impl_swapon(res, (long)(specialfile), \ (long)(swap_flags)) -#define __sanitizer_syscall_pre_swapoff(specialfile) \ +#define __sanitizer_syscall_pre_swapoff(specialfile) \ __sanitizer_syscall_pre_impl_swapoff((long)(specialfile)) -#define __sanitizer_syscall_post_swapoff(res, specialfile) \ +#define __sanitizer_syscall_post_swapoff(res, specialfile) \ __sanitizer_syscall_post_impl_swapoff(res, (long)(specialfile)) -#define __sanitizer_syscall_pre_sysctl(args) \ +#define __sanitizer_syscall_pre_sysctl(args) \ __sanitizer_syscall_pre_impl_sysctl((long)(args)) -#define __sanitizer_syscall_post_sysctl(res, args) \ +#define __sanitizer_syscall_post_sysctl(res, args) \ __sanitizer_syscall_post_impl_sysctl(res, (long)(args)) -#define __sanitizer_syscall_pre_sysinfo(info) \ +#define __sanitizer_syscall_pre_sysinfo(info) \ __sanitizer_syscall_pre_impl_sysinfo((long)(info)) -#define __sanitizer_syscall_post_sysinfo(res, info) \ +#define __sanitizer_syscall_post_sysinfo(res, info) \ __sanitizer_syscall_post_impl_sysinfo(res, (long)(info)) -#define __sanitizer_syscall_pre_sysfs(option, arg1, arg2) \ +#define __sanitizer_syscall_pre_sysfs(option, arg1, arg2) \ __sanitizer_syscall_pre_impl_sysfs((long)(option), (long)(arg1), (long)(arg2)) -#define __sanitizer_syscall_post_sysfs(res, option, arg1, arg2) \ - __sanitizer_syscall_post_impl_sysfs(res, (long)(option), (long)(arg1), \ +#define __sanitizer_syscall_post_sysfs(res, option, arg1, arg2) \ + __sanitizer_syscall_post_impl_sysfs(res, (long)(option), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_syslog(type, buf, len) \ +#define __sanitizer_syscall_pre_syslog(type, buf, len) \ __sanitizer_syscall_pre_impl_syslog((long)(type), (long)(buf), (long)(len)) -#define __sanitizer_syscall_post_syslog(res, type, buf, len) \ - __sanitizer_syscall_post_impl_syslog(res, (long)(type), (long)(buf), \ +#define __sanitizer_syscall_post_syslog(res, type, buf, len) \ + __sanitizer_syscall_post_impl_syslog(res, (long)(type), (long)(buf), \ (long)(len)) -#define __sanitizer_syscall_pre_uselib(library) \ +#define __sanitizer_syscall_pre_uselib(library) \ __sanitizer_syscall_pre_impl_uselib((long)(library)) -#define __sanitizer_syscall_post_uselib(res, library) \ +#define __sanitizer_syscall_post_uselib(res, library) \ __sanitizer_syscall_post_impl_uselib(res, (long)(library)) -#define __sanitizer_syscall_pre_ni_syscall() \ +#define __sanitizer_syscall_pre_ni_syscall() \ __sanitizer_syscall_pre_impl_ni_syscall() -#define __sanitizer_syscall_post_ni_syscall(res) \ +#define __sanitizer_syscall_post_ni_syscall(res) \ __sanitizer_syscall_post_impl_ni_syscall(res) -#define __sanitizer_syscall_pre_ptrace(request, pid, addr, data) \ - __sanitizer_syscall_pre_impl_ptrace((long)(request), (long)(pid), \ +#define __sanitizer_syscall_pre_ptrace(request, pid, addr, data) \ + __sanitizer_syscall_pre_impl_ptrace((long)(request), (long)(pid), \ (long)(addr), (long)(data)) -#define __sanitizer_syscall_post_ptrace(res, request, pid, addr, data) \ - __sanitizer_syscall_post_impl_ptrace(res, (long)(request), (long)(pid), \ +#define __sanitizer_syscall_post_ptrace(res, request, pid, addr, data) \ + __sanitizer_syscall_post_impl_ptrace(res, (long)(request), (long)(pid), \ (long)(addr), (long)(data)) -#define __sanitizer_syscall_pre_add_key(_type, _description, _payload, plen, \ - destringid) \ - __sanitizer_syscall_pre_impl_add_key((long)(_type), (long)(_description), \ - (long)(_payload), (long)(plen), \ +#define __sanitizer_syscall_pre_add_key(_type, _description, _payload, plen, \ + destringid) \ + __sanitizer_syscall_pre_impl_add_key((long)(_type), (long)(_description), \ + (long)(_payload), (long)(plen), \ (long)(destringid)) -#define __sanitizer_syscall_post_add_key(res, _type, _description, _payload, \ - plen, destringid) \ - __sanitizer_syscall_post_impl_add_key( \ - res, (long)(_type), (long)(_description), (long)(_payload), \ +#define __sanitizer_syscall_post_add_key(res, _type, _description, _payload, \ + plen, destringid) \ + __sanitizer_syscall_post_impl_add_key( \ + res, (long)(_type), (long)(_description), (long)(_payload), \ (long)(plen), (long)(destringid)) -#define __sanitizer_syscall_pre_request_key(_type, _description, \ - _callout_info, destringid) \ - __sanitizer_syscall_pre_impl_request_key( \ - (long)(_type), (long)(_description), (long)(_callout_info), \ +#define __sanitizer_syscall_pre_request_key(_type, _description, \ + _callout_info, destringid) \ + __sanitizer_syscall_pre_impl_request_key( \ + (long)(_type), (long)(_description), (long)(_callout_info), \ (long)(destringid)) -#define __sanitizer_syscall_post_request_key(res, _type, _description, \ - _callout_info, destringid) \ - __sanitizer_syscall_post_impl_request_key( \ - res, (long)(_type), (long)(_description), (long)(_callout_info), \ +#define __sanitizer_syscall_post_request_key(res, _type, _description, \ + _callout_info, destringid) \ + __sanitizer_syscall_post_impl_request_key( \ + res, (long)(_type), (long)(_description), (long)(_callout_info), \ (long)(destringid)) #define __sanitizer_syscall_pre_keyctl(cmd, arg2, arg3, arg4, arg5) \ __sanitizer_syscall_pre_impl_keyctl((long)(cmd), (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_post_keyctl(res, cmd, arg2, arg3, arg4, arg5) \ - __sanitizer_syscall_post_impl_keyctl(res, (long)(cmd), (long)(arg2), \ - (long)(arg3), (long)(arg4), \ +#define __sanitizer_syscall_post_keyctl(res, cmd, arg2, arg3, arg4, arg5) \ + __sanitizer_syscall_post_impl_keyctl(res, (long)(cmd), (long)(arg2), \ + (long)(arg3), (long)(arg4), \ (long)(arg5)) -#define __sanitizer_syscall_pre_ioprio_set(which, who, ioprio) \ - __sanitizer_syscall_pre_impl_ioprio_set((long)(which), (long)(who), \ +#define __sanitizer_syscall_pre_ioprio_set(which, who, ioprio) \ + __sanitizer_syscall_pre_impl_ioprio_set((long)(which), (long)(who), \ (long)(ioprio)) -#define __sanitizer_syscall_post_ioprio_set(res, which, who, ioprio) \ - __sanitizer_syscall_post_impl_ioprio_set(res, (long)(which), (long)(who), \ +#define __sanitizer_syscall_post_ioprio_set(res, which, who, ioprio) \ + __sanitizer_syscall_post_impl_ioprio_set(res, (long)(which), (long)(who), \ (long)(ioprio)) -#define __sanitizer_syscall_pre_ioprio_get(which, who) \ +#define __sanitizer_syscall_pre_ioprio_get(which, who) \ __sanitizer_syscall_pre_impl_ioprio_get((long)(which), (long)(who)) -#define __sanitizer_syscall_post_ioprio_get(res, which, who) \ +#define __sanitizer_syscall_post_ioprio_get(res, which, who) \ __sanitizer_syscall_post_impl_ioprio_get(res, (long)(which), (long)(who)) -#define __sanitizer_syscall_pre_set_mempolicy(mode, nmask, maxnode) \ - __sanitizer_syscall_pre_impl_set_mempolicy((long)(mode), (long)(nmask), \ +#define __sanitizer_syscall_pre_set_mempolicy(mode, nmask, maxnode) \ + __sanitizer_syscall_pre_impl_set_mempolicy((long)(mode), (long)(nmask), \ (long)(maxnode)) -#define __sanitizer_syscall_post_set_mempolicy(res, mode, nmask, maxnode) \ - __sanitizer_syscall_post_impl_set_mempolicy(res, (long)(mode), \ +#define __sanitizer_syscall_post_set_mempolicy(res, mode, nmask, maxnode) \ + __sanitizer_syscall_post_impl_set_mempolicy(res, (long)(mode), \ (long)(nmask), (long)(maxnode)) -#define __sanitizer_syscall_pre_migrate_pages(pid, maxnode, from, to) \ - __sanitizer_syscall_pre_impl_migrate_pages((long)(pid), (long)(maxnode), \ +#define __sanitizer_syscall_pre_migrate_pages(pid, maxnode, from, to) \ + __sanitizer_syscall_pre_impl_migrate_pages((long)(pid), (long)(maxnode), \ (long)(from), (long)(to)) -#define __sanitizer_syscall_post_migrate_pages(res, pid, maxnode, from, to) \ - __sanitizer_syscall_post_impl_migrate_pages( \ +#define __sanitizer_syscall_post_migrate_pages(res, pid, maxnode, from, to) \ + __sanitizer_syscall_post_impl_migrate_pages( \ res, (long)(pid), (long)(maxnode), (long)(from), (long)(to)) -#define __sanitizer_syscall_pre_move_pages(pid, nr_pages, pages, nodes, \ - status, flags) \ - __sanitizer_syscall_pre_impl_move_pages((long)(pid), (long)(nr_pages), \ - (long)(pages), (long)(nodes), \ +#define __sanitizer_syscall_pre_move_pages(pid, nr_pages, pages, nodes, \ + status, flags) \ + __sanitizer_syscall_pre_impl_move_pages((long)(pid), (long)(nr_pages), \ + (long)(pages), (long)(nodes), \ (long)(status), (long)(flags)) #define __sanitizer_syscall_post_move_pages(res, pid, nr_pages, pages, nodes, \ status, flags) \ @@ -1517,322 +1526,320 @@ __sanitizer_syscall_pre_impl_mbind((long)(start), (long)(len), (long)(mode), \ (long)(nmask), (long)(maxnode), \ (long)(flags)) -#define __sanitizer_syscall_post_mbind(res, start, len, mode, nmask, maxnode, \ - flags) \ - __sanitizer_syscall_post_impl_mbind(res, (long)(start), (long)(len), \ - (long)(mode), (long)(nmask), \ +#define __sanitizer_syscall_post_mbind(res, start, len, mode, nmask, maxnode, \ + flags) \ + __sanitizer_syscall_post_impl_mbind(res, (long)(start), (long)(len), \ + (long)(mode), (long)(nmask), \ (long)(maxnode), (long)(flags)) -#define __sanitizer_syscall_pre_get_mempolicy(policy, nmask, maxnode, addr, \ - flags) \ - __sanitizer_syscall_pre_impl_get_mempolicy((long)(policy), (long)(nmask), \ - (long)(maxnode), (long)(addr), \ +#define __sanitizer_syscall_pre_get_mempolicy(policy, nmask, maxnode, addr, \ + flags) \ + __sanitizer_syscall_pre_impl_get_mempolicy((long)(policy), (long)(nmask), \ + (long)(maxnode), (long)(addr), \ (long)(flags)) -#define __sanitizer_syscall_post_get_mempolicy(res, policy, nmask, maxnode, \ - addr, flags) \ - __sanitizer_syscall_post_impl_get_mempolicy(res, (long)(policy), \ - (long)(nmask), (long)(maxnode), \ +#define __sanitizer_syscall_post_get_mempolicy(res, policy, nmask, maxnode, \ + addr, flags) \ + __sanitizer_syscall_post_impl_get_mempolicy(res, (long)(policy), \ + (long)(nmask), (long)(maxnode), \ (long)(addr), (long)(flags)) -#define __sanitizer_syscall_pre_inotify_init() \ +#define __sanitizer_syscall_pre_inotify_init() \ __sanitizer_syscall_pre_impl_inotify_init() -#define __sanitizer_syscall_post_inotify_init(res) \ +#define __sanitizer_syscall_post_inotify_init(res) \ __sanitizer_syscall_post_impl_inotify_init(res) -#define __sanitizer_syscall_pre_inotify_init1(flags) \ +#define __sanitizer_syscall_pre_inotify_init1(flags) \ __sanitizer_syscall_pre_impl_inotify_init1((long)(flags)) -#define __sanitizer_syscall_post_inotify_init1(res, flags) \ +#define __sanitizer_syscall_post_inotify_init1(res, flags) \ __sanitizer_syscall_post_impl_inotify_init1(res, (long)(flags)) -#define __sanitizer_syscall_pre_inotify_add_watch(fd, path, mask) \ - __sanitizer_syscall_pre_impl_inotify_add_watch((long)(fd), (long)(path), \ +#define __sanitizer_syscall_pre_inotify_add_watch(fd, path, mask) \ + __sanitizer_syscall_pre_impl_inotify_add_watch((long)(fd), (long)(path), \ (long)(mask)) -#define __sanitizer_syscall_post_inotify_add_watch(res, fd, path, mask) \ - __sanitizer_syscall_post_impl_inotify_add_watch(res, (long)(fd), \ +#define __sanitizer_syscall_post_inotify_add_watch(res, fd, path, mask) \ + __sanitizer_syscall_post_impl_inotify_add_watch(res, (long)(fd), \ (long)(path), (long)(mask)) -#define __sanitizer_syscall_pre_inotify_rm_watch(fd, wd) \ +#define __sanitizer_syscall_pre_inotify_rm_watch(fd, wd) \ __sanitizer_syscall_pre_impl_inotify_rm_watch((long)(fd), (long)(wd)) -#define __sanitizer_syscall_post_inotify_rm_watch(res, fd, wd) \ +#define __sanitizer_syscall_post_inotify_rm_watch(res, fd, wd) \ __sanitizer_syscall_post_impl_inotify_rm_watch(res, (long)(fd), (long)(wd)) -#define __sanitizer_syscall_pre_spu_run(fd, unpc, ustatus) \ - __sanitizer_syscall_pre_impl_spu_run((long)(fd), (long)(unpc), \ +#define __sanitizer_syscall_pre_spu_run(fd, unpc, ustatus) \ + __sanitizer_syscall_pre_impl_spu_run((long)(fd), (long)(unpc), \ (long)(ustatus)) -#define __sanitizer_syscall_post_spu_run(res, fd, unpc, ustatus) \ - __sanitizer_syscall_post_impl_spu_run(res, (long)(fd), (long)(unpc), \ +#define __sanitizer_syscall_post_spu_run(res, fd, unpc, ustatus) \ + __sanitizer_syscall_post_impl_spu_run(res, (long)(fd), (long)(unpc), \ (long)(ustatus)) -#define __sanitizer_syscall_pre_spu_create(name, flags, mode, fd) \ - __sanitizer_syscall_pre_impl_spu_create((long)(name), (long)(flags), \ +#define __sanitizer_syscall_pre_spu_create(name, flags, mode, fd) \ + __sanitizer_syscall_pre_impl_spu_create((long)(name), (long)(flags), \ (long)(mode), (long)(fd)) -#define __sanitizer_syscall_post_spu_create(res, name, flags, mode, fd) \ - __sanitizer_syscall_post_impl_spu_create(res, (long)(name), (long)(flags), \ +#define __sanitizer_syscall_post_spu_create(res, name, flags, mode, fd) \ + __sanitizer_syscall_post_impl_spu_create(res, (long)(name), (long)(flags), \ (long)(mode), (long)(fd)) -#define __sanitizer_syscall_pre_mknodat(dfd, filename, mode, dev) \ - __sanitizer_syscall_pre_impl_mknodat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_mknodat(dfd, filename, mode, dev) \ + __sanitizer_syscall_pre_impl_mknodat((long)(dfd), (long)(filename), \ (long)(mode), (long)(dev)) -#define __sanitizer_syscall_post_mknodat(res, dfd, filename, mode, dev) \ - __sanitizer_syscall_post_impl_mknodat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_mknodat(res, dfd, filename, mode, dev) \ + __sanitizer_syscall_post_impl_mknodat(res, (long)(dfd), (long)(filename), \ (long)(mode), (long)(dev)) -#define __sanitizer_syscall_pre_mkdirat(dfd, pathname, mode) \ - __sanitizer_syscall_pre_impl_mkdirat((long)(dfd), (long)(pathname), \ +#define __sanitizer_syscall_pre_mkdirat(dfd, pathname, mode) \ + __sanitizer_syscall_pre_impl_mkdirat((long)(dfd), (long)(pathname), \ (long)(mode)) -#define __sanitizer_syscall_post_mkdirat(res, dfd, pathname, mode) \ - __sanitizer_syscall_post_impl_mkdirat(res, (long)(dfd), (long)(pathname), \ +#define __sanitizer_syscall_post_mkdirat(res, dfd, pathname, mode) \ + __sanitizer_syscall_post_impl_mkdirat(res, (long)(dfd), (long)(pathname), \ (long)(mode)) -#define __sanitizer_syscall_pre_unlinkat(dfd, pathname, flag) \ - __sanitizer_syscall_pre_impl_unlinkat((long)(dfd), (long)(pathname), \ +#define __sanitizer_syscall_pre_unlinkat(dfd, pathname, flag) \ + __sanitizer_syscall_pre_impl_unlinkat((long)(dfd), (long)(pathname), \ (long)(flag)) -#define __sanitizer_syscall_post_unlinkat(res, dfd, pathname, flag) \ - __sanitizer_syscall_post_impl_unlinkat(res, (long)(dfd), (long)(pathname), \ +#define __sanitizer_syscall_post_unlinkat(res, dfd, pathname, flag) \ + __sanitizer_syscall_post_impl_unlinkat(res, (long)(dfd), (long)(pathname), \ (long)(flag)) -#define __sanitizer_syscall_pre_symlinkat(oldname, newdfd, newname) \ - __sanitizer_syscall_pre_impl_symlinkat((long)(oldname), (long)(newdfd), \ +#define __sanitizer_syscall_pre_symlinkat(oldname, newdfd, newname) \ + __sanitizer_syscall_pre_impl_symlinkat((long)(oldname), (long)(newdfd), \ (long)(newname)) -#define __sanitizer_syscall_post_symlinkat(res, oldname, newdfd, newname) \ - __sanitizer_syscall_post_impl_symlinkat(res, (long)(oldname), \ +#define __sanitizer_syscall_post_symlinkat(res, oldname, newdfd, newname) \ + __sanitizer_syscall_post_impl_symlinkat(res, (long)(oldname), \ (long)(newdfd), (long)(newname)) -#define __sanitizer_syscall_pre_linkat(olddfd, oldname, newdfd, newname, \ - flags) \ - __sanitizer_syscall_pre_impl_linkat((long)(olddfd), (long)(oldname), \ - (long)(newdfd), (long)(newname), \ +#define __sanitizer_syscall_pre_linkat(olddfd, oldname, newdfd, newname, \ + flags) \ + __sanitizer_syscall_pre_impl_linkat((long)(olddfd), (long)(oldname), \ + (long)(newdfd), (long)(newname), \ (long)(flags)) #define __sanitizer_syscall_post_linkat(res, olddfd, oldname, newdfd, newname, \ flags) \ __sanitizer_syscall_post_impl_linkat(res, (long)(olddfd), (long)(oldname), \ (long)(newdfd), (long)(newname), \ (long)(flags)) -#define __sanitizer_syscall_pre_renameat(olddfd, oldname, newdfd, newname) \ - __sanitizer_syscall_pre_impl_renameat((long)(olddfd), (long)(oldname), \ +#define __sanitizer_syscall_pre_renameat(olddfd, oldname, newdfd, newname) \ + __sanitizer_syscall_pre_impl_renameat((long)(olddfd), (long)(oldname), \ (long)(newdfd), (long)(newname)) #define __sanitizer_syscall_post_renameat(res, olddfd, oldname, newdfd, \ newname) \ __sanitizer_syscall_post_impl_renameat(res, (long)(olddfd), (long)(oldname), \ (long)(newdfd), (long)(newname)) -#define __sanitizer_syscall_pre_futimesat(dfd, filename, utimes) \ - __sanitizer_syscall_pre_impl_futimesat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_futimesat(dfd, filename, utimes) \ + __sanitizer_syscall_pre_impl_futimesat((long)(dfd), (long)(filename), \ (long)(utimes)) -#define __sanitizer_syscall_post_futimesat(res, dfd, filename, utimes) \ - __sanitizer_syscall_post_impl_futimesat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_futimesat(res, dfd, filename, utimes) \ + __sanitizer_syscall_post_impl_futimesat(res, (long)(dfd), (long)(filename), \ (long)(utimes)) -#define __sanitizer_syscall_pre_faccessat(dfd, filename, mode) \ - __sanitizer_syscall_pre_impl_faccessat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_faccessat(dfd, filename, mode) \ + __sanitizer_syscall_pre_impl_faccessat((long)(dfd), (long)(filename), \ (long)(mode)) -#define __sanitizer_syscall_post_faccessat(res, dfd, filename, mode) \ - __sanitizer_syscall_post_impl_faccessat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_faccessat(res, dfd, filename, mode) \ + __sanitizer_syscall_post_impl_faccessat(res, (long)(dfd), (long)(filename), \ (long)(mode)) -#define __sanitizer_syscall_pre_fchmodat(dfd, filename, mode) \ - __sanitizer_syscall_pre_impl_fchmodat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_fchmodat(dfd, filename, mode) \ + __sanitizer_syscall_pre_impl_fchmodat((long)(dfd), (long)(filename), \ (long)(mode)) -#define __sanitizer_syscall_post_fchmodat(res, dfd, filename, mode) \ - __sanitizer_syscall_post_impl_fchmodat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_fchmodat(res, dfd, filename, mode) \ + __sanitizer_syscall_post_impl_fchmodat(res, (long)(dfd), (long)(filename), \ (long)(mode)) -#define __sanitizer_syscall_pre_fchownat(dfd, filename, user, group, flag) \ - __sanitizer_syscall_pre_impl_fchownat((long)(dfd), (long)(filename), \ - (long)(user), (long)(group), \ +#define __sanitizer_syscall_pre_fchownat(dfd, filename, user, group, flag) \ + __sanitizer_syscall_pre_impl_fchownat((long)(dfd), (long)(filename), \ + (long)(user), (long)(group), \ (long)(flag)) -#define __sanitizer_syscall_post_fchownat(res, dfd, filename, user, group, \ - flag) \ - __sanitizer_syscall_post_impl_fchownat(res, (long)(dfd), (long)(filename), \ - (long)(user), (long)(group), \ +#define __sanitizer_syscall_post_fchownat(res, dfd, filename, user, group, \ + flag) \ + __sanitizer_syscall_post_impl_fchownat(res, (long)(dfd), (long)(filename), \ + (long)(user), (long)(group), \ (long)(flag)) -#define __sanitizer_syscall_pre_openat(dfd, filename, flags, mode) \ - __sanitizer_syscall_pre_impl_openat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_openat(dfd, filename, flags, mode) \ + __sanitizer_syscall_pre_impl_openat((long)(dfd), (long)(filename), \ (long)(flags), (long)(mode)) -#define __sanitizer_syscall_post_openat(res, dfd, filename, flags, mode) \ - __sanitizer_syscall_post_impl_openat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_openat(res, dfd, filename, flags, mode) \ + __sanitizer_syscall_post_impl_openat(res, (long)(dfd), (long)(filename), \ (long)(flags), (long)(mode)) -#define __sanitizer_syscall_pre_newfstatat(dfd, filename, statbuf, flag) \ - __sanitizer_syscall_pre_impl_newfstatat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_newfstatat(dfd, filename, statbuf, flag) \ + __sanitizer_syscall_pre_impl_newfstatat((long)(dfd), (long)(filename), \ (long)(statbuf), (long)(flag)) #define __sanitizer_syscall_post_newfstatat(res, dfd, filename, statbuf, flag) \ __sanitizer_syscall_post_impl_newfstatat(res, (long)(dfd), (long)(filename), \ (long)(statbuf), (long)(flag)) -#define __sanitizer_syscall_pre_fstatat64(dfd, filename, statbuf, flag) \ - __sanitizer_syscall_pre_impl_fstatat64((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_fstatat64(dfd, filename, statbuf, flag) \ + __sanitizer_syscall_pre_impl_fstatat64((long)(dfd), (long)(filename), \ (long)(statbuf), (long)(flag)) -#define __sanitizer_syscall_post_fstatat64(res, dfd, filename, statbuf, flag) \ - __sanitizer_syscall_post_impl_fstatat64(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_fstatat64(res, dfd, filename, statbuf, flag) \ + __sanitizer_syscall_post_impl_fstatat64(res, (long)(dfd), (long)(filename), \ (long)(statbuf), (long)(flag)) -#define __sanitizer_syscall_pre_readlinkat(dfd, path, buf, bufsiz) \ - __sanitizer_syscall_pre_impl_readlinkat((long)(dfd), (long)(path), \ +#define __sanitizer_syscall_pre_readlinkat(dfd, path, buf, bufsiz) \ + __sanitizer_syscall_pre_impl_readlinkat((long)(dfd), (long)(path), \ (long)(buf), (long)(bufsiz)) -#define __sanitizer_syscall_post_readlinkat(res, dfd, path, buf, bufsiz) \ - __sanitizer_syscall_post_impl_readlinkat(res, (long)(dfd), (long)(path), \ +#define __sanitizer_syscall_post_readlinkat(res, dfd, path, buf, bufsiz) \ + __sanitizer_syscall_post_impl_readlinkat(res, (long)(dfd), (long)(path), \ (long)(buf), (long)(bufsiz)) -#define __sanitizer_syscall_pre_utimensat(dfd, filename, utimes, flags) \ - __sanitizer_syscall_pre_impl_utimensat((long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_pre_utimensat(dfd, filename, utimes, flags) \ + __sanitizer_syscall_pre_impl_utimensat((long)(dfd), (long)(filename), \ (long)(utimes), (long)(flags)) -#define __sanitizer_syscall_post_utimensat(res, dfd, filename, utimes, flags) \ - __sanitizer_syscall_post_impl_utimensat(res, (long)(dfd), (long)(filename), \ +#define __sanitizer_syscall_post_utimensat(res, dfd, filename, utimes, flags) \ + __sanitizer_syscall_post_impl_utimensat(res, (long)(dfd), (long)(filename), \ (long)(utimes), (long)(flags)) -#define __sanitizer_syscall_pre_unshare(unshare_flags) \ +#define __sanitizer_syscall_pre_unshare(unshare_flags) \ __sanitizer_syscall_pre_impl_unshare((long)(unshare_flags)) -#define __sanitizer_syscall_post_unshare(res, unshare_flags) \ +#define __sanitizer_syscall_post_unshare(res, unshare_flags) \ __sanitizer_syscall_post_impl_unshare(res, (long)(unshare_flags)) -#define __sanitizer_syscall_pre_splice(fd_in, off_in, fd_out, off_out, len, \ - flags) \ - __sanitizer_syscall_pre_impl_splice((long)(fd_in), (long)(off_in), \ - (long)(fd_out), (long)(off_out), \ +#define __sanitizer_syscall_pre_splice(fd_in, off_in, fd_out, off_out, len, \ + flags) \ + __sanitizer_syscall_pre_impl_splice((long)(fd_in), (long)(off_in), \ + (long)(fd_out), (long)(off_out), \ (long)(len), (long)(flags)) -#define __sanitizer_syscall_post_splice(res, fd_in, off_in, fd_out, off_out, \ - len, flags) \ - __sanitizer_syscall_post_impl_splice(res, (long)(fd_in), (long)(off_in), \ - (long)(fd_out), (long)(off_out), \ +#define __sanitizer_syscall_post_splice(res, fd_in, off_in, fd_out, off_out, \ + len, flags) \ + __sanitizer_syscall_post_impl_splice(res, (long)(fd_in), (long)(off_in), \ + (long)(fd_out), (long)(off_out), \ (long)(len), (long)(flags)) -#define __sanitizer_syscall_pre_vmsplice(fd, iov, nr_segs, flags) \ - __sanitizer_syscall_pre_impl_vmsplice((long)(fd), (long)(iov), \ +#define __sanitizer_syscall_pre_vmsplice(fd, iov, nr_segs, flags) \ + __sanitizer_syscall_pre_impl_vmsplice((long)(fd), (long)(iov), \ (long)(nr_segs), (long)(flags)) -#define __sanitizer_syscall_post_vmsplice(res, fd, iov, nr_segs, flags) \ - __sanitizer_syscall_post_impl_vmsplice(res, (long)(fd), (long)(iov), \ +#define __sanitizer_syscall_post_vmsplice(res, fd, iov, nr_segs, flags) \ + __sanitizer_syscall_post_impl_vmsplice(res, (long)(fd), (long)(iov), \ (long)(nr_segs), (long)(flags)) -#define __sanitizer_syscall_pre_tee(fdin, fdout, len, flags) \ - __sanitizer_syscall_pre_impl_tee((long)(fdin), (long)(fdout), (long)(len), \ +#define __sanitizer_syscall_pre_tee(fdin, fdout, len, flags) \ + __sanitizer_syscall_pre_impl_tee((long)(fdin), (long)(fdout), (long)(len), \ (long)(flags)) -#define __sanitizer_syscall_post_tee(res, fdin, fdout, len, flags) \ - __sanitizer_syscall_post_impl_tee(res, (long)(fdin), (long)(fdout), \ +#define __sanitizer_syscall_post_tee(res, fdin, fdout, len, flags) \ + __sanitizer_syscall_post_impl_tee(res, (long)(fdin), (long)(fdout), \ (long)(len), (long)(flags)) -#define __sanitizer_syscall_pre_get_robust_list(pid, head_ptr, len_ptr) \ - __sanitizer_syscall_pre_impl_get_robust_list((long)(pid), (long)(head_ptr), \ +#define __sanitizer_syscall_pre_get_robust_list(pid, head_ptr, len_ptr) \ + __sanitizer_syscall_pre_impl_get_robust_list((long)(pid), (long)(head_ptr), \ (long)(len_ptr)) -#define __sanitizer_syscall_post_get_robust_list(res, pid, head_ptr, len_ptr) \ - __sanitizer_syscall_post_impl_get_robust_list( \ +#define __sanitizer_syscall_post_get_robust_list(res, pid, head_ptr, len_ptr) \ + __sanitizer_syscall_post_impl_get_robust_list( \ res, (long)(pid), (long)(head_ptr), (long)(len_ptr)) -#define __sanitizer_syscall_pre_set_robust_list(head, len) \ +#define __sanitizer_syscall_pre_set_robust_list(head, len) \ __sanitizer_syscall_pre_impl_set_robust_list((long)(head), (long)(len)) -#define __sanitizer_syscall_post_set_robust_list(res, head, len) \ +#define __sanitizer_syscall_post_set_robust_list(res, head, len) \ __sanitizer_syscall_post_impl_set_robust_list(res, (long)(head), (long)(len)) -#define __sanitizer_syscall_pre_getcpu(cpu, node, cache) \ +#define __sanitizer_syscall_pre_getcpu(cpu, node, cache) \ __sanitizer_syscall_pre_impl_getcpu((long)(cpu), (long)(node), (long)(cache)) -#define __sanitizer_syscall_post_getcpu(res, cpu, node, cache) \ - __sanitizer_syscall_post_impl_getcpu(res, (long)(cpu), (long)(node), \ +#define __sanitizer_syscall_post_getcpu(res, cpu, node, cache) \ + __sanitizer_syscall_post_impl_getcpu(res, (long)(cpu), (long)(node), \ (long)(cache)) -#define __sanitizer_syscall_pre_signalfd(ufd, user_mask, sizemask) \ - __sanitizer_syscall_pre_impl_signalfd((long)(ufd), (long)(user_mask), \ +#define __sanitizer_syscall_pre_signalfd(ufd, user_mask, sizemask) \ + __sanitizer_syscall_pre_impl_signalfd((long)(ufd), (long)(user_mask), \ (long)(sizemask)) -#define __sanitizer_syscall_post_signalfd(res, ufd, user_mask, sizemask) \ - __sanitizer_syscall_post_impl_signalfd(res, (long)(ufd), (long)(user_mask), \ +#define __sanitizer_syscall_post_signalfd(res, ufd, user_mask, sizemask) \ + __sanitizer_syscall_post_impl_signalfd(res, (long)(ufd), (long)(user_mask), \ (long)(sizemask)) -#define __sanitizer_syscall_pre_signalfd4(ufd, user_mask, sizemask, flags) \ - __sanitizer_syscall_pre_impl_signalfd4((long)(ufd), (long)(user_mask), \ +#define __sanitizer_syscall_pre_signalfd4(ufd, user_mask, sizemask, flags) \ + __sanitizer_syscall_pre_impl_signalfd4((long)(ufd), (long)(user_mask), \ (long)(sizemask), (long)(flags)) #define __sanitizer_syscall_post_signalfd4(res, ufd, user_mask, sizemask, \ flags) \ __sanitizer_syscall_post_impl_signalfd4(res, (long)(ufd), (long)(user_mask), \ (long)(sizemask), (long)(flags)) -#define __sanitizer_syscall_pre_timerfd_create(clockid, flags) \ +#define __sanitizer_syscall_pre_timerfd_create(clockid, flags) \ __sanitizer_syscall_pre_impl_timerfd_create((long)(clockid), (long)(flags)) -#define __sanitizer_syscall_post_timerfd_create(res, clockid, flags) \ - __sanitizer_syscall_post_impl_timerfd_create(res, (long)(clockid), \ +#define __sanitizer_syscall_post_timerfd_create(res, clockid, flags) \ + __sanitizer_syscall_post_impl_timerfd_create(res, (long)(clockid), \ (long)(flags)) -#define __sanitizer_syscall_pre_timerfd_settime(ufd, flags, utmr, otmr) \ - __sanitizer_syscall_pre_impl_timerfd_settime((long)(ufd), (long)(flags), \ +#define __sanitizer_syscall_pre_timerfd_settime(ufd, flags, utmr, otmr) \ + __sanitizer_syscall_pre_impl_timerfd_settime((long)(ufd), (long)(flags), \ (long)(utmr), (long)(otmr)) -#define __sanitizer_syscall_post_timerfd_settime(res, ufd, flags, utmr, otmr) \ - __sanitizer_syscall_post_impl_timerfd_settime( \ +#define __sanitizer_syscall_post_timerfd_settime(res, ufd, flags, utmr, otmr) \ + __sanitizer_syscall_post_impl_timerfd_settime( \ res, (long)(ufd), (long)(flags), (long)(utmr), (long)(otmr)) -#define __sanitizer_syscall_pre_timerfd_gettime(ufd, otmr) \ +#define __sanitizer_syscall_pre_timerfd_gettime(ufd, otmr) \ __sanitizer_syscall_pre_impl_timerfd_gettime((long)(ufd), (long)(otmr)) -#define __sanitizer_syscall_post_timerfd_gettime(res, ufd, otmr) \ +#define __sanitizer_syscall_post_timerfd_gettime(res, ufd, otmr) \ __sanitizer_syscall_post_impl_timerfd_gettime(res, (long)(ufd), (long)(otmr)) -#define __sanitizer_syscall_pre_eventfd(count) \ +#define __sanitizer_syscall_pre_eventfd(count) \ __sanitizer_syscall_pre_impl_eventfd((long)(count)) -#define __sanitizer_syscall_post_eventfd(res, count) \ +#define __sanitizer_syscall_post_eventfd(res, count) \ __sanitizer_syscall_post_impl_eventfd(res, (long)(count)) -#define __sanitizer_syscall_pre_eventfd2(count, flags) \ +#define __sanitizer_syscall_pre_eventfd2(count, flags) \ __sanitizer_syscall_pre_impl_eventfd2((long)(count), (long)(flags)) -#define __sanitizer_syscall_post_eventfd2(res, count, flags) \ +#define __sanitizer_syscall_post_eventfd2(res, count, flags) \ __sanitizer_syscall_post_impl_eventfd2(res, (long)(count), (long)(flags)) -#define __sanitizer_syscall_pre_old_readdir(arg0, arg1, arg2) \ - __sanitizer_syscall_pre_impl_old_readdir((long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_pre_old_readdir(arg0, arg1, arg2) \ + __sanitizer_syscall_pre_impl_old_readdir((long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_post_old_readdir(res, arg0, arg1, arg2) \ - __sanitizer_syscall_post_impl_old_readdir(res, (long)(arg0), (long)(arg1), \ +#define __sanitizer_syscall_post_old_readdir(res, arg0, arg1, arg2) \ + __sanitizer_syscall_post_impl_old_readdir(res, (long)(arg0), (long)(arg1), \ (long)(arg2)) -#define __sanitizer_syscall_pre_pselect6(arg0, arg1, arg2, arg3, arg4, arg5) \ - __sanitizer_syscall_pre_impl_pselect6((long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_pre_pselect6(arg0, arg1, arg2, arg3, arg4, arg5) \ + __sanitizer_syscall_pre_impl_pselect6((long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) -#define __sanitizer_syscall_post_pselect6(res, arg0, arg1, arg2, arg3, arg4, \ - arg5) \ - __sanitizer_syscall_post_impl_pselect6(res, (long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_post_pselect6(res, arg0, arg1, arg2, arg3, arg4, \ + arg5) \ + __sanitizer_syscall_post_impl_pselect6(res, (long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4), (long)(arg5)) #define __sanitizer_syscall_pre_ppoll(arg0, arg1, arg2, arg3, arg4) \ __sanitizer_syscall_pre_impl_ppoll((long)(arg0), (long)(arg1), (long)(arg2), \ (long)(arg3), (long)(arg4)) -#define __sanitizer_syscall_post_ppoll(res, arg0, arg1, arg2, arg3, arg4) \ - __sanitizer_syscall_post_impl_ppoll(res, (long)(arg0), (long)(arg1), \ - (long)(arg2), (long)(arg3), \ +#define __sanitizer_syscall_post_ppoll(res, arg0, arg1, arg2, arg3, arg4) \ + __sanitizer_syscall_post_impl_ppoll(res, (long)(arg0), (long)(arg1), \ + (long)(arg2), (long)(arg3), \ (long)(arg4)) -#define __sanitizer_syscall_pre_syncfs(fd) \ +#define __sanitizer_syscall_pre_syncfs(fd) \ __sanitizer_syscall_pre_impl_syncfs((long)(fd)) -#define __sanitizer_syscall_post_syncfs(res, fd) \ +#define __sanitizer_syscall_post_syncfs(res, fd) \ __sanitizer_syscall_post_impl_syncfs(res, (long)(fd)) #define __sanitizer_syscall_pre_perf_event_open(attr_uptr, pid, cpu, group_fd, \ flags) \ __sanitizer_syscall_pre_impl_perf_event_open((long)(attr_uptr), (long)(pid), \ (long)(cpu), (long)(group_fd), \ (long)(flags)) -#define __sanitizer_syscall_post_perf_event_open(res, attr_uptr, pid, cpu, \ - group_fd, flags) \ - __sanitizer_syscall_post_impl_perf_event_open( \ - res, (long)(attr_uptr), (long)(pid), (long)(cpu), (long)(group_fd), \ +#define __sanitizer_syscall_post_perf_event_open(res, attr_uptr, pid, cpu, \ + group_fd, flags) \ + __sanitizer_syscall_post_impl_perf_event_open( \ + res, (long)(attr_uptr), (long)(pid), (long)(cpu), (long)(group_fd), \ (long)(flags)) -#define __sanitizer_syscall_pre_mmap_pgoff(addr, len, prot, flags, fd, pgoff) \ - __sanitizer_syscall_pre_impl_mmap_pgoff((long)(addr), (long)(len), \ - (long)(prot), (long)(flags), \ +#define __sanitizer_syscall_pre_mmap_pgoff(addr, len, prot, flags, fd, pgoff) \ + __sanitizer_syscall_pre_impl_mmap_pgoff((long)(addr), (long)(len), \ + (long)(prot), (long)(flags), \ (long)(fd), (long)(pgoff)) -#define __sanitizer_syscall_post_mmap_pgoff(res, addr, len, prot, flags, fd, \ - pgoff) \ - __sanitizer_syscall_post_impl_mmap_pgoff(res, (long)(addr), (long)(len), \ - (long)(prot), (long)(flags), \ +#define __sanitizer_syscall_post_mmap_pgoff(res, addr, len, prot, flags, fd, \ + pgoff) \ + __sanitizer_syscall_post_impl_mmap_pgoff(res, (long)(addr), (long)(len), \ + (long)(prot), (long)(flags), \ (long)(fd), (long)(pgoff)) -#define __sanitizer_syscall_pre_old_mmap(arg) \ +#define __sanitizer_syscall_pre_old_mmap(arg) \ __sanitizer_syscall_pre_impl_old_mmap((long)(arg)) -#define __sanitizer_syscall_post_old_mmap(res, arg) \ +#define __sanitizer_syscall_post_old_mmap(res, arg) \ __sanitizer_syscall_post_impl_old_mmap(res, (long)(arg)) -#define __sanitizer_syscall_pre_name_to_handle_at(dfd, name, handle, mnt_id, \ - flag) \ - __sanitizer_syscall_pre_impl_name_to_handle_at( \ +#define __sanitizer_syscall_pre_name_to_handle_at(dfd, name, handle, mnt_id, \ + flag) \ + __sanitizer_syscall_pre_impl_name_to_handle_at( \ (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), (long)(flag)) -#define __sanitizer_syscall_post_name_to_handle_at(res, dfd, name, handle, \ - mnt_id, flag) \ - __sanitizer_syscall_post_impl_name_to_handle_at( \ - res, (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), \ +#define __sanitizer_syscall_post_name_to_handle_at(res, dfd, name, handle, \ + mnt_id, flag) \ + __sanitizer_syscall_post_impl_name_to_handle_at( \ + res, (long)(dfd), (long)(name), (long)(handle), (long)(mnt_id), \ (long)(flag)) -#define __sanitizer_syscall_pre_open_by_handle_at(mountdirfd, handle, flags) \ - __sanitizer_syscall_pre_impl_open_by_handle_at( \ +#define __sanitizer_syscall_pre_open_by_handle_at(mountdirfd, handle, flags) \ + __sanitizer_syscall_pre_impl_open_by_handle_at( \ (long)(mountdirfd), (long)(handle), (long)(flags)) -#define __sanitizer_syscall_post_open_by_handle_at(res, mountdirfd, handle, \ - flags) \ - __sanitizer_syscall_post_impl_open_by_handle_at( \ +#define __sanitizer_syscall_post_open_by_handle_at(res, mountdirfd, handle, \ + flags) \ + __sanitizer_syscall_post_impl_open_by_handle_at( \ res, (long)(mountdirfd), (long)(handle), (long)(flags)) -#define __sanitizer_syscall_pre_setns(fd, nstype) \ +#define __sanitizer_syscall_pre_setns(fd, nstype) \ __sanitizer_syscall_pre_impl_setns((long)(fd), (long)(nstype)) -#define __sanitizer_syscall_post_setns(res, fd, nstype) \ +#define __sanitizer_syscall_post_setns(res, fd, nstype) \ __sanitizer_syscall_post_impl_setns(res, (long)(fd), (long)(nstype)) -#define __sanitizer_syscall_pre_process_vm_readv(pid, lvec, liovcnt, rvec, \ - riovcnt, flags) \ - __sanitizer_syscall_pre_impl_process_vm_readv( \ - (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ +#define __sanitizer_syscall_pre_process_vm_readv(pid, lvec, liovcnt, rvec, \ + riovcnt, flags) \ + __sanitizer_syscall_pre_impl_process_vm_readv( \ + (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ (long)(riovcnt), (long)(flags)) -#define __sanitizer_syscall_post_process_vm_readv(res, pid, lvec, liovcnt, \ - rvec, riovcnt, flags) \ - __sanitizer_syscall_post_impl_process_vm_readv( \ - res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ +#define __sanitizer_syscall_post_process_vm_readv(res, pid, lvec, liovcnt, \ + rvec, riovcnt, flags) \ + __sanitizer_syscall_post_impl_process_vm_readv( \ + res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ (long)(riovcnt), (long)(flags)) -#define __sanitizer_syscall_pre_process_vm_writev(pid, lvec, liovcnt, rvec, \ - riovcnt, flags) \ - __sanitizer_syscall_pre_impl_process_vm_writev( \ - (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ +#define __sanitizer_syscall_pre_process_vm_writev(pid, lvec, liovcnt, rvec, \ + riovcnt, flags) \ + __sanitizer_syscall_pre_impl_process_vm_writev( \ + (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ (long)(riovcnt), (long)(flags)) -#define __sanitizer_syscall_post_process_vm_writev(res, pid, lvec, liovcnt, \ - rvec, riovcnt, flags) \ - __sanitizer_syscall_post_impl_process_vm_writev( \ - res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ +#define __sanitizer_syscall_post_process_vm_writev(res, pid, lvec, liovcnt, \ + rvec, riovcnt, flags) \ + __sanitizer_syscall_post_impl_process_vm_writev( \ + res, (long)(pid), (long)(lvec), (long)(liovcnt), (long)(rvec), \ (long)(riovcnt), (long)(flags)) -#define __sanitizer_syscall_pre_fork() \ - __sanitizer_syscall_pre_impl_fork() -#define __sanitizer_syscall_post_fork(res) \ +#define __sanitizer_syscall_pre_fork() __sanitizer_syscall_pre_impl_fork() +#define __sanitizer_syscall_post_fork(res) \ __sanitizer_syscall_post_impl_fork(res) -#define __sanitizer_syscall_pre_vfork() \ - __sanitizer_syscall_pre_impl_vfork() -#define __sanitizer_syscall_post_vfork(res) \ +#define __sanitizer_syscall_pre_vfork() __sanitizer_syscall_pre_impl_vfork() +#define __sanitizer_syscall_post_vfork(res) \ __sanitizer_syscall_post_impl_vfork(res) #define __sanitizer_syscall_pre_sigaction(signum, act, oldact) \ __sanitizer_syscall_pre_impl_sigaction((long)signum, (long)act, (long)oldact) @@ -2699,6 +2706,13 @@ void __sanitizer_syscall_pre_impl_epoll_pwait(long epfd, long events, void __sanitizer_syscall_post_impl_epoll_pwait(long res, long epfd, long events, long maxevents, long timeout, long sigmask, long sigsetsize); +void __sanitizer_syscall_pre_impl_epoll_pwait2(long epfd, long events, + long maxevents, long timeout, + long sigmask, long sigsetsize); +void __sanitizer_syscall_post_impl_epoll_pwait2(long res, long epfd, + long events, long maxevents, + long timeout, long sigmask, + long sigsetsize); void __sanitizer_syscall_pre_impl_gethostname(long name, long len); void __sanitizer_syscall_post_impl_gethostname(long res, long name, long len); void __sanitizer_syscall_pre_impl_sethostname(long name, long len); @@ -3080,7 +3094,7 @@ void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act, void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss); void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss); #ifdef __cplusplus -} // extern "C" +} // extern "C" #endif -#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H +#endif // SANITIZER_LINUX_SYSCALL_HOOKS_H diff --git a/compiler-rt/include/sanitizer/tsan_interface.h b/compiler-rt/include/sanitizer/tsan_interface.h index 565aa391a9f..2782e61fb8c 100644 --- a/compiler-rt/include/sanitizer/tsan_interface.h +++ b/compiler-rt/include/sanitizer/tsan_interface.h @@ -169,6 +169,9 @@ void __tsan_on_initialize(); // if TSan should exit as if issues were detected. int __tsan_on_finalize(int failed); +// Release TSan internal memory in a best-effort manner. +void __tsan_flush_memory(); + #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/lib/asan/asan_allocator.cpp b/compiler-rt/lib/asan/asan_allocator.cpp index 414fba3b427..3fa36742060 100644 --- a/compiler-rt/lib/asan/asan_allocator.cpp +++ b/compiler-rt/lib/asan/asan_allocator.cpp @@ -102,19 +102,18 @@ class ChunkHeader { public: uptr UsedSize() const { - uptr R = user_requested_size_lo; - if (sizeof(uptr) > sizeof(user_requested_size_lo)) - R += (uptr)user_requested_size_hi << (8 * sizeof(user_requested_size_lo)); - return R; + static_assert(sizeof(user_requested_size_lo) == 4, + "Expression below requires this"); + return FIRST_32_SECOND_64(0, ((uptr)user_requested_size_hi << 32)) + + user_requested_size_lo; } void SetUsedSize(uptr size) { user_requested_size_lo = size; - if (sizeof(uptr) > sizeof(user_requested_size_lo)) { - size >>= (8 * sizeof(user_requested_size_lo)); - user_requested_size_hi = size; - CHECK_EQ(user_requested_size_hi, size); - } + static_assert(sizeof(user_requested_size_lo) == 4, + "Expression below requires this"); + user_requested_size_hi = FIRST_32_SECOND_64(0, size >> 32); + CHECK_EQ(UsedSize(), size); } void SetAllocContext(u32 tid, u32 stack) { @@ -522,7 +521,7 @@ struct Allocator { size > max_user_defined_malloc_size) { if (AllocatorMayReturnNull()) { Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n", - (void*)size); + size); return nullptr; } uptr malloc_limit = @@ -908,13 +907,6 @@ AllocType AsanChunkView::GetAllocType() const { return (AllocType)chunk_->alloc_type; } -static StackTrace GetStackTraceFromId(u32 id) { - CHECK(id); - StackTrace res = StackDepotGet(id); - CHECK(res.trace); - return res; -} - u32 AsanChunkView::GetAllocStackId() const { u32 tid = 0; u32 stack = 0; @@ -931,14 +923,6 @@ u32 AsanChunkView::GetFreeStackId() const { return stack; } -StackTrace AsanChunkView::GetAllocStack() const { - return GetStackTraceFromId(GetAllocStackId()); -} - -StackTrace AsanChunkView::GetFreeStack() const { - return GetStackTraceFromId(GetFreeStackId()); -} - void InitializeAllocator(const AllocatorOptions &options) { instance.InitLinkerInitialized(options); } diff --git a/compiler-rt/lib/asan/asan_allocator.h b/compiler-rt/lib/asan/asan_allocator.h index 2963e979b55..27d826fb613 100644 --- a/compiler-rt/lib/asan/asan_allocator.h +++ b/compiler-rt/lib/asan/asan_allocator.h @@ -64,8 +64,6 @@ class AsanChunkView { bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; } u32 GetAllocStackId() const; u32 GetFreeStackId() const; - StackTrace GetAllocStack() const; - StackTrace GetFreeStack() const; AllocType GetAllocType() const; bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const { if (addr >= Beg() && (addr + access_size) <= End()) { diff --git a/compiler-rt/lib/asan/asan_debugging.cpp b/compiler-rt/lib/asan/asan_debugging.cpp index c01360b52fc..0b4bf52f249 100644 --- a/compiler-rt/lib/asan/asan_debugging.cpp +++ b/compiler-rt/lib/asan/asan_debugging.cpp @@ -19,6 +19,7 @@ #include "asan_mapping.h" #include "asan_report.h" #include "asan_thread.h" +#include "sanitizer_common/sanitizer_stackdepot.h" namespace { using namespace __asan; @@ -54,11 +55,11 @@ uptr AsanGetStack(uptr addr, uptr *trace, u32 size, u32 *thread_id, StackTrace stack(nullptr, 0); if (alloc_stack) { if (chunk.AllocTid() == kInvalidTid) return 0; - stack = chunk.GetAllocStack(); + stack = StackDepotGet(chunk.GetAllocStackId()); if (thread_id) *thread_id = chunk.AllocTid(); } else { if (chunk.FreeTid() == kInvalidTid) return 0; - stack = chunk.GetFreeStack(); + stack = StackDepotGet(chunk.GetFreeStackId()); if (thread_id) *thread_id = chunk.FreeTid(); } diff --git a/compiler-rt/lib/asan/asan_descriptions.cpp b/compiler-rt/lib/asan/asan_descriptions.cpp index 2ba8a02f841..d7d96168579 100644 --- a/compiler-rt/lib/asan/asan_descriptions.cpp +++ b/compiler-rt/lib/asan/asan_descriptions.cpp @@ -251,7 +251,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr, } str.append("'"); if (var.line > 0) { - str.append(" (line %d)", var.line); + str.append(" (line %zd)", var.line); } if (pos_descr) { Decorator d; @@ -318,7 +318,8 @@ bool DescribeAddressIfGlobal(uptr addr, uptr access_size, } void ShadowAddressDescription::Print() const { - Printf("Address %p is located in the %s area.\n", addr, ShadowNames[kind]); + Printf("Address %p is located in the %s area.\n", (void *)addr, + ShadowNames[kind]); } void GlobalAddressDescription::Print(const char *bug_type) const { @@ -356,7 +357,7 @@ bool GlobalAddressDescription::PointsInsideTheSameVariable( void StackAddressDescription::Print() const { Decorator d; Printf("%s", d.Location()); - Printf("Address %p is located in stack of thread %s", addr, + Printf("Address %p is located in stack of thread %s", (void *)addr, AsanThreadIdAndName(tid).c_str()); if (!frame_descr) { @@ -469,7 +470,7 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size, void WildAddressDescription::Print() const { Printf("Address %p is a wild pointer inside of access range of size %p.\n", - addr, access_size); + (void *)addr, (void *)access_size); } void PrintAddressDescription(uptr addr, uptr access_size, diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp index 45166c06487..7cd9fe911af 100644 --- a/compiler-rt/lib/asan/asan_errors.cpp +++ b/compiler-rt/lib/asan/asan_errors.cpp @@ -46,10 +46,9 @@ void ErrorDeadlySignal::Print() { void ErrorDoubleFree::Print() { Decorator d; Printf("%s", d.Error()); - Report( - "ERROR: AddressSanitizer: attempting %s on %p in thread %s:\n", - scariness.GetDescription(), addr_description.addr, - AsanThreadIdAndName(tid).c_str()); + Report("ERROR: AddressSanitizer: attempting %s on %p in thread %s:\n", + scariness.GetDescription(), (void *)addr_description.addr, + AsanThreadIdAndName(tid).c_str()); Printf("%s", d.Default()); scariness.Print(); GET_STACK_TRACE_FATAL(second_free_stack->trace[0], @@ -62,10 +61,9 @@ void ErrorDoubleFree::Print() { void ErrorNewDeleteTypeMismatch::Print() { Decorator d; Printf("%s", d.Error()); - Report( - "ERROR: AddressSanitizer: %s on %p in thread %s:\n", - scariness.GetDescription(), addr_description.addr, - AsanThreadIdAndName(tid).c_str()); + Report("ERROR: AddressSanitizer: %s on %p in thread %s:\n", + scariness.GetDescription(), (void *)addr_description.addr, + AsanThreadIdAndName(tid).c_str()); Printf("%s object passed to delete has wrong type:\n", d.Default()); if (delete_size != 0) { Printf( @@ -106,7 +104,7 @@ void ErrorFreeNotMalloced::Print() { Report( "ERROR: AddressSanitizer: attempting free on address " "which was not malloc()-ed: %p in thread %s\n", - addr_description.Address(), AsanThreadIdAndName(tid).c_str()); + (void *)addr_description.Address(), AsanThreadIdAndName(tid).c_str()); Printf("%s", d.Default()); CHECK_GT(free_stack->size, 0); scariness.Print(); @@ -126,7 +124,7 @@ void ErrorAllocTypeMismatch::Print() { Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n", scariness.GetDescription(), alloc_names[alloc_type], - dealloc_names[dealloc_type], addr_description.Address()); + dealloc_names[dealloc_type], (void *)addr_description.Address()); Printf("%s", d.Default()); CHECK_GT(dealloc_stack->size, 0); scariness.Print(); @@ -145,7 +143,7 @@ void ErrorMallocUsableSizeNotOwned::Print() { Report( "ERROR: AddressSanitizer: attempting to call malloc_usable_size() for " "pointer which is not owned: %p\n", - addr_description.Address()); + (void *)addr_description.Address()); Printf("%s", d.Default()); stack->Print(); addr_description.Print(); @@ -158,7 +156,7 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() { Report( "ERROR: AddressSanitizer: attempting to call " "__sanitizer_get_allocated_size() for pointer which is not owned: %p\n", - addr_description.Address()); + (void *)addr_description.Address()); Printf("%s", d.Default()); stack->Print(); addr_description.Print(); @@ -298,9 +296,10 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() { Report( "ERROR: AddressSanitizer: %s: memory ranges [%p,%p) and [%p, %p) " "overlap\n", - bug_type, addr1_description.Address(), - addr1_description.Address() + length1, addr2_description.Address(), - addr2_description.Address() + length2); + bug_type, (void *)addr1_description.Address(), + (void *)(addr1_description.Address() + length1), + (void *)addr2_description.Address(), + (void *)(addr2_description.Address() + length2)); Printf("%s", d.Default()); scariness.Print(); stack->Print(); @@ -329,10 +328,10 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() { " end : %p\n" " old_mid : %p\n" " new_mid : %p\n", - beg, end, old_mid, new_mid); + (void *)beg, (void *)end, (void *)old_mid, (void *)new_mid); uptr granularity = SHADOW_GRANULARITY; if (!IsAligned(beg, granularity)) - Report("ERROR: beg is not aligned by %d\n", granularity); + Report("ERROR: beg is not aligned by %zu\n", granularity); stack->Print(); ReportErrorSummary(scariness.GetDescription(), stack); } @@ -341,7 +340,7 @@ void ErrorODRViolation::Print() { Decorator d; Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(), - global1.beg); + (void *)global1.beg); Printf("%s", d.Default()); InternalScopedString g1_loc; InternalScopedString g2_loc; @@ -371,7 +370,8 @@ void ErrorInvalidPointerPair::Print() { Decorator d; Printf("%s", d.Error()); Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(), - addr1_description.Address(), addr2_description.Address()); + (void *)addr1_description.Address(), + (void *)addr2_description.Address()); Printf("%s", d.Default()); GET_STACK_TRACE_FATAL(pc, bp); stack.Print(); @@ -538,7 +538,8 @@ static void PrintLegend(InternalScopedString *str) { static void PrintShadowBytes(InternalScopedString *str, const char *before, u8 *bytes, u8 *guilty, uptr n) { Decorator d; - if (before) str->append("%s%p:", before, bytes); + if (before) + str->append("%s%p:", before, (void *)bytes); for (uptr i = 0; i < n; i++) { u8 *p = bytes + i; const char *before = @@ -575,7 +576,7 @@ void ErrorGeneric::Print() { Printf("%s", d.Error()); uptr addr = addr_description.Address(); Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n", - bug_descr, (void *)addr, pc, bp, sp); + bug_descr, (void *)addr, (void *)pc, (void *)bp, (void *)sp); Printf("%s", d.Default()); Printf("%s%s of size %zu at %p thread %s%s\n", d.Access(), diff --git a/compiler-rt/lib/asan/asan_fake_stack.cpp b/compiler-rt/lib/asan/asan_fake_stack.cpp index bf5c342ee59..07681c10de9 100644 --- a/compiler-rt/lib/asan/asan_fake_stack.cpp +++ b/compiler-rt/lib/asan/asan_fake_stack.cpp @@ -54,10 +54,11 @@ FakeStack *FakeStack::Create(uptr stack_size_log) { : MmapOrDie(size, "FakeStack")); res->stack_size_log_ = stack_size_log; u8 *p = reinterpret_cast(res); - VReport(1, "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " + VReport(1, + "T%d: FakeStack created: %p -- %p stack_size_log: %zd; " "mmapped %zdK, noreserve=%d \n", - GetCurrentTidOrInvalid(), p, - p + FakeStack::RequiredSize(stack_size_log), stack_size_log, + GetCurrentTidOrInvalid(), (void *)p, + (void *)(p + FakeStack::RequiredSize(stack_size_log)), stack_size_log, size >> 10, flags()->uar_noreserve); return res; } diff --git a/compiler-rt/lib/asan/asan_fuchsia.cpp b/compiler-rt/lib/asan/asan_fuchsia.cpp index b0c7255144a..15381d5bd0e 100644 --- a/compiler-rt/lib/asan/asan_fuchsia.cpp +++ b/compiler-rt/lib/asan/asan_fuchsia.cpp @@ -31,7 +31,8 @@ namespace __asan { // AsanInitInternal->InitializeHighMemEnd (asan_rtl.cpp). // Just do some additional sanity checks here. void InitializeShadowMemory() { - if (Verbosity()) PrintAddressSpaceLayout(); + if (Verbosity()) + PrintAddressSpaceLayout(); // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address. __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel; @@ -62,7 +63,34 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { UNIMPLEMENTED(); } -bool PlatformUnpoisonStacks() { return false; } +bool PlatformUnpoisonStacks() { + // The current sp might not point to the default stack. This + // could be because we are in a crash stack from fuzzing for example. + // Unpoison the default stack and the current stack page. + AsanThread *curr_thread = GetCurrentThread(); + CHECK(curr_thread != nullptr); + uptr top = curr_thread->stack_top(); + uptr bottom = curr_thread->stack_bottom(); + // The default stack grows from top to bottom. (bottom < top). + + uptr local_stack = reinterpret_cast(__builtin_frame_address(0)); + if (local_stack >= bottom && local_stack <= top) { + // The current stack is the default stack. + // We only need to unpoison from where we are using until the end. + bottom = RoundDownTo(local_stack, GetPageSize()); + UnpoisonStack(bottom, top, "default"); + } else { + // The current stack is not the default stack. + // Unpoison the entire default stack and the current stack page. + UnpoisonStack(bottom, top, "default"); + bottom = RoundDownTo(local_stack, GetPageSize()); + top = bottom + GetPageSize(); + UnpoisonStack(bottom, top, "unknown"); + return true; + } + + return false; +} // We can use a plain thread_local variable for TSD. static thread_local void *per_thread; @@ -90,14 +118,12 @@ struct AsanThread::InitOptions { // Shared setup between thread creation and startup for the initial thread. static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid, - uptr user_id, bool detached, - const char *name) { + bool detached, const char *name) { // In lieu of AsanThread::Create. AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__); AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; - u32 tid = - asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args); + u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args); asanThreadRegistry().SetThreadName(tid, name); return thread; @@ -124,7 +150,7 @@ AsanThread *CreateMainThread() { CHECK_NE(__sanitizer::MainThreadStackBase, 0); CHECK_GT(__sanitizer::MainThreadStackSize, 0); AsanThread *t = CreateAsanThread( - nullptr, 0, reinterpret_cast(self), true, + nullptr, 0, true, _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name, sizeof(name)) == ZX_OK ? name @@ -148,13 +174,13 @@ static void *BeforeThreadCreateHook(uptr user_id, bool detached, uptr stack_size) { EnsureMainThreadIDIsCorrect(); // Strict init-order checking is thread-hostile. - if (flags()->strict_init_order) StopInitOrderChecking(); + if (flags()->strict_init_order) + StopInitOrderChecking(); GET_STACK_TRACE_THREAD; u32 parent_tid = GetCurrentTidOrInvalid(); - AsanThread *thread = - CreateAsanThread(&stack, parent_tid, user_id, detached, name); + AsanThread *thread = CreateAsanThread(&stack, parent_tid, detached, name); // On other systems, AsanThread::Init() is called from the new // thread itself. But on Fuchsia we already know the stack address diff --git a/compiler-rt/lib/asan/asan_globals.cpp b/compiler-rt/lib/asan/asan_globals.cpp index 9d7dbc6f264..5f56fe6f457 100644 --- a/compiler-rt/lib/asan/asan_globals.cpp +++ b/compiler-rt/lib/asan/asan_globals.cpp @@ -35,7 +35,7 @@ struct ListOfGlobals { ListOfGlobals *next; }; -static BlockingMutex mu_for_globals(LINKER_INITIALIZED); +static Mutex mu_for_globals; static LowLevelAllocator allocator_for_globals; static ListOfGlobals *list_of_all_globals; @@ -85,12 +85,12 @@ static void ReportGlobal(const Global &g, const char *prefix) { Report( "%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu " "odr_indicator=%p\n", - prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name, + prefix, (void *)&g, (void *)g.beg, g.size, g.size_with_redzone, g.name, g.module_name, g.has_dynamic_init, (void *)g.odr_indicator); if (g.location) { - Report(" location (%p): name=%s[%p], %d %d\n", g.location, - g.location->filename, g.location->filename, g.location->line_no, - g.location->column_no); + Report(" location (%p): name=%s[%p], %d %d\n", (void *)g.location, + g.location->filename, (void *)g.location->filename, + g.location->line_no, g.location->column_no); } } @@ -108,7 +108,7 @@ static u32 FindRegistrationSite(const Global *g) { int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites, int max_globals) { if (!flags()->report_globals) return 0; - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); int res = 0; for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { const Global &g = *l->g; @@ -257,7 +257,7 @@ static void UnregisterGlobal(const Global *g) { } void StopInitOrderChecking() { - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); if (!flags()->check_initialization_order || !dynamic_init_globals) return; flags()->check_initialization_order = false; @@ -359,7 +359,7 @@ void __asan_register_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; GET_STACK_TRACE_MALLOC; u32 stack_id = StackDepotPut(stack); - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); if (!global_registration_site_vector) { global_registration_site_vector = new (allocator_for_globals) GlobalRegistrationSiteVector; @@ -369,7 +369,8 @@ void __asan_register_globals(__asan_global *globals, uptr n) { global_registration_site_vector->push_back(site); if (flags()->report_globals >= 2) { PRINT_CURRENT_STACK(); - Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]); + Printf("=== ID %d; %p %p\n", stack_id, (void *)&globals[0], + (void *)&globals[n - 1]); } for (uptr i = 0; i < n; i++) { if (SANITIZER_WINDOWS && globals[i].beg == 0) { @@ -398,7 +399,7 @@ void __asan_register_globals(__asan_global *globals, uptr n) { // We must do this when a shared objects gets dlclosed. void __asan_unregister_globals(__asan_global *globals, uptr n) { if (!flags()->report_globals) return; - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); for (uptr i = 0; i < n; i++) { if (SANITIZER_WINDOWS && globals[i].beg == 0) { // Skip globals that look like padding from the MSVC incremental linker. @@ -424,7 +425,7 @@ void __asan_before_dynamic_init(const char *module_name) { bool strict_init_order = flags()->strict_init_order; CHECK(module_name); CHECK(asan_inited); - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); if (flags()->report_globals >= 3) Printf("DynInitPoison module: %s\n", module_name); for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { @@ -448,7 +449,7 @@ void __asan_after_dynamic_init() { !dynamic_init_globals) return; CHECK(asan_inited); - BlockingMutexLock lock(&mu_for_globals); + Lock lock(&mu_for_globals); // FIXME: Optionally report that we're unpoisoning globals from a module. for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) { DynInitGlobal &dyn_g = (*dynamic_init_globals)[i]; diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index d0a6dd48a74..b28909152e2 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -49,8 +49,8 @@ namespace __asan { ASAN_READ_RANGE((ctx), (s), \ common_flags()->strict_string_checks ? (len) + 1 : (n)) -#define ASAN_READ_STRING(ctx, s, n) \ - ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n)) +# define ASAN_READ_STRING(ctx, s, n) \ + ASAN_READ_STRING_OF_LEN((ctx), (s), internal_strlen(s), (n)) static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) { #if SANITIZER_INTERCEPT_STRNLEN @@ -370,9 +370,9 @@ DEFINE_REAL(char*, index, const char *string, int c) ASAN_INTERCEPTOR_ENTER(ctx, strcat); ENSURE_ASAN_INITED(); if (flags()->replace_str) { - uptr from_length = REAL(strlen)(from); + uptr from_length = internal_strlen(from); ASAN_READ_RANGE(ctx, from, from_length + 1); - uptr to_length = REAL(strlen)(to); + uptr to_length = internal_strlen(to); ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); // If the copying actually happens, the |from| string should not overlap @@ -394,7 +394,7 @@ INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) { uptr from_length = MaybeRealStrnlen(from, size); uptr copy_length = Min(size, from_length + 1); ASAN_READ_RANGE(ctx, from, copy_length); - uptr to_length = REAL(strlen)(to); + uptr to_length = internal_strlen(to); ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length); ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1); if (from_length > 0) { @@ -419,7 +419,7 @@ INTERCEPTOR(char *, strcpy, char *to, const char *from) { } ENSURE_ASAN_INITED(); if (flags()->replace_str) { - uptr from_size = REAL(strlen)(from) + 1; + uptr from_size = internal_strlen(from) + 1; CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size); ASAN_READ_RANGE(ctx, from, from_size); ASAN_WRITE_RANGE(ctx, to, from_size); @@ -432,7 +432,7 @@ INTERCEPTOR(char*, strdup, const char *s) { ASAN_INTERCEPTOR_ENTER(ctx, strdup); if (UNLIKELY(!asan_inited)) return internal_strdup(s); ENSURE_ASAN_INITED(); - uptr length = REAL(strlen)(s); + uptr length = internal_strlen(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); } @@ -448,7 +448,7 @@ INTERCEPTOR(char*, __strdup, const char *s) { ASAN_INTERCEPTOR_ENTER(ctx, strdup); if (UNLIKELY(!asan_inited)) return internal_strdup(s); ENSURE_ASAN_INITED(); - uptr length = REAL(strlen)(s); + uptr length = internal_strlen(s); if (flags()->replace_str) { ASAN_READ_RANGE(ctx, s, length + 1); } @@ -581,7 +581,7 @@ INTERCEPTOR(int, atexit, void (*func)()) { #if CAN_SANITIZE_LEAKS __lsan::ScopedInterceptorDisabler disabler; #endif - // Avoid calling real atexit as it is unrechable on at least on Linux. + // Avoid calling real atexit as it is unreachable on at least on Linux. int res = REAL(__cxa_atexit)((void (*)(void *a))func, nullptr, nullptr); REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr); return res; diff --git a/compiler-rt/lib/asan/asan_interceptors.h b/compiler-rt/lib/asan/asan_interceptors.h index a9249dea45b..047b044c8bf 100644 --- a/compiler-rt/lib/asan/asan_interceptors.h +++ b/compiler-rt/lib/asan/asan_interceptors.h @@ -133,29 +133,30 @@ DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size) DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen) DECLARE_REAL(char*, strstr, const char *s1, const char *s2) -#if !SANITIZER_MAC -#define ASAN_INTERCEPT_FUNC(name) \ - do { \ - if (!INTERCEPT_FUNCTION(name)) \ - VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \ - } while (0) -#define ASAN_INTERCEPT_FUNC_VER(name, ver) \ - do { \ - if (!INTERCEPT_FUNCTION_VER(name, ver)) \ - VReport(1, "AddressSanitizer: failed to intercept '%s@@%s'\n", #name, \ - #ver); \ - } while (0) -#define ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \ - do { \ - if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \ - VReport(1, "AddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \ - #name, #ver, #name); \ - } while (0) +# if !SANITIZER_MAC +# define ASAN_INTERCEPT_FUNC(name) \ + do { \ + if (!INTERCEPT_FUNCTION(name)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \ + } while (0) +# define ASAN_INTERCEPT_FUNC_VER(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver)) \ + VReport(1, "AddressSanitizer: failed to intercept '%s@@%s'\n", \ + #name, ver); \ + } while (0) +# define ASAN_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver) \ + do { \ + if (!INTERCEPT_FUNCTION_VER(name, ver) && !INTERCEPT_FUNCTION(name)) \ + VReport(1, \ + "AddressSanitizer: failed to intercept '%s@@%s' or '%s'\n", \ + #name, ver, #name); \ + } while (0) -#else +# else // OS X interceptors don't need to be initialized with INTERCEPT_FUNCTION. -#define ASAN_INTERCEPT_FUNC(name) -#endif // SANITIZER_MAC +# define ASAN_INTERCEPT_FUNC(name) +# endif // SANITIZER_MAC #endif // !SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/asan/asan_linux.cpp b/compiler-rt/lib/asan/asan_linux.cpp index 4bcbe5d02e3..ad3693d5e6a 100644 --- a/compiler-rt/lib/asan/asan_linux.cpp +++ b/compiler-rt/lib/asan/asan_linux.cpp @@ -128,8 +128,8 @@ void AsanCheckIncompatibleRT() {} #else static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, void *data) { - VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", - info->dlpi_name, info->dlpi_addr); + VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name, + (void *)info->dlpi_addr); // Continue until the first dynamic library is found if (!info->dlpi_name || info->dlpi_name[0] == 0) diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp index c6bec8551bc..bab80b96f58 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -21,129 +21,66 @@ # include "asan_interceptors.h" # include "asan_internal.h" # include "asan_stack.h" +# include "lsan/lsan_common.h" # include "sanitizer_common/sanitizer_allocator_checks.h" +# include "sanitizer_common/sanitizer_allocator_dlsym.h" # include "sanitizer_common/sanitizer_errno.h" # include "sanitizer_common/sanitizer_tls_get_addr.h" // ---------------------- Replacement functions ---------------- {{{1 using namespace __asan; -static uptr allocated_for_dlsym; -static uptr last_dlsym_alloc_size_in_words; -static const uptr kDlsymAllocPoolSize = 1024; -static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; - -static inline bool IsInDlsymAllocPool(const void *ptr) { - uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]); -} - -static void *AllocateFromLocalPool(uptr size_in_bytes) { - uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; - void *mem = (void*)&alloc_memory_for_dlsym[allocated_for_dlsym]; - last_dlsym_alloc_size_in_words = size_in_words; - allocated_for_dlsym += size_in_words; - CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); - return mem; -} - -static void DeallocateFromLocalPool(const void *ptr) { - // Hack: since glibc 2.27 dlsym no longer uses stack-allocated memory to store - // error messages and instead uses malloc followed by free. To avoid pool - // exhaustion due to long object filenames, handle that special case here. - uptr prev_offset = allocated_for_dlsym - last_dlsym_alloc_size_in_words; - void *prev_mem = (void*)&alloc_memory_for_dlsym[prev_offset]; - if (prev_mem == ptr) { - REAL(memset)(prev_mem, 0, last_dlsym_alloc_size_in_words * kWordSize); - allocated_for_dlsym = prev_offset; - last_dlsym_alloc_size_in_words = 0; +struct DlsymAlloc : public DlSymAllocator { + static bool UseImpl() { return asan_init_is_running; } + static void OnAllocate(const void *ptr, uptr size) { +# if CAN_SANITIZE_LEAKS + // Suppress leaks from dlerror(). Previously dlsym hack on global array was + // used by leak sanitizer as a root region. + __lsan_register_root_region(ptr, size); +# endif } -} - -static int PosixMemalignFromLocalPool(void **memptr, uptr alignment, - uptr size_in_bytes) { - if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) - return errno_EINVAL; - - CHECK(alignment >= kWordSize); - - uptr addr = (uptr)&alloc_memory_for_dlsym[allocated_for_dlsym]; - uptr aligned_addr = RoundUpTo(addr, alignment); - uptr aligned_size = RoundUpTo(size_in_bytes, kWordSize); - - uptr *end_mem = (uptr*)(aligned_addr + aligned_size); - uptr allocated = end_mem - alloc_memory_for_dlsym; - if (allocated >= kDlsymAllocPoolSize) - return errno_ENOMEM; - - allocated_for_dlsym = allocated; - *memptr = (void*)aligned_addr; - return 0; -} - -static inline bool MaybeInDlsym() { - // Fuchsia doesn't use dlsym-based interceptors. - return !SANITIZER_FUCHSIA && asan_init_is_running; -} - -static inline bool UseLocalPool() { return MaybeInDlsym(); } - -static void *ReallocFromLocalPool(void *ptr, uptr size) { - const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(UseLocalPool())) { - new_ptr = AllocateFromLocalPool(size); - } else { - ENSURE_ASAN_INITED(); - GET_STACK_TRACE_MALLOC; - new_ptr = asan_malloc(size, &stack); + static void OnFree(const void *ptr, uptr size) { +# if CAN_SANITIZE_LEAKS + __lsan_unregister_root_region(ptr, size); +# endif } - internal_memcpy(new_ptr, ptr, copy_size); - return new_ptr; -} +}; INTERCEPTOR(void, free, void *ptr) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - DeallocateFromLocalPool(ptr); - return; - } + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; asan_free(ptr, &stack, FROM_MALLOC); } #if SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void, cfree, void *ptr) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) - return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); GET_STACK_TRACE_FREE; asan_free(ptr, &stack, FROM_MALLOC); } #endif // SANITIZER_INTERCEPT_CFREE INTERCEPTOR(void*, malloc, uptr size) { - if (UNLIKELY(UseLocalPool())) - // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. - return AllocateFromLocalPool(size); + if (DlsymAlloc::Use()) + return DlsymAlloc::Allocate(size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_malloc(size, &stack); } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { - if (UNLIKELY(UseLocalPool())) - // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. - return AllocateFromLocalPool(nmemb * size); + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_calloc(nmemb, size, &stack); } INTERCEPTOR(void*, realloc, void *ptr, uptr size) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) - return ReallocFromLocalPool(ptr, size); - if (UNLIKELY(UseLocalPool())) - return AllocateFromLocalPool(size); + if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Realloc(ptr, size); ENSURE_ASAN_INITED(); GET_STACK_TRACE_MALLOC; return asan_realloc(ptr, size, &stack); @@ -205,8 +142,6 @@ INTERCEPTOR(int, mallopt, int cmd, int value) { #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) { - if (UNLIKELY(UseLocalPool())) - return PosixMemalignFromLocalPool(memptr, alignment, size); GET_STACK_TRACE_MALLOC; return asan_posix_memalign(memptr, alignment, size, &stack); } diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp index 5f215fe0f9b..d97af91e692 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -66,7 +66,7 @@ void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { uptr end = ptr + size; if (Verbosity()) { Printf("__asan_%spoison_intra_object_redzone [%p,%p) %zd\n", - poison ? "" : "un", ptr, end, size); + poison ? "" : "un", (void *)ptr, (void *)end, size); if (Verbosity() >= 2) PRINT_CURRENT_STACK(); } diff --git a/compiler-rt/lib/asan/asan_report.cpp b/compiler-rt/lib/asan/asan_report.cpp index 03f1ed2b018..1f266334b31 100644 --- a/compiler-rt/lib/asan/asan_report.cpp +++ b/compiler-rt/lib/asan/asan_report.cpp @@ -32,12 +32,12 @@ namespace __asan { static void (*error_report_callback)(const char*); static char *error_message_buffer = nullptr; static uptr error_message_buffer_pos = 0; -static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED); +static Mutex error_message_buf_mutex; static const unsigned kAsanBuggyPcPoolSize = 25; static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize]; void AppendToErrorMessageBuffer(const char *buffer) { - BlockingMutexLock l(&error_message_buf_mutex); + Lock l(&error_message_buf_mutex); if (!error_message_buffer) { error_message_buffer = (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__); @@ -67,14 +67,14 @@ static void PrintZoneForPointer(uptr ptr, uptr zone_ptr, const char *zone_name) { if (zone_ptr) { if (zone_name) { - Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", - ptr, zone_ptr, zone_name); + Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n", (void *)ptr, + (void *)zone_ptr, zone_name); } else { Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n", - ptr, zone_ptr); + (void *)ptr, (void *)zone_ptr); } } else { - Printf("malloc_zone_from_ptr(%p) = 0\n", ptr); + Printf("malloc_zone_from_ptr(%p) = 0\n", (void *)ptr); } } @@ -155,10 +155,10 @@ class ScopedInErrorReport { DumpProcessMap(); // Copy the message buffer so that we could start logging without holding a - // lock that gets aquired during printing. + // lock that gets acquired during printing. InternalMmapVector buffer_copy(kErrorMessageBufferSize); { - BlockingMutexLock l(&error_message_buf_mutex); + Lock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); // Clear error_message_buffer so that if we find other errors @@ -435,9 +435,10 @@ static inline void CheckForInvalidPointerPair(void *p1, void *p2) { void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name, BufferedStackTrace *stack) { ScopedInErrorReport in_report; - Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n" - "This is an unrecoverable problem, exiting now.\n", - addr); + Printf( + "mz_realloc(%p) -- attempting to realloc unallocated memory.\n" + "This is an unrecoverable problem, exiting now.\n", + (void *)addr); PrintZoneForPointer(addr, zone_ptr, zone_name); stack->Print(); DescribeAddressIfHeap(addr); @@ -490,7 +491,7 @@ void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write, } void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) { - BlockingMutexLock l(&error_message_buf_mutex); + Lock l(&error_message_buf_mutex); error_report_callback = callback; } diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index bfaa3bc2702..1b150b393cf 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -557,7 +557,8 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) { "False positive error reports may follow\n" "For details see " "https://github.com/google/sanitizers/issues/189\n", - type, top, bottom, top - bottom, top - bottom); + type, (void *)top, (void *)bottom, (void *)(top - bottom), + top - bottom); return; } PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0); diff --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp index 6e6260d3413..fc6de39622b 100644 --- a/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -33,7 +33,7 @@ static void ProtectGap(uptr addr, uptr size) { "protect_shadow_gap=0:" " not protecting shadow gap, allocating gap's shadow\n" "|| `[%p, %p]` || ShadowGap's shadow ||\n", - GapShadowBeg, GapShadowEnd); + (void*)GapShadowBeg, (void*)GapShadowEnd); ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd, "unprotected gap shadow"); return; @@ -113,7 +113,7 @@ void InitializeShadowMemory() { "Shadow memory range interleaves with an existing memory mapping. " "ASan cannot proceed correctly. ABORTING.\n"); Report("ASan shadow was supposed to be located in the [%p-%p] range.\n", - shadow_start, kHighShadowEnd); + (void*)shadow_start, (void*)kHighShadowEnd); MaybeReportLinuxPIEBug(); DumpProcessMap(); Die(); diff --git a/compiler-rt/lib/asan/asan_stats.cpp b/compiler-rt/lib/asan/asan_stats.cpp index 00ded8f5ef5..9a715ea76fe 100644 --- a/compiler-rt/lib/asan/asan_stats.cpp +++ b/compiler-rt/lib/asan/asan_stats.cpp @@ -62,11 +62,11 @@ void AsanStats::MergeFrom(const AsanStats *stats) { dst_ptr[i] += src_ptr[i]; } -static BlockingMutex print_lock(LINKER_INITIALIZED); +static Mutex print_lock; static AsanStats unknown_thread_stats(LINKER_INITIALIZED); static AsanStats dead_threads_stats(LINKER_INITIALIZED); -static BlockingMutex dead_threads_stats_lock(LINKER_INITIALIZED); +static Mutex dead_threads_stats_lock; // Required for malloc_zone_statistics() on OS X. This can't be stored in // per-thread AsanStats. static uptr max_malloced_memory; @@ -87,7 +87,7 @@ static void GetAccumulatedStats(AsanStats *stats) { } stats->MergeFrom(&unknown_thread_stats); { - BlockingMutexLock lock(&dead_threads_stats_lock); + Lock lock(&dead_threads_stats_lock); stats->MergeFrom(&dead_threads_stats); } // This is not very accurate: we may miss allocation peaks that happen @@ -99,7 +99,7 @@ static void GetAccumulatedStats(AsanStats *stats) { } void FlushToDeadThreadStats(AsanStats *stats) { - BlockingMutexLock lock(&dead_threads_stats_lock); + Lock lock(&dead_threads_stats_lock); dead_threads_stats.MergeFrom(stats); stats->Clear(); } @@ -122,11 +122,11 @@ static void PrintAccumulatedStats() { AsanStats stats; GetAccumulatedStats(&stats); // Use lock to keep reports from mixing up. - BlockingMutexLock lock(&print_lock); + Lock lock(&print_lock); stats.Print(); - StackDepotStats *stack_depot_stats = StackDepotGetStats(); + StackDepotStats stack_depot_stats = StackDepotGetStats(); Printf("Stats: StackDepot: %zd ids; %zdM allocated\n", - stack_depot_stats->n_uniq_ids, stack_depot_stats->allocated >> 20); + stack_depot_stats.n_uniq_ids, stack_depot_stats.allocated >> 20); PrintInternalAllocatorStats(); } diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 35d4467e7b5..930139968ec 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -43,11 +43,11 @@ void AsanThreadContext::OnFinished() { static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)]; static ThreadRegistry *asan_thread_registry; -static BlockingMutex mu_for_thread_context(LINKER_INITIALIZED); +static Mutex mu_for_thread_context; static LowLevelAllocator allocator_for_thread_context; static ThreadContextBase *GetAsanThreadContext(u32 tid) { - BlockingMutexLock lock(&mu_for_thread_context); + Lock lock(&mu_for_thread_context); return new(allocator_for_thread_context) AsanThreadContext(tid); } @@ -83,8 +83,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg, thread->start_routine_ = start_routine; thread->arg_ = arg; AsanThreadContext::CreateThreadContextArgs args = {thread, stack}; - asanThreadRegistry().CreateThread(*reinterpret_cast(thread), detached, - parent_tid, &args); + asanThreadRegistry().CreateThread(0, detached, parent_tid, &args); return thread; } @@ -254,7 +253,7 @@ void AsanThread::Init(const InitOptions *options) { int local = 0; VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(), (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_, - &local); + (void *)&local); } // Fuchsia doesn't use ThreadStart. @@ -443,7 +442,7 @@ AsanThread *GetCurrentThread() { void SetCurrentThread(AsanThread *t) { CHECK(t->context()); - VReport(2, "SetCurrentThread: %p for thread %p\n", t->context(), + VReport(2, "SetCurrentThread: %p for thread %p\n", (void *)t->context(), (void *)GetThreadSelf()); // Make sure we do not reset the current AsanThread. CHECK_EQ(0, AsanTSDGet()); diff --git a/compiler-rt/lib/builtins/README.txt b/compiler-rt/lib/builtins/README.txt index d66d725e7ab..53d656d5086 100644 --- a/compiler-rt/lib/builtins/README.txt +++ b/compiler-rt/lib/builtins/README.txt @@ -271,8 +271,8 @@ switchu8 // There is no C interface to the *_vfp_d8_d15_regs functions. There are // called in the prolog and epilog of Thumb1 functions. When the C++ ABI use -// SJLJ for exceptions, each function with a catch clause or destuctors needs -// to save and restore all registers in it prolog and epliog. But there is +// SJLJ for exceptions, each function with a catch clause or destructors needs +// to save and restore all registers in it prolog and epilog. But there is // no way to access vector and high float registers from thumb1 code, so the // compiler must add call outs to these helper functions in the prolog and // epilog. @@ -311,9 +311,9 @@ double __floatsidfvfp(int a); // Appears to convert from float __floatsisfvfp(int a); // Appears to convert from // int to float. double __floatunssidfvfp(unsigned int a); // Appears to convert from - // unisgned int to double. + // unsigned int to double. float __floatunssisfvfp(unsigned int a); // Appears to convert from - // unisgned int to float. + // unsigned int to float. int __gedf2vfp(double a, double b); // Appears to return __gedf2 // (a >= b) int __gesf2vfp(float a, float b); // Appears to return __gesf2 diff --git a/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S index a3c0a73466e..e1c171262a7 100644 --- a/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S +++ b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S @@ -11,9 +11,9 @@ // // extern float __truncdfsf2vfp(double a); // -// Converts double precision float to signle precision result. +// Converts double precision float to single precision result. // Uses Darwin calling convention where a double precision parameter is -// passed in a R0/R1 pair and a signle precision result is returned in R0. +// passed in a R0/R1 pair and a single precision result is returned in R0. // .syntax unified .p2align 2 diff --git a/compiler-rt/lib/builtins/atomic.c b/compiler-rt/lib/builtins/atomic.c index 64bf72dfa34..4c3ebb99a51 100644 --- a/compiler-rt/lib/builtins/atomic.c +++ b/compiler-rt/lib/builtins/atomic.c @@ -336,6 +336,18 @@ OPTIMISED_CASES return tmp; \ } +#define ATOMIC_RMW_NAND(n, lockfree, type) \ + type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \ + if (lockfree(ptr)) \ + return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \ + Lock *l = lock_for_pointer(ptr); \ + lock(l); \ + type tmp = *ptr; \ + *ptr = ~(tmp & val); \ + unlock(l); \ + return tmp; \ + } + #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) OPTIMISED_CASES #undef OPTIMISED_CASE @@ -351,3 +363,6 @@ OPTIMISED_CASES #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^) OPTIMISED_CASES #undef OPTIMISED_CASE +#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW_NAND(n, lockfree, type) +OPTIMISED_CASES +#undef OPTIMISED_CASE diff --git a/compiler-rt/lib/builtins/clear_cache.c b/compiler-rt/lib/builtins/clear_cache.c index 3c12b74e8fa..da0715914b4 100644 --- a/compiler-rt/lib/builtins/clear_cache.c +++ b/compiler-rt/lib/builtins/clear_cache.c @@ -35,7 +35,7 @@ uintptr_t GetCurrentProcess(void); #include #endif -#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__)) +#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__) || defined(__riscv)) // clang-format off #include #include @@ -166,6 +166,13 @@ void __clear_cache(void *start, void *end) { : "=r"(start_reg) : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr)); assert(start_reg == 0 && "Cache flush syscall failed."); +#elif defined(__riscv) && defined(__OpenBSD__) + struct riscv_sync_icache_args arg; + + arg.addr = (uintptr_t)start; + arg.len = (uintptr_t)end - (uintptr_t)start; + + sysarch(RISCV_SYNC_ICACHE, &arg); #else #if __APPLE__ // On Darwin, sys_icache_invalidate() provides this functionality diff --git a/compiler-rt/lib/builtins/cpu_model.c b/compiler-rt/lib/builtins/cpu_model.c index 6ee42911b20..b8d807ed651 100644 --- a/compiler-rt/lib/builtins/cpu_model.c +++ b/compiler-rt/lib/builtins/cpu_model.c @@ -422,6 +422,22 @@ getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model, *Subtype = INTEL_COREI7_ICELAKE_CLIENT; break; + // Tigerlake: + case 0x8c: + case 0x8d: + CPU = "tigerlake"; + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_TIGERLAKE; + break; + + // Alderlake: + case 0x97: + case 0x9a: + CPU = "alderlake"; + *Type = INTEL_COREI7; + *Subtype = INTEL_COREI7_ALDERLAKE; + break; + // Icelake Xeon: case 0x6a: case 0x6c: diff --git a/compiler-rt/lib/builtins/emutls.c b/compiler-rt/lib/builtins/emutls.c index 98cabd917d6..e112fdf5144 100644 --- a/compiler-rt/lib/builtins/emutls.c +++ b/compiler-rt/lib/builtins/emutls.c @@ -150,7 +150,7 @@ static void win_error(DWORD last_err, const char *hint) { NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) { fprintf(stderr, "Windows error: %s\n", buffer); } else { - fprintf(stderr, "Unkown Windows error: %s\n", hint); + fprintf(stderr, "Unknown Windows error: %s\n", hint); } LocalFree(buffer); } @@ -374,6 +374,21 @@ emutls_get_address_array(uintptr_t index) { return array; } +#ifndef _WIN32 +// Our emulated TLS implementation relies on local state (e.g. for the pthread +// key), and if we duplicate this state across different shared libraries, +// accesses to the same TLS variable from different shared libraries will yield +// different results (see https://github.com/android/ndk/issues/1551 for an +// example). __emutls_get_address is the only external entry point for emulated +// TLS, and by making it default visibility and weak, we can rely on the dynamic +// linker to coalesce multiple copies at runtime and ensure a single unique copy +// of TLS state. This is a best effort; it won't work if the user is linking +// with -Bsymbolic or -Bsymbolic-functions, and it also won't work on Windows, +// where the dynamic linker has no notion of coalescing weak symbols at runtime. +// A more robust solution would be to create a separate shared library for +// emulated TLS, to ensure a single copy of its state. +__attribute__((visibility("default"), weak)) +#endif void *__emutls_get_address(__emutls_control *control) { uintptr_t index = emutls_get_index(control); emutls_address_array *array = emutls_get_address_array(index--); diff --git a/compiler-rt/lib/builtins/fixdfdi.c b/compiler-rt/lib/builtins/fixdfdi.c index 511568fc12f..a48facb6859 100644 --- a/compiler-rt/lib/builtins/fixdfdi.c +++ b/compiler-rt/lib/builtins/fixdfdi.c @@ -42,3 +42,7 @@ AEABI_RTABI di_int __aeabi_d2lz(fp_t a) { return __fixdfdi(a); } COMPILER_RT_ALIAS(__fixdfdi, __aeabi_d2lz) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__fixdfdi, __dtoi64) +#endif diff --git a/compiler-rt/lib/builtins/fixsfdi.c b/compiler-rt/lib/builtins/fixsfdi.c index 0cf71c30311..3a66fb9e2f0 100644 --- a/compiler-rt/lib/builtins/fixsfdi.c +++ b/compiler-rt/lib/builtins/fixsfdi.c @@ -42,3 +42,7 @@ AEABI_RTABI di_int __aeabi_f2lz(fp_t a) { return __fixsfdi(a); } COMPILER_RT_ALIAS(__fixsfdi, __aeabi_f2lz) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__fixsfdi, __stoi64) +#endif diff --git a/compiler-rt/lib/builtins/fixunsdfdi.c b/compiler-rt/lib/builtins/fixunsdfdi.c index ccb256d2c7e..f15f86788e8 100644 --- a/compiler-rt/lib/builtins/fixunsdfdi.c +++ b/compiler-rt/lib/builtins/fixunsdfdi.c @@ -40,3 +40,7 @@ AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) { return __fixunsdfdi(a); } COMPILER_RT_ALIAS(__fixunsdfdi, __aeabi_d2ulz) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__fixunsdfdi, __dtou64) +#endif diff --git a/compiler-rt/lib/builtins/fixunssfdi.c b/compiler-rt/lib/builtins/fixunssfdi.c index 647185fbabf..e8f600df976 100644 --- a/compiler-rt/lib/builtins/fixunssfdi.c +++ b/compiler-rt/lib/builtins/fixunssfdi.c @@ -41,3 +41,7 @@ AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) { return __fixunssfdi(a); } COMPILER_RT_ALIAS(__fixunssfdi, __aeabi_f2ulz) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__fixunssfdi, __stou64) +#endif diff --git a/compiler-rt/lib/builtins/fixunsxfdi.c b/compiler-rt/lib/builtins/fixunsxfdi.c index 097a4e55e93..c8a8061b2cf 100644 --- a/compiler-rt/lib/builtins/fixunsxfdi.c +++ b/compiler-rt/lib/builtins/fixunsxfdi.c @@ -26,7 +26,7 @@ // mmmm mmmm mmmm #if defined(_MSC_VER) && !defined(__clang__) -// MSVC throws a warning about 'unitialized variable use' here, +// MSVC throws a warning about 'uninitialized variable use' here, // disable it for builds that warn-as-error #pragma warning(push) #pragma warning(disable : 4700) diff --git a/compiler-rt/lib/builtins/fixunsxfsi.c b/compiler-rt/lib/builtins/fixunsxfsi.c index 3bc1288d38a..154abcbd35e 100644 --- a/compiler-rt/lib/builtins/fixunsxfsi.c +++ b/compiler-rt/lib/builtins/fixunsxfsi.c @@ -26,7 +26,7 @@ // mmmm mmmm mmmm #if defined(_MSC_VER) && !defined(__clang__) -// MSVC throws a warning about 'unitialized variable use' here, +// MSVC throws a warning about 'uninitialized variable use' here, // disable it for builds that warn-as-error #pragma warning(push) #pragma warning(disable : 4700) diff --git a/compiler-rt/lib/builtins/fixxfdi.c b/compiler-rt/lib/builtins/fixxfdi.c index a7a0464feb9..86cf3767b75 100644 --- a/compiler-rt/lib/builtins/fixxfdi.c +++ b/compiler-rt/lib/builtins/fixxfdi.c @@ -25,7 +25,7 @@ // mmmm mmmm mmmm #if defined(_MSC_VER) && !defined(__clang__) -// MSVC throws a warning about 'unitialized variable use' here, +// MSVC throws a warning about 'uninitialized variable use' here, // disable it for builds that warn-as-error #pragma warning(push) #pragma warning(disable : 4700) diff --git a/compiler-rt/lib/builtins/floatdidf.c b/compiler-rt/lib/builtins/floatdidf.c index 7ecb30bca71..d37c43b1f2f 100644 --- a/compiler-rt/lib/builtins/floatdidf.c +++ b/compiler-rt/lib/builtins/floatdidf.c @@ -101,3 +101,7 @@ AEABI_RTABI double __aeabi_l2d(di_int a) { return __floatdidf(a); } COMPILER_RT_ALIAS(__floatdidf, __aeabi_l2d) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__floatdidf, __i64tod) +#endif diff --git a/compiler-rt/lib/builtins/floatdisf.c b/compiler-rt/lib/builtins/floatdisf.c index faaa1bcb3c8..5c6316431e3 100644 --- a/compiler-rt/lib/builtins/floatdisf.c +++ b/compiler-rt/lib/builtins/floatdisf.c @@ -73,3 +73,7 @@ AEABI_RTABI float __aeabi_l2f(di_int a) { return __floatdisf(a); } COMPILER_RT_ALIAS(__floatdisf, __aeabi_l2f) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__floatdisf, __i64tos) +#endif diff --git a/compiler-rt/lib/builtins/floatundidf.c b/compiler-rt/lib/builtins/floatundidf.c index e5e533042a3..2ec802cdc13 100644 --- a/compiler-rt/lib/builtins/floatundidf.c +++ b/compiler-rt/lib/builtins/floatundidf.c @@ -104,3 +104,7 @@ AEABI_RTABI double __aeabi_ul2d(du_int a) { return __floatundidf(a); } COMPILER_RT_ALIAS(__floatundidf, __aeabi_ul2d) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__floatundidf, __u64tod) +#endif diff --git a/compiler-rt/lib/builtins/floatundisf.c b/compiler-rt/lib/builtins/floatundisf.c index 00d61b0c631..2a4157dc5e4 100644 --- a/compiler-rt/lib/builtins/floatundisf.c +++ b/compiler-rt/lib/builtins/floatundisf.c @@ -70,3 +70,7 @@ AEABI_RTABI float __aeabi_ul2f(du_int a) { return __floatundisf(a); } COMPILER_RT_ALIAS(__floatundisf, __aeabi_ul2f) #endif #endif + +#if defined(__MINGW32__) && defined(__arm__) +COMPILER_RT_ALIAS(__floatundisf, __u64tos) +#endif diff --git a/compiler-rt/lib/builtins/mingw_fixfloat.c b/compiler-rt/lib/builtins/mingw_fixfloat.c deleted file mode 100644 index 945be9d4344..00000000000 --- a/compiler-rt/lib/builtins/mingw_fixfloat.c +++ /dev/null @@ -1,34 +0,0 @@ -//===-- mingw_fixfloat.c - Wrap int/float conversions for arm/windows -----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "int_lib.h" - -COMPILER_RT_ABI di_int __fixdfdi(double a); -COMPILER_RT_ABI di_int __fixsfdi(float a); -COMPILER_RT_ABI du_int __fixunsdfdi(double a); -COMPILER_RT_ABI du_int __fixunssfdi(float a); -COMPILER_RT_ABI double __floatdidf(di_int a); -COMPILER_RT_ABI float __floatdisf(di_int a); -COMPILER_RT_ABI double __floatundidf(du_int a); -COMPILER_RT_ABI float __floatundisf(du_int a); - -COMPILER_RT_ABI di_int __dtoi64(double a) { return __fixdfdi(a); } - -COMPILER_RT_ABI di_int __stoi64(float a) { return __fixsfdi(a); } - -COMPILER_RT_ABI du_int __dtou64(double a) { return __fixunsdfdi(a); } - -COMPILER_RT_ABI du_int __stou64(float a) { return __fixunssfdi(a); } - -COMPILER_RT_ABI double __i64tod(di_int a) { return __floatdidf(a); } - -COMPILER_RT_ABI float __i64tos(di_int a) { return __floatdisf(a); } - -COMPILER_RT_ABI double __u64tod(du_int a) { return __floatundidf(a); } - -COMPILER_RT_ABI float __u64tos(du_int a) { return __floatundisf(a); } diff --git a/compiler-rt/lib/builtins/riscv/restore.S b/compiler-rt/lib/builtins/riscv/restore.S index 12f0d336565..73f64a920d6 100644 --- a/compiler-rt/lib/builtins/riscv/restore.S +++ b/compiler-rt/lib/builtins/riscv/restore.S @@ -93,7 +93,7 @@ __riscv_restore_0: __riscv_restore_12: ld s11, 8(sp) addi sp, sp, 16 - // fallthrough into __riscv_restore_11/10/9/8 + // fallthrough into __riscv_restore_11/10 .globl __riscv_restore_11 .type __riscv_restore_11,@function @@ -143,10 +143,6 @@ __riscv_restore_4: .type __riscv_restore_3,@function .globl __riscv_restore_2 .type __riscv_restore_2,@function - .globl __riscv_restore_1 - .type __riscv_restore_1,@function - .globl __riscv_restore_0 - .type __riscv_restore_0,@function __riscv_restore_3: __riscv_restore_2: ld s2, 0(sp) @@ -154,6 +150,10 @@ __riscv_restore_2: addi sp, sp, 16 // fallthrough into __riscv_restore_1/0 + .globl __riscv_restore_1 + .type __riscv_restore_1,@function + .globl __riscv_restore_0 + .type __riscv_restore_0,@function __riscv_restore_1: __riscv_restore_0: ld s0, 0(sp) diff --git a/compiler-rt/lib/builtins/riscv/save.S b/compiler-rt/lib/builtins/riscv/save.S index d811bf584fc..85501aeb4c2 100644 --- a/compiler-rt/lib/builtins/riscv/save.S +++ b/compiler-rt/lib/builtins/riscv/save.S @@ -174,6 +174,8 @@ __riscv_save_2: .type __riscv_save_1,@function .globl __riscv_save_0 .type __riscv_save_0,@function +__riscv_save_1: +__riscv_save_0: addi sp, sp, -16 sd s0, 0(sp) sd ra, 8(sp) diff --git a/compiler-rt/lib/cfi/cfi.cpp b/compiler-rt/lib/cfi/cfi.cpp index f691cfb94cf..95853208f95 100644 --- a/compiler-rt/lib/cfi/cfi.cpp +++ b/compiler-rt/lib/cfi/cfi.cpp @@ -320,7 +320,7 @@ void InitShadow() { } THREADLOCAL int in_loader; -BlockingMutex shadow_update_lock(LINKER_INITIALIZED); +Mutex shadow_update_lock; void EnterLoader() NO_THREAD_SAFETY_ANALYSIS { if (in_loader == 0) { @@ -359,7 +359,7 @@ ALWAYS_INLINE void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr, return; } CFICheckFn cfi_check = sv.get_cfi_check(); - VReport(2, "__cfi_check at %p\n", cfi_check); + VReport(2, "__cfi_check at %p\n", (void *)cfi_check); cfi_check(CallSiteTypeId, Ptr, DiagData); } @@ -436,11 +436,11 @@ INTERCEPTOR(int, dlclose, void *handle) { return res; } -static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED); +static Mutex interceptor_init_lock; static bool interceptors_inited = false; static void EnsureInterceptorsInitialized() { - BlockingMutexLock lock(&interceptor_init_lock); + Lock lock(&interceptor_init_lock); if (interceptors_inited) return; diff --git a/compiler-rt/lib/dfsan/dfsan.cpp b/compiler-rt/lib/dfsan/dfsan.cpp index 6f9ae141d7a..ce2c04df83a 100644 --- a/compiler-rt/lib/dfsan/dfsan.cpp +++ b/compiler-rt/lib/dfsan/dfsan.cpp @@ -369,37 +369,6 @@ static void SetOrigin(const void *dst, uptr size, u32 origin) { *(u32 *)(end - kOriginAlign) = origin; } -static void WriteShadowInRange(dfsan_label label, uptr beg_shadow_addr, - uptr end_shadow_addr) { - // TODO: After changing dfsan_label to 8bit, use internal_memset when label - // is not 0. - dfsan_label *labelp = (dfsan_label *)beg_shadow_addr; - if (label) { - for (; (uptr)labelp < end_shadow_addr; ++labelp) *labelp = label; - return; - } - - for (; (uptr)labelp < end_shadow_addr; ++labelp) { - // Don't write the label if it is already the value we need it to be. - // In a program where most addresses are not labeled, it is common that - // a page of shadow memory is entirely zeroed. The Linux copy-on-write - // implementation will share all of the zeroed pages, making a copy of a - // page when any value is written. The un-sharing will happen even if - // the value written does not change the value in memory. Avoiding the - // write when both |label| and |*labelp| are zero dramatically reduces - // the amount of real memory used by large programs. - if (!*labelp) - continue; - - *labelp = 0; - } -} - -static void WriteShadowWithSize(dfsan_label label, uptr shadow_addr, - uptr size) { - WriteShadowInRange(label, shadow_addr, shadow_addr + size * sizeof(label)); -} - #define RET_CHAIN_ORIGIN(id) \ GET_CALLER_PC_BP_SP; \ (void)sp; \ @@ -451,21 +420,6 @@ void dfsan_copy_memory(void *dst, const void *src, uptr size) { dfsan_mem_origin_transfer(dst, src, size); } -} // namespace __dfsan - -// If the label s is tainted, set the size bytes from the address p to be a new -// origin chain with the previous ID o and the current stack trace. This is -// used by instrumentation to reduce code size when too much code is inserted. -extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin( - dfsan_label s, void *p, uptr size, dfsan_origin o) { - if (UNLIKELY(s)) { - GET_CALLER_PC_BP_SP; - (void)sp; - GET_STORE_STACK_TRACE_PC_BP(pc, bp); - SetOrigin(p, size, ChainOrigin(o, &stack)); - } -} - // Releases the pages within the origin address range. static void ReleaseOrigins(void *addr, uptr size) { const uptr beg_origin_addr = (uptr)__dfsan::origin_for(addr); @@ -484,6 +438,19 @@ static void ReleaseOrigins(void *addr, uptr size) { Die(); } +static void WriteZeroShadowInRange(uptr beg, uptr end) { + // Don't write the label if it is already the value we need it to be. + // In a program where most addresses are not labeled, it is common that + // a page of shadow memory is entirely zeroed. The Linux copy-on-write + // implementation will share all of the zeroed pages, making a copy of a + // page when any value is written. The un-sharing will happen even if + // the value written does not change the value in memory. Avoiding the + // write when both |label| and |*labelp| are zero dramatically reduces + // the amount of real memory used by large programs. + if (!mem_is_zero((const char *)beg, end - beg)) + internal_memset((void *)beg, 0, end - beg); +} + // Releases the pages within the shadow address range, and sets // the shadow addresses not on the pages to be 0. static void ReleaseOrClearShadows(void *addr, uptr size) { @@ -492,20 +459,22 @@ static void ReleaseOrClearShadows(void *addr, uptr size) { const uptr end_shadow_addr = (uptr)__dfsan::shadow_for(end_addr); if (end_shadow_addr - beg_shadow_addr < - common_flags()->clear_shadow_mmap_threshold) - return WriteShadowWithSize(0, beg_shadow_addr, size); + common_flags()->clear_shadow_mmap_threshold) { + WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr); + return; + } const uptr page_size = GetPageSizeCached(); const uptr beg_aligned = RoundUpTo(beg_shadow_addr, page_size); const uptr end_aligned = RoundDownTo(end_shadow_addr, page_size); if (beg_aligned >= end_aligned) { - WriteShadowWithSize(0, beg_shadow_addr, size); + WriteZeroShadowInRange(beg_shadow_addr, end_shadow_addr); } else { if (beg_aligned != beg_shadow_addr) - WriteShadowInRange(0, beg_shadow_addr, beg_aligned); + WriteZeroShadowInRange(beg_shadow_addr, beg_aligned); if (end_aligned != end_shadow_addr) - WriteShadowInRange(0, end_aligned, end_shadow_addr); + WriteZeroShadowInRange(end_aligned, end_shadow_addr); if (!MmapFixedSuperNoReserve(beg_aligned, end_aligned - beg_aligned)) Die(); } @@ -514,7 +483,7 @@ static void ReleaseOrClearShadows(void *addr, uptr size) { void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) { if (0 != label) { const uptr beg_shadow_addr = (uptr)__dfsan::shadow_for(addr); - WriteShadowWithSize(label, beg_shadow_addr, size); + internal_memset((void *)beg_shadow_addr, label, size); if (dfsan_get_track_origins()) SetOrigin(addr, size, origin); return; @@ -526,9 +495,24 @@ void SetShadow(dfsan_label label, void *addr, uptr size, dfsan_origin origin) { ReleaseOrClearShadows(addr, size); } +} // namespace __dfsan + +// If the label s is tainted, set the size bytes from the address p to be a new +// origin chain with the previous ID o and the current stack trace. This is +// used by instrumentation to reduce code size when too much code is inserted. +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_maybe_store_origin( + dfsan_label s, void *p, uptr size, dfsan_origin o) { + if (UNLIKELY(s)) { + GET_CALLER_PC_BP_SP; + (void)sp; + GET_STORE_STACK_TRACE_PC_BP(pc, bp); + SetOrigin(p, size, ChainOrigin(o, &stack)); + } +} + extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __dfsan_set_label( dfsan_label label, dfsan_origin origin, void *addr, uptr size) { - SetShadow(label, addr, size, origin); + __dfsan::SetShadow(label, addr, size, origin); } SANITIZER_INTERFACE_ATTRIBUTE @@ -539,7 +523,7 @@ void dfsan_set_label(dfsan_label label, void *addr, uptr size) { GET_STORE_STACK_TRACE_PC_BP(pc, bp); init_origin = ChainOrigin(0, &stack, true); } - SetShadow(label, addr, size, init_origin); + __dfsan::SetShadow(label, addr, size, init_origin); } SANITIZER_INTERFACE_ATTRIBUTE @@ -709,9 +693,9 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void dfsan_print_origin_trace( PrintInvalidOriginWarning(label, addr); } -extern "C" SANITIZER_INTERFACE_ATTRIBUTE size_t +extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr dfsan_sprint_origin_trace(const void *addr, const char *description, - char *out_buf, size_t out_buf_size) { + char *out_buf, uptr out_buf_size) { CHECK(out_buf); if (!dfsan_get_track_origins()) { @@ -780,8 +764,8 @@ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_print_stack_trace() { stack.Print(); } -extern "C" SANITIZER_INTERFACE_ATTRIBUTE size_t -dfsan_sprint_stack_trace(char *out_buf, size_t out_buf_size) { +extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr +dfsan_sprint_stack_trace(char *out_buf, uptr out_buf_size) { CHECK(out_buf); GET_CALLER_PC_BP; GET_STORE_STACK_TRACE_PC_BP(pc, bp); @@ -932,7 +916,7 @@ static bool ProtectMemoryRange(uptr beg, uptr size, const char *name) { // Consider refactoring these into a shared implementation. bool InitShadow(bool init_origins) { // Let user know mapping parameters first. - VPrintf(1, "dfsan_init %p\n", &__dfsan::dfsan_init); + VPrintf(1, "dfsan_init %p\n", (void *)&__dfsan::dfsan_init); for (unsigned i = 0; i < kMemoryLayoutSize; ++i) VPrintf(1, "%s: %zx - %zx\n", kMemoryLayout[i].name, kMemoryLayout[i].start, kMemoryLayout[i].end - 1); @@ -1007,7 +991,7 @@ static void DFsanInit(int argc, char **argv, char **envp) { DFsanThread *main_thread = DFsanThread::Create(nullptr, nullptr, nullptr); SetCurrentThread(main_thread); - main_thread->ThreadStart(); + main_thread->Init(); dfsan_init_is_running = false; dfsan_inited = true; diff --git a/compiler-rt/lib/dfsan/dfsan.h b/compiler-rt/lib/dfsan/dfsan.h index b212298157e..b529e008f30 100644 --- a/compiler-rt/lib/dfsan/dfsan.h +++ b/compiler-rt/lib/dfsan/dfsan.h @@ -49,7 +49,7 @@ void dfsan_mem_origin_transfer(const void *dst, const void *src, uptr len); } // extern "C" template -void dfsan_set_label(dfsan_label label, T &data) { // NOLINT +void dfsan_set_label(dfsan_label label, T &data) { dfsan_set_label(label, (void *)&data, sizeof(T)); } diff --git a/compiler-rt/lib/dfsan/dfsan_custom.cpp b/compiler-rt/lib/dfsan/dfsan_custom.cpp index 3185184f29c..217bd35c1c5 100644 --- a/compiler-rt/lib/dfsan/dfsan_custom.cpp +++ b/compiler-rt/lib/dfsan/dfsan_custom.cpp @@ -583,7 +583,7 @@ SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcat(char *dest, const char *src, dfsan_label src_label, dfsan_label *ret_label) { size_t dest_len = strlen(dest); - char *ret = strcat(dest, src); // NOLINT + char *ret = strcat(dest, src); dfsan_label *sdest = shadow_for(dest + dest_len); const dfsan_label *ssrc = shadow_for(src); internal_memcpy((void *)sdest, (const void *)ssrc, @@ -597,7 +597,7 @@ SANITIZER_INTERFACE_ATTRIBUTE char *__dfso_strcat( dfsan_label *ret_label, dfsan_origin dest_origin, dfsan_origin src_origin, dfsan_origin *ret_origin) { size_t dest_len = strlen(dest); - char *ret = strcat(dest, src); // NOLINT + char *ret = strcat(dest, src); dfsan_label *sdest = shadow_for(dest + dest_len); const dfsan_label *ssrc = shadow_for(src); size_t src_len = strlen(src); @@ -755,6 +755,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void *__dfso_dlopen( static void *DFsanThreadStartFunc(void *arg) { DFsanThread *t = (DFsanThread *)arg; SetCurrentThread(t); + t->Init(); + SetSigProcMask(&t->starting_sigset_, nullptr); return t->ThreadStart(); } @@ -775,6 +777,7 @@ static int dfsan_pthread_create(pthread_t *thread, const pthread_attr_t *attr, DFsanThread *t = DFsanThread::Create(start_routine_trampoline, (thread_callback_t)start_routine, arg, track_origins); + ScopedBlockSignals block(&t->starting_sigset_); int res = pthread_create(thread, attr, DFsanThreadStartFunc, t); if (attr == &myattr) @@ -1026,6 +1029,33 @@ char *__dfso_get_current_dir_name(dfsan_label *ret_label, return __dfsw_get_current_dir_name(ret_label); } +// This function is only available for glibc 2.25 or newer. Mark it weak so +// linking succeeds with older glibcs. +SANITIZER_WEAK_ATTRIBUTE int getentropy(void *buffer, size_t length); + +SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_getentropy(void *buffer, size_t length, + dfsan_label buffer_label, + dfsan_label length_label, + dfsan_label *ret_label) { + int ret = getentropy(buffer, length); + if (ret == 0) { + dfsan_set_label(0, buffer, length); + } + *ret_label = 0; + return ret; +} + +SANITIZER_INTERFACE_ATTRIBUTE int __dfso_getentropy(void *buffer, size_t length, + dfsan_label buffer_label, + dfsan_label length_label, + dfsan_label *ret_label, + dfsan_origin buffer_origin, + dfsan_origin length_origin, + dfsan_origin *ret_origin) { + return __dfsw_getentropy(buffer, length, buffer_label, length_label, + ret_label); +} + SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label, dfsan_label len_label, dfsan_label *ret_label) { @@ -1088,7 +1118,7 @@ int __dfso_getrusage(int who, struct rusage *usage, dfsan_label who_label, SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label, dfsan_label src_label, dfsan_label *ret_label) { - char *ret = strcpy(dest, src); // NOLINT + char *ret = strcpy(dest, src); if (ret) { internal_memcpy(shadow_for(dest), shadow_for(src), sizeof(dfsan_label) * (strlen(src) + 1)); @@ -1102,7 +1132,7 @@ char *__dfso_strcpy(char *dest, const char *src, dfsan_label dst_label, dfsan_label src_label, dfsan_label *ret_label, dfsan_origin dst_origin, dfsan_origin src_origin, dfsan_origin *ret_origin) { - char *ret = strcpy(dest, src); // NOLINT + char *ret = strcpy(dest, src); if (ret) { size_t str_len = strlen(src) + 1; dfsan_mem_origin_transfer(dest, src, str_len); @@ -2489,7 +2519,8 @@ pid_t __dfso_fork(dfsan_label *ret_label, dfsan_origin *ret_origin) { SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *, u32 *) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr *beg, + const uptr *end) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {} diff --git a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp index 92be4fc87d4..d8fb9ea8661 100644 --- a/compiler-rt/lib/dfsan/dfsan_interceptors.cpp +++ b/compiler-rt/lib/dfsan/dfsan_interceptors.cpp @@ -17,6 +17,7 @@ #include "dfsan/dfsan.h" #include "dfsan/dfsan_thread.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator_dlsym.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_errno.h" @@ -26,11 +27,11 @@ using namespace __sanitizer; -namespace { +static bool interceptors_initialized; -bool interceptors_initialized; - -} // namespace +struct DlsymAlloc : public DlSymAllocator { + static bool UseImpl() { return !__dfsan::dfsan_inited; } +}; INTERCEPTOR(void *, reallocarray, void *ptr, SIZE_T nmemb, SIZE_T size) { return __dfsan::dfsan_reallocarray(ptr, nmemb, size); @@ -47,63 +48,37 @@ INTERCEPTOR(void *, aligned_alloc, SIZE_T alignment, SIZE_T size) { return __dfsan::dfsan_aligned_alloc(alignment, size); } -static uptr allocated_for_dlsym; -static const uptr kDlsymAllocPoolSize = 1024; -static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; - -static bool IsInDlsymAllocPool(const void *ptr) { - uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < sizeof(alloc_memory_for_dlsym); -} - -static void *AllocateFromLocalPool(uptr size_in_bytes) { - uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; - void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym]; - allocated_for_dlsym += size_in_words; - CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); - return mem; -} - INTERCEPTOR(void *, calloc, SIZE_T nmemb, SIZE_T size) { - if (UNLIKELY(!__dfsan::dfsan_inited)) - // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. - return AllocateFromLocalPool(nmemb * size); + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); return __dfsan::dfsan_calloc(nmemb, size); } INTERCEPTOR(void *, realloc, void *ptr, SIZE_T size) { - if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(!__dfsan::dfsan_inited)) { - new_ptr = AllocateFromLocalPool(copy_size); - } else { - copy_size = size; - new_ptr = __dfsan::dfsan_malloc(copy_size); - } - internal_memcpy(new_ptr, ptr, copy_size); - return new_ptr; - } + if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Realloc(ptr, size); return __dfsan::dfsan_realloc(ptr, size); } INTERCEPTOR(void *, malloc, SIZE_T size) { - if (UNLIKELY(!__dfsan::dfsan_inited)) - // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. - return AllocateFromLocalPool(size); + if (DlsymAlloc::Use()) + return DlsymAlloc::Allocate(size); return __dfsan::dfsan_malloc(size); } INTERCEPTOR(void, free, void *ptr) { - if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + if (!ptr) return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); return __dfsan::dfsan_deallocate(ptr); } INTERCEPTOR(void, cfree, void *ptr) { - if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + if (!ptr) return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); return __dfsan::dfsan_deallocate(ptr); } @@ -152,12 +127,12 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) { if (__dfsan::dfsan_init_is_running) \ return REAL(func)(__VA_ARGS__); \ ENSURE_DFSAN_INITED(); \ - dfsan_set_label(0, __errno_location(), sizeof(int)); /* NOLINT */ + dfsan_set_label(0, __errno_location(), sizeof(int)); INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { if (common_flags()->detect_write_exec) - ReportMmapWriteExec(prot); + ReportMmapWriteExec(prot, flags); if (!__dfsan::dfsan_inited) return (void *)internal_mmap(addr, length, prot, flags, fd, offset); COMMON_INTERCEPTOR_ENTER(mmap, addr, length, prot, flags, fd, offset); @@ -171,7 +146,7 @@ INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, INTERCEPTOR(void *, mmap64, void *addr, SIZE_T length, int prot, int flags, int fd, OFF64_T offset) { if (common_flags()->detect_write_exec) - ReportMmapWriteExec(prot); + ReportMmapWriteExec(prot, flags); if (!__dfsan::dfsan_inited) return (void *)internal_mmap(addr, length, prot, flags, fd, offset); COMMON_INTERCEPTOR_ENTER(mmap64, addr, length, prot, flags, fd, offset); diff --git a/compiler-rt/lib/dfsan/dfsan_thread.cpp b/compiler-rt/lib/dfsan/dfsan_thread.cpp index 6869cf23158..df7e4d9b742 100644 --- a/compiler-rt/lib/dfsan/dfsan_thread.cpp +++ b/compiler-rt/lib/dfsan/dfsan_thread.cpp @@ -67,8 +67,6 @@ void DFsanThread::Destroy() { } thread_return_t DFsanThread::ThreadStart() { - Init(); - if (!start_routine_) { // start_routine_ == 0 if we're on the main thread or on one of the // OS X libdispatch worker threads. But nobody is supposed to call diff --git a/compiler-rt/lib/dfsan/dfsan_thread.h b/compiler-rt/lib/dfsan/dfsan_thread.h index 8dde626f556..1c33a185499 100644 --- a/compiler-rt/lib/dfsan/dfsan_thread.h +++ b/compiler-rt/lib/dfsan/dfsan_thread.h @@ -1,5 +1,4 @@ -//===-- dfsan_thread.h -------------------------------------------*- C++ -//-*-===// +//===-- dfsan_thread.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. @@ -16,6 +15,7 @@ #include "dfsan_allocator.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_posix.h" namespace __dfsan { @@ -46,6 +46,7 @@ class DFsanThread { DFsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; } int destructor_iterations_; + __sanitizer_sigset_t starting_sigset_; private: void SetThreadStackAndTls(); diff --git a/compiler-rt/lib/dfsan/done_abilist.txt b/compiler-rt/lib/dfsan/done_abilist.txt index 3c2670e04c2..eef7c48948c 100644 --- a/compiler-rt/lib/dfsan/done_abilist.txt +++ b/compiler-rt/lib/dfsan/done_abilist.txt @@ -218,6 +218,7 @@ fun:fgets=custom fun:fstat=custom fun:getcwd=custom fun:get_current_dir_name=custom +fun:getentropy=custom fun:gethostname=custom fun:getpeername=custom fun:getrlimit=custom @@ -268,7 +269,7 @@ fun:strrchr=custom fun:strstr=custom # Functions which take action based on global state, such as running a callback -# set by a sepperate function. +# set by a separate function. fun:write=custom # Functions that take a callback (wrap the callback manually). diff --git a/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt index a1ea0a06b53..433092e2b27 100644 --- a/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt +++ b/compiler-rt/lib/dfsan/libc_ubuntu1404_abilist.txt @@ -1852,6 +1852,7 @@ fun:getdirentries64=uninstrumented fun:getdomainname=uninstrumented fun:getdtablesize=uninstrumented fun:getegid=uninstrumented +fun:getentropy=uninstrumented fun:getenv=uninstrumented fun:geteuid=uninstrumented fun:getfsent=uninstrumented diff --git a/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h b/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h index ab191b60ef6..421dee7f660 100644 --- a/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h +++ b/compiler-rt/lib/fuzzer/FuzzerBuiltinsMsvc.h @@ -41,7 +41,8 @@ inline uint32_t Clzll(uint64_t X) { #if !defined(_M_ARM) && !defined(_M_X64) // Scan the high 32 bits. if (_BitScanReverse(&LeadZeroIdx, static_cast(X >> 32))) - return static_cast(63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB. + return static_cast( + 63 - (LeadZeroIdx + 32)); // Create a bit offset from the MSB. // Scan the low 32 bits. if (_BitScanReverse(&LeadZeroIdx, static_cast(X))) return static_cast(63 - LeadZeroIdx); diff --git a/compiler-rt/lib/fuzzer/FuzzerCommand.h b/compiler-rt/lib/fuzzer/FuzzerCommand.h index 87308864af5..f653fe35876 100644 --- a/compiler-rt/lib/fuzzer/FuzzerCommand.h +++ b/compiler-rt/lib/fuzzer/FuzzerCommand.h @@ -33,7 +33,7 @@ public: Command() : CombinedOutAndErr(false) {} - explicit Command(const Vector &ArgsToAdd) + explicit Command(const std::vector &ArgsToAdd) : Args(ArgsToAdd), CombinedOutAndErr(false) {} explicit Command(const Command &Other) @@ -58,7 +58,7 @@ public: // Gets all of the current command line arguments, **including** those after // "-ignore-remaining-args=1". - const Vector &getArguments() const { return Args; } + const std::vector &getArguments() const { return Args; } // Adds the given argument before "-ignore_remaining_args=1", or at the end // if that flag isn't present. @@ -68,7 +68,7 @@ public: // Adds all given arguments before "-ignore_remaining_args=1", or at the end // if that flag isn't present. - void addArguments(const Vector &ArgsToAdd) { + void addArguments(const std::vector &ArgsToAdd) { Args.insert(endMutableArgs(), ArgsToAdd.begin(), ArgsToAdd.end()); } @@ -155,16 +155,16 @@ private: Command(Command &&Other) = delete; Command &operator=(Command &&Other) = delete; - Vector::iterator endMutableArgs() { + std::vector::iterator endMutableArgs() { return std::find(Args.begin(), Args.end(), ignoreRemainingArgs()); } - Vector::const_iterator endMutableArgs() const { + std::vector::const_iterator endMutableArgs() const { return std::find(Args.begin(), Args.end(), ignoreRemainingArgs()); } // The command arguments. Args[0] is the command name. - Vector Args; + std::vector Args; // True indicates stderr is redirected to stdout. bool CombinedOutAndErr; diff --git a/compiler-rt/lib/fuzzer/FuzzerCorpus.h b/compiler-rt/lib/fuzzer/FuzzerCorpus.h index f8c126072c9..e01891e18fe 100644 --- a/compiler-rt/lib/fuzzer/FuzzerCorpus.h +++ b/compiler-rt/lib/fuzzer/FuzzerCorpus.h @@ -39,13 +39,13 @@ struct InputInfo { bool MayDeleteFile = false; bool Reduced = false; bool HasFocusFunction = false; - Vector UniqFeatureSet; - Vector DataFlowTraceForFocusFunction; + std::vector UniqFeatureSet; + std::vector DataFlowTraceForFocusFunction; // Power schedule. bool NeedsEnergyUpdate = false; double Energy = 0.0; double SumIncidence = 0.0; - Vector> FeatureFreqs; + std::vector> FeatureFreqs; // Delete feature Idx and its frequency from FeatureFreqs. bool DeleteFeatureFreq(uint32_t Idx) { @@ -209,7 +209,7 @@ public: InputInfo *AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile, bool HasFocusFunction, bool NeverReduce, std::chrono::microseconds TimeOfUnit, - const Vector &FeatureSet, + const std::vector &FeatureSet, const DataFlowTrace &DFT, const InputInfo *BaseII) { assert(!U.empty()); if (FeatureDebug) @@ -258,7 +258,7 @@ public: } // Debug-only - void PrintFeatureSet(const Vector &FeatureSet) { + void PrintFeatureSet(const std::vector &FeatureSet) { if (!FeatureDebug) return; Printf("{"); for (uint32_t Feature: FeatureSet) @@ -284,7 +284,8 @@ public: } } - void Replace(InputInfo *II, const Unit &U) { + void Replace(InputInfo *II, const Unit &U, + std::chrono::microseconds TimeOfUnit) { assert(II->U.size() > U.size()); Hashes.erase(Sha1ToString(II->Sha1)); DeleteFile(*II); @@ -292,6 +293,7 @@ public: Hashes.insert(Sha1ToString(II->Sha1)); II->U = U; II->Reduced = true; + II->TimeOfUnit = TimeOfUnit; DistributionNeedsUpdate = true; } @@ -325,7 +327,8 @@ public: const auto &II = *Inputs[i]; Printf(" [% 3zd %s] sz: % 5zd runs: % 5zd succ: % 5zd focus: %d\n", i, Sha1ToString(II.Sha1).c_str(), II.U.size(), - II.NumExecutedMutations, II.NumSuccessfullMutations, II.HasFocusFunction); + II.NumExecutedMutations, II.NumSuccessfullMutations, + II.HasFocusFunction); } } @@ -563,11 +566,11 @@ private: } std::piecewise_constant_distribution CorpusDistribution; - Vector Intervals; - Vector Weights; + std::vector Intervals; + std::vector Weights; std::unordered_set Hashes; - Vector Inputs; + std::vector Inputs; size_t NumAddedFeatures = 0; size_t NumUpdatedFeatures = 0; @@ -577,7 +580,7 @@ private: bool DistributionNeedsUpdate = true; uint16_t FreqOfMostAbundantRareFeature = 0; uint16_t GlobalFeatureFreqs[kFeatureSetSize] = {}; - Vector RareFeatures; + std::vector RareFeatures; std::string OutputCorpus; }; diff --git a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp index 23d422590d1..2f9a4d2d7ad 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.cpp @@ -37,7 +37,7 @@ bool BlockCoverage::AppendCoverage(const std::string &S) { // Coverage lines have this form: // CN X Y Z T // where N is the number of the function, T is the total number of instrumented -// BBs, and X,Y,Z, if present, are the indecies of covered BB. +// BBs, and X,Y,Z, if present, are the indices of covered BB. // BB #0, which is the entry block, is not explicitly listed. bool BlockCoverage::AppendCoverage(std::istream &IN) { std::string L; @@ -52,7 +52,7 @@ bool BlockCoverage::AppendCoverage(std::istream &IN) { continue; } if (L[0] != 'C') continue; - Vector CoveredBlocks; + std::vector CoveredBlocks; while (true) { uint32_t BB = 0; SS >> BB; @@ -68,7 +68,7 @@ bool BlockCoverage::AppendCoverage(std::istream &IN) { auto It = Functions.find(FunctionId); auto &Counters = It == Functions.end() - ? Functions.insert({FunctionId, Vector(NumBlocks)}) + ? Functions.insert({FunctionId, std::vector(NumBlocks)}) .first->second : It->second; @@ -86,8 +86,8 @@ bool BlockCoverage::AppendCoverage(std::istream &IN) { // * any uncovered function gets weight 0. // * a function with lots of uncovered blocks gets bigger weight. // * a function with a less frequently executed code gets bigger weight. -Vector BlockCoverage::FunctionWeights(size_t NumFunctions) const { - Vector Res(NumFunctions); +std::vector BlockCoverage::FunctionWeights(size_t NumFunctions) const { + std::vector Res(NumFunctions); for (auto It : Functions) { auto FunctionID = It.first; auto Counters = It.second; @@ -104,7 +104,7 @@ Vector BlockCoverage::FunctionWeights(size_t NumFunctions) const { } void DataFlowTrace::ReadCoverage(const std::string &DirPath) { - Vector Files; + std::vector Files; GetSizedFilesFromDir(DirPath, &Files); for (auto &SF : Files) { auto Name = Basename(SF.File); @@ -115,16 +115,16 @@ void DataFlowTrace::ReadCoverage(const std::string &DirPath) { } } -static void DFTStringAppendToVector(Vector *DFT, +static void DFTStringAppendToVector(std::vector *DFT, const std::string &DFTString) { assert(DFT->size() == DFTString.size()); for (size_t I = 0, Len = DFT->size(); I < Len; I++) (*DFT)[I] = DFTString[I] == '1'; } -// converts a string of '0' and '1' into a Vector -static Vector DFTStringToVector(const std::string &DFTString) { - Vector DFT(DFTString.size()); +// converts a string of '0' and '1' into a std::vector +static std::vector DFTStringToVector(const std::string &DFTString) { + std::vector DFT(DFTString.size()); DFTStringAppendToVector(&DFT, DFTString); return DFT; } @@ -159,14 +159,14 @@ static bool ParseDFTLine(const std::string &Line, size_t *FunctionNum, } bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction, - Vector &CorporaFiles, Random &Rand) { + std::vector &CorporaFiles, Random &Rand) { if (DirPath.empty()) return false; Printf("INFO: DataFlowTrace: reading from '%s'\n", DirPath.c_str()); - Vector Files; + std::vector Files; GetSizedFilesFromDir(DirPath, &Files); std::string L; size_t FocusFuncIdx = SIZE_MAX; - Vector FunctionNames; + std::vector FunctionNames; // Collect the hashes of the corpus files. for (auto &SF : CorporaFiles) @@ -191,7 +191,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction, // * chooses a random function according to the weights. ReadCoverage(DirPath); auto Weights = Coverage.FunctionWeights(NumFunctions); - Vector Intervals(NumFunctions + 1); + std::vector Intervals(NumFunctions + 1); std::iota(Intervals.begin(), Intervals.end(), 0); auto Distribution = std::piecewise_constant_distribution( Intervals.begin(), Intervals.end(), Weights.begin()); @@ -247,7 +247,7 @@ bool DataFlowTrace::Init(const std::string &DirPath, std::string *FocusFunction, } int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, - const Vector &CorporaFiles) { + const std::vector &CorporaFiles) { Printf("INFO: collecting data flow: bin: %s dir: %s files: %zd\n", DFTBinary.c_str(), DirPath.c_str(), CorporaFiles.size()); if (CorporaFiles.empty()) { @@ -265,7 +265,7 @@ int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, // we then request tags in [0,Size/2) and [Size/2, Size), and so on. // Function number => DFT. auto OutPath = DirPlusFile(DirPath, Hash(FileToVector(F.File))); - std::unordered_map> DFTMap; + std::unordered_map> DFTMap; std::unordered_set Cov; Command Cmd; Cmd.addArgument(DFTBinary); diff --git a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h index 07c03bb2565..054dce1bdcb 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h +++ b/compiler-rt/lib/fuzzer/FuzzerDataFlowTrace.h @@ -39,7 +39,7 @@ namespace fuzzer { int CollectDataFlow(const std::string &DFTBinary, const std::string &DirPath, - const Vector &CorporaFiles); + const std::vector &CorporaFiles); class BlockCoverage { public: @@ -77,11 +77,11 @@ public: return Result; } - Vector FunctionWeights(size_t NumFunctions) const; + std::vector FunctionWeights(size_t NumFunctions) const; void clear() { Functions.clear(); } private: - typedef Vector CoverageVector; + typedef std::vector CoverageVector; uint32_t NumberOfCoveredBlocks(const CoverageVector &Counters) const { uint32_t Res = 0; @@ -117,9 +117,9 @@ class DataFlowTrace { public: void ReadCoverage(const std::string &DirPath); bool Init(const std::string &DirPath, std::string *FocusFunction, - Vector &CorporaFiles, Random &Rand); + std::vector &CorporaFiles, Random &Rand); void Clear() { Traces.clear(); } - const Vector *Get(const std::string &InputSha1) const { + const std::vector *Get(const std::string &InputSha1) const { auto It = Traces.find(InputSha1); if (It != Traces.end()) return &It->second; @@ -128,9 +128,9 @@ class DataFlowTrace { private: // Input's sha1 => DFT for the FocusFunction. - std::unordered_map > Traces; - BlockCoverage Coverage; - std::unordered_set CorporaHashes; + std::unordered_map> Traces; + BlockCoverage Coverage; + std::unordered_set CorporaHashes; }; } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerDefs.h b/compiler-rt/lib/fuzzer/FuzzerDefs.h index 1a2752af2f4..db1f74a545e 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDefs.h +++ b/compiler-rt/lib/fuzzer/FuzzerDefs.h @@ -38,28 +38,8 @@ struct ExternalFunctions; // Global interface to functions that may or may not be available. extern ExternalFunctions *EF; -// We are using a custom allocator to give a different symbol name to STL -// containers in order to avoid ODR violations. -template - class fuzzer_allocator: public std::allocator { - public: - fuzzer_allocator() = default; - - template - fuzzer_allocator(const fuzzer_allocator&) {} - - template - struct rebind { typedef fuzzer_allocator other; }; - }; - -template -using Vector = std::vector>; - -template -using Set = std::set, fuzzer_allocator>; - -typedef Vector Unit; -typedef Vector UnitVector; +typedef std::vector Unit; +typedef std::vector UnitVector; typedef int (*UserCallback)(const uint8_t *Data, size_t Size); int FuzzerDriver(int *argc, char ***argv, UserCallback Callback); diff --git a/compiler-rt/lib/fuzzer/FuzzerDictionary.h b/compiler-rt/lib/fuzzer/FuzzerDictionary.h index db55907d936..48f063c7ee4 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDictionary.h +++ b/compiler-rt/lib/fuzzer/FuzzerDictionary.h @@ -52,10 +52,13 @@ class DictionaryEntry { public: DictionaryEntry() {} DictionaryEntry(Word W) : W(W) {} - DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} + DictionaryEntry(Word W, size_t PositionHint) + : W(W), PositionHint(PositionHint) {} const Word &GetW() const { return W; } - bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } + bool HasPositionHint() const { + return PositionHint != std::numeric_limits::max(); + } size_t GetPositionHint() const { assert(HasPositionHint()); return PositionHint; @@ -108,12 +111,12 @@ private: }; // Parses one dictionary entry. -// If successful, write the enty to Unit and returns true, +// If successful, writes the entry to Unit and returns true, // otherwise returns false. bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // Parses the dictionary file, fills Units, returns true iff all lines // were parsed successfully. -bool ParseDictionaryFile(const std::string &Text, Vector *Units); +bool ParseDictionaryFile(const std::string &Text, std::vector *Units); } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp index ceaa9070512..6b007f2ad45 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -86,7 +86,7 @@ static const FlagDescription FlagDescriptions [] { static const size_t kNumFlags = sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]); -static Vector *Inputs; +static std::vector *Inputs; static std::string *ProgName; static void PrintHelp() { @@ -187,7 +187,7 @@ static bool ParseOneFlag(const char *Param) { } // We don't use any library to minimize dependencies. -static void ParseFlags(const Vector &Args, +static void ParseFlags(const std::vector &Args, const ExternalFunctions *EF) { for (size_t F = 0; F < kNumFlags; F++) { if (FlagDescriptions[F].IntFlag) @@ -206,7 +206,7 @@ static void ParseFlags(const Vector &Args, "Disabling -len_control by default.\n", EF->LLVMFuzzerCustomMutator); } - Inputs = new Vector; + Inputs = new std::vector; for (size_t A = 1; A < Args.size(); A++) { if (ParseOneFlag(Args[A].c_str())) { if (Flags.ignore_remaining_args) @@ -272,7 +272,7 @@ static void ValidateDirectoryExists(const std::string &Path, exit(1); } -std::string CloneArgsWithoutX(const Vector &Args, +std::string CloneArgsWithoutX(const std::vector &Args, const char *X1, const char *X2) { std::string Cmd; for (auto &S : Args) { @@ -283,18 +283,19 @@ std::string CloneArgsWithoutX(const Vector &Args, return Cmd; } -static int RunInMultipleProcesses(const Vector &Args, +static int RunInMultipleProcesses(const std::vector &Args, unsigned NumWorkers, unsigned NumJobs) { std::atomic Counter(0); std::atomic HasErrors(false); Command Cmd(Args); Cmd.removeFlag("jobs"); Cmd.removeFlag("workers"); - Vector V; + std::vector V; std::thread Pulse(PulseThread); Pulse.detach(); for (unsigned i = 0; i < NumWorkers; i++) - V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, &HasErrors)); + V.push_back(std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs, + &HasErrors)); for (auto &T : V) T.join(); return HasErrors ? 1 : 0; @@ -348,8 +349,8 @@ static std::string GetDedupTokenFromCmdOutput(const std::string &S) { return S.substr(Beg, End - Beg); } -int CleanseCrashInput(const Vector &Args, - const FuzzingOptions &Options) { +int CleanseCrashInput(const std::vector &Args, + const FuzzingOptions &Options) { if (Inputs->size() != 1 || !Flags.exact_artifact_path) { Printf("ERROR: -cleanse_crash should be given one input file and" " -exact_artifact_path\n"); @@ -372,7 +373,7 @@ int CleanseCrashInput(const Vector &Args, auto U = FileToVector(CurrentFilePath); size_t Size = U.size(); - const Vector ReplacementBytes = {' ', 0xff}; + const std::vector ReplacementBytes = {' ', 0xff}; for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) { bool Changed = false; for (size_t Idx = 0; Idx < Size; Idx++) { @@ -403,7 +404,7 @@ int CleanseCrashInput(const Vector &Args, return 0; } -int MinimizeCrashInput(const Vector &Args, +int MinimizeCrashInput(const std::vector &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1) { Printf("ERROR: -minimize_crash should be given one input file\n"); @@ -503,14 +504,15 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } -void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector &Args, - const Vector &Corpora, const char *CFPathOrNull) { +void Merge(Fuzzer *F, FuzzingOptions &Options, + const std::vector &Args, + const std::vector &Corpora, const char *CFPathOrNull) { if (Corpora.size() < 2) { Printf("INFO: Merge requires two or more corpus dirs\n"); exit(0); } - Vector OldCorpus, NewCorpus; + std::vector OldCorpus, NewCorpus; GetSizedFilesFromDir(Corpora[0], &OldCorpus); for (size_t i = 1; i < Corpora.size(); i++) GetSizedFilesFromDir(Corpora[i], &NewCorpus); @@ -518,10 +520,10 @@ void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector &Args, std::sort(NewCorpus.begin(), NewCorpus.end()); std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt"); - Vector NewFiles; - Set NewFeatures, NewCov; + std::vector NewFiles; + std::set NewFeatures, NewCov; CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures, - {}, &NewCov, CFPath, true); + {}, &NewCov, CFPath, true, Flags.set_cover_merge); for (auto &Path : NewFiles) F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen)); // We are done, delete the control file if it was a temporary one. @@ -531,17 +533,17 @@ void Merge(Fuzzer *F, FuzzingOptions &Options, const Vector &Args, exit(0); } -int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, - UnitVector& Corpus) { +int AnalyzeDictionary(Fuzzer *F, const std::vector &Dict, + UnitVector &Corpus) { Printf("Started dictionary minimization (up to %d tests)\n", Dict.size() * Corpus.size() * 2); // Scores and usage count for each dictionary unit. - Vector Scores(Dict.size()); - Vector Usages(Dict.size()); + std::vector Scores(Dict.size()); + std::vector Usages(Dict.size()); - Vector InitialFeatures; - Vector ModifiedFeatures; + std::vector InitialFeatures; + std::vector ModifiedFeatures; for (auto &C : Corpus) { // Get coverage for the testcase without modifications. F->ExecuteCallback(C.data(), C.size()); @@ -551,7 +553,7 @@ int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, }); for (size_t i = 0; i < Dict.size(); ++i) { - Vector Data = C; + std::vector Data = C; auto StartPos = std::search(Data.begin(), Data.end(), Dict[i].begin(), Dict[i].end()); // Skip dictionary unit, if the testcase does not contain it. @@ -597,9 +599,9 @@ int AnalyzeDictionary(Fuzzer *F, const Vector& Dict, return 0; } -Vector ParseSeedInuts(const char *seed_inputs) { +std::vector ParseSeedInuts(const char *seed_inputs) { // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file - Vector Files; + std::vector Files; if (!seed_inputs) return Files; std::string SeedInputs; if (Flags.seed_inputs[0] == '@') @@ -620,9 +622,10 @@ Vector ParseSeedInuts(const char *seed_inputs) { return Files; } -static Vector ReadCorpora(const Vector &CorpusDirs, - const Vector &ExtraSeedFiles) { - Vector SizedFiles; +static std::vector +ReadCorpora(const std::vector &CorpusDirs, + const std::vector &ExtraSeedFiles) { + std::vector SizedFiles; size_t LastNumFiles = 0; for (auto &Dir : CorpusDirs) { GetSizedFilesFromDir(Dir, &SizedFiles); @@ -645,7 +648,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { EF->LLVMFuzzerInitialize(argc, argv); if (EF->__msan_scoped_disable_interceptor_checks) EF->__msan_scoped_disable_interceptor_checks(); - const Vector Args(*argv, *argv + *argc); + const std::vector Args(*argv, *argv + *argc); assert(!Args.empty()); ProgName = new std::string(Args[0]); if (Argv0 != *ProgName) { @@ -734,7 +737,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { ValidateDirectoryExists(DirName(Options.ExactArtifactPath), Flags.create_missing_dirs); } - Vector Dictionary; + std::vector Dictionary; if (Flags.dict) if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary)) return 1; @@ -794,7 +797,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { if (Flags.verbosity) Printf("INFO: Seed: %u\n", Seed); - if (Flags.collect_data_flow && !Flags.fork && !Flags.merge) { + if (Flags.collect_data_flow && !Flags.fork && + !(Flags.merge || Flags.set_cover_merge)) { if (RunIndividualFiles) return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace, ReadCorpora({}, *Inputs)); @@ -866,10 +870,11 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); } + Options.ForkCorpusGroups = Flags.fork_corpus_groups; if (Flags.fork) FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork); - if (Flags.merge) + if (Flags.merge || Flags.set_cover_merge) Merge(F, Options, Args, *Inputs, Flags.merge_control_file); if (Flags.merge_inner) { @@ -877,7 +882,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { if (Options.MaxLen == 0) F->SetMaxInputLen(kDefaultMaxMergeLen); assert(Flags.merge_control_file); - F->CrashResistantMergeInternalStep(Flags.merge_control_file); + F->CrashResistantMergeInternalStep(Flags.merge_control_file, + !strncmp(Flags.merge_inner, "2", 1)); exit(0); } diff --git a/compiler-rt/lib/fuzzer/FuzzerExtraCounters.cpp b/compiler-rt/lib/fuzzer/FuzzerExtraCounters.cpp index 04f569a1a87..54ecbf7c62f 100644 --- a/compiler-rt/lib/fuzzer/FuzzerExtraCounters.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerExtraCounters.cpp @@ -31,12 +31,4 @@ void ClearExtraCounters() { // hand-written memset, don't asan-ify. } // namespace fuzzer -#else -// TODO: implement for other platforms. -namespace fuzzer { -uint8_t *ExtraCountersBegin() { return nullptr; } -uint8_t *ExtraCountersEnd() { return nullptr; } -void ClearExtraCounters() {} -} // namespace fuzzer - #endif diff --git a/compiler-rt/lib/fuzzer/FuzzerExtraCountersDarwin.cpp b/compiler-rt/lib/fuzzer/FuzzerExtraCountersDarwin.cpp new file mode 100644 index 00000000000..2321ba8a3d4 --- /dev/null +++ b/compiler-rt/lib/fuzzer/FuzzerExtraCountersDarwin.cpp @@ -0,0 +1,22 @@ +//===- FuzzerExtraCountersDarwin.cpp - Extra coverage counters for Darwin -===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Extra coverage counters defined by user code for Darwin. +//===----------------------------------------------------------------------===// + +#include "FuzzerPlatform.h" +#include + +#if LIBFUZZER_APPLE + +namespace fuzzer { +uint8_t *ExtraCountersBegin() { return nullptr; } +uint8_t *ExtraCountersEnd() { return nullptr; } +void ClearExtraCounters() {} +} // namespace fuzzer + +#endif diff --git a/compiler-rt/lib/fuzzer/FuzzerExtraCountersWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerExtraCountersWindows.cpp new file mode 100644 index 00000000000..102f5febdae --- /dev/null +++ b/compiler-rt/lib/fuzzer/FuzzerExtraCountersWindows.cpp @@ -0,0 +1,80 @@ +//===- FuzzerExtraCountersWindows.cpp - Extra coverage counters for Win32 -===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Extra coverage counters defined by user code for Windows. +//===----------------------------------------------------------------------===// + +#include "FuzzerPlatform.h" +#include + +#if LIBFUZZER_WINDOWS +#include + +namespace fuzzer { + +// +// The __start___libfuzzer_extra_counters variable is align 16, size 16 to +// ensure the padding between it and the next variable in this section (either +// __libfuzzer_extra_counters or __stop___libfuzzer_extra_counters) will be +// located at (__start___libfuzzer_extra_counters + +// sizeof(__start___libfuzzer_extra_counters)). Otherwise, the calculation of +// (stop - (start + sizeof(start))) might be skewed. +// +// The section name, __libfuzzer_extra_countaaa ends with "aaa", so it sorts +// before __libfuzzer_extra_counters alphabetically. We want the start symbol to +// be placed in the section just before the user supplied counters (if present). +// +#pragma section(".data$__libfuzzer_extra_countaaa") +ATTRIBUTE_ALIGNED(16) +__declspec(allocate(".data$__libfuzzer_extra_countaaa")) uint8_t + __start___libfuzzer_extra_counters[16] = {0}; + +// +// Example of what the user-supplied counters should look like. First, the +// pragma to create the section name. It will fall alphabetically between +// ".data$__libfuzzer_extra_countaaa" and ".data$__libfuzzer_extra_countzzz". +// Next, the declspec to allocate the variable inside the specified section. +// Finally, some array, struct, whatever that is used to track the counter data. +// The size of this variable is computed at runtime by finding the difference of +// __stop___libfuzzer_extra_counters and __start___libfuzzer_extra_counters + +// sizeof(__start___libfuzzer_extra_counters). +// + +// +// #pragma section(".data$__libfuzzer_extra_counters") +// __declspec(allocate(".data$__libfuzzer_extra_counters")) +// uint8_t any_name_variable[64 * 1024]; +// + +// +// Here, the section name, __libfuzzer_extra_countzzz ends with "zzz", so it +// sorts after __libfuzzer_extra_counters alphabetically. We want the stop +// symbol to be placed in the section just after the user supplied counters (if +// present). Align to 1 so there isn't any padding placed between this and the +// previous variable. +// +#pragma section(".data$__libfuzzer_extra_countzzz") +ATTRIBUTE_ALIGNED(1) +__declspec(allocate(".data$__libfuzzer_extra_countzzz")) uint8_t + __stop___libfuzzer_extra_counters = 0; + +uint8_t *ExtraCountersBegin() { + return __start___libfuzzer_extra_counters + + sizeof(__start___libfuzzer_extra_counters); +} + +uint8_t *ExtraCountersEnd() { return &__stop___libfuzzer_extra_counters; } + +ATTRIBUTE_NO_SANITIZE_ALL +void ClearExtraCounters() { + uint8_t *Beg = ExtraCountersBegin(); + SecureZeroMemory(Beg, ExtraCountersEnd() - Beg); +} + +} // namespace fuzzer + +#endif diff --git a/compiler-rt/lib/fuzzer/FuzzerFlags.def b/compiler-rt/lib/fuzzer/FuzzerFlags.def index ab31da0ae5d..11815349b01 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFlags.def +++ b/compiler-rt/lib/fuzzer/FuzzerFlags.def @@ -58,12 +58,21 @@ FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total " FUZZER_FLAG_INT(help, 0, "Print help.") FUZZER_FLAG_INT(fork, 0, "Experimental mode where fuzzing happens " "in a subprocess") +FUZZER_FLAG_INT(fork_corpus_groups, 0, "For fork mode, enable the corpus-group " + "strategy, The main corpus will be grouped according to size, " + "and each sub-process will randomly select seeds from different " + "groups as the sub-corpus.") FUZZER_FLAG_INT(ignore_timeouts, 1, "Ignore timeouts in fork mode") FUZZER_FLAG_INT(ignore_ooms, 1, "Ignore OOMs in fork mode") FUZZER_FLAG_INT(ignore_crashes, 0, "Ignore crashes in fork mode") FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " "merged into the 1-st corpus. Only interesting units will be taken. " "This flag can be used to minimize a corpus.") +FUZZER_FLAG_INT(set_cover_merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " + "merged into the 1-st corpus. Same as the 'merge' flag, but uses the " + "standard greedy algorithm for the set cover problem to " + "compute an approximation of the minimum set of testcases that " + "provide the same coverage as the initial corpora") FUZZER_FLAG_STRING(stop_file, "Stop fuzzing ASAP if this file exists") FUZZER_FLAG_STRING(merge_inner, "internal flag") FUZZER_FLAG_STRING(merge_control_file, diff --git a/compiler-rt/lib/fuzzer/FuzzerFork.cpp b/compiler-rt/lib/fuzzer/FuzzerFork.cpp index 5134a5d979e..d59d5138420 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFork.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerFork.cpp @@ -86,18 +86,21 @@ struct FuzzJob { }; struct GlobalEnv { - Vector Args; - Vector CorpusDirs; + std::vector Args; + std::vector CorpusDirs; std::string MainCorpusDir; std::string TempDir; std::string DFTDir; std::string DataFlowBinary; - Set Features, Cov; - Set FilesWithDFT; - Vector Files; + std::set Features, Cov; + std::set FilesWithDFT; + std::vector Files; + std::vector FilesSizes; Random *Rand; std::chrono::system_clock::time_point ProcessStartTime; int Verbosity = 0; + int Group = 0; + int NumCorpuses = 8; size_t NumTimeouts = 0; size_t NumOOMs = 0; @@ -136,10 +139,24 @@ struct GlobalEnv { if (size_t CorpusSubsetSize = std::min(Files.size(), (size_t)sqrt(Files.size() + 2))) { auto Time1 = std::chrono::system_clock::now(); - for (size_t i = 0; i < CorpusSubsetSize; i++) { - auto &SF = Files[Rand->SkewTowardsLast(Files.size())]; - Seeds += (Seeds.empty() ? "" : ",") + SF; - CollectDFT(SF); + if (Group) { // whether to group the corpus. + size_t AverageCorpusSize = Files.size() / NumCorpuses + 1; + size_t StartIndex = ((JobId - 1) % NumCorpuses) * AverageCorpusSize; + for (size_t i = 0; i < CorpusSubsetSize; i++) { + size_t RandNum = (*Rand)(AverageCorpusSize); + size_t Index = RandNum + StartIndex; + Index = Index < Files.size() ? Index + : Rand->SkewTowardsLast(Files.size()); + auto &SF = Files[Index]; + Seeds += (Seeds.empty() ? "" : ",") + SF; + CollectDFT(SF); + } + } else { + for (size_t i = 0; i < CorpusSubsetSize; i++) { + auto &SF = Files[Rand->SkewTowardsLast(Files.size())]; + Seeds += (Seeds.empty() ? "" : ",") + SF; + CollectDFT(SF); + } } auto Time2 = std::chrono::system_clock::now(); auto DftTimeInSeconds = duration_cast(Time2 - Time1).count(); @@ -183,7 +200,7 @@ struct GlobalEnv { auto Stats = ParseFinalStatsFromLog(Job->LogPath); NumRuns += Stats.number_of_executed_units; - Vector TempFiles, MergeCandidates; + std::vector TempFiles, MergeCandidates; // Read all newly created inputs and their feature sets. // Choose only those inputs that have new features. GetSizedFilesFromDir(Job->CorpusDir, &TempFiles); @@ -193,7 +210,7 @@ struct GlobalEnv { FeatureFile.replace(0, Job->CorpusDir.size(), Job->FeaturesDir); auto FeatureBytes = FileToVector(FeatureFile, 0, false); assert((FeatureBytes.size() % sizeof(uint32_t)) == 0); - Vector NewFeatures(FeatureBytes.size() / sizeof(uint32_t)); + std::vector NewFeatures(FeatureBytes.size() / sizeof(uint32_t)); memcpy(NewFeatures.data(), FeatureBytes.data(), FeatureBytes.size()); for (auto Ft : NewFeatures) { if (!Features.count(Ft)) { @@ -211,15 +228,27 @@ struct GlobalEnv { if (MergeCandidates.empty()) return; - Vector FilesToAdd; - Set NewFeatures, NewCov; + std::vector FilesToAdd; + std::set NewFeatures, NewCov; + bool IsSetCoverMerge = + !Job->Cmd.getFlagValue("set_cover_merge").compare("1"); CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features, - &NewFeatures, Cov, &NewCov, Job->CFPath, false); + &NewFeatures, Cov, &NewCov, Job->CFPath, false, + IsSetCoverMerge); for (auto &Path : FilesToAdd) { auto U = FileToVector(Path); auto NewPath = DirPlusFile(MainCorpusDir, Hash(U)); WriteToFile(U, NewPath); - Files.push_back(NewPath); + if (Group) { // Insert the queue according to the size of the seed. + size_t UnitSize = U.size(); + auto Idx = + std::upper_bound(FilesSizes.begin(), FilesSizes.end(), UnitSize) - + FilesSizes.begin(); + FilesSizes.insert(FilesSizes.begin() + Idx, UnitSize); + Files.insert(Files.begin() + Idx, NewPath); + } else { + Files.push_back(NewPath); + } } Features.insert(NewFeatures.begin(), NewFeatures.end()); Cov.insert(NewCov.begin(), NewCov.end()); @@ -228,10 +257,8 @@ struct GlobalEnv { if (TPC.PcIsFuncEntry(TE)) PrintPC(" NEW_FUNC: %p %F %L\n", "", TPC.GetNextInstructionPc(TE->PC)); - } - void CollectDFT(const std::string &InputPath) { if (DataFlowBinary.empty()) return; if (!FilesWithDFT.insert(InputPath).second) return; @@ -283,8 +310,8 @@ void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) { // This is just a skeleton of an experimental -fork=1 feature. void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, - const Vector &Args, - const Vector &CorpusDirs, int NumJobs) { + const std::vector &Args, + const std::vector &CorpusDirs, int NumJobs) { Printf("INFO: -fork=%d: fuzzing in separate process(s)\n", NumJobs); GlobalEnv Env; @@ -294,8 +321,9 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, Env.Verbosity = Options.Verbosity; Env.ProcessStartTime = std::chrono::system_clock::now(); Env.DataFlowBinary = Options.CollectDataFlow; + Env.Group = Options.ForkCorpusGroups; - Vector SeedFiles; + std::vector SeedFiles; for (auto &Dir : CorpusDirs) GetSizedFilesFromDir(Dir, &SeedFiles); std::sort(SeedFiles.begin(), SeedFiles.end()); @@ -316,13 +344,20 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, Env.Files.push_back(File.File); } else { auto CFPath = DirPlusFile(Env.TempDir, "merge.txt"); - Set NewFeatures, NewCov; + std::set NewFeatures, NewCov; CrashResistantMerge(Env.Args, {}, SeedFiles, &Env.Files, Env.Features, - &NewFeatures, Env.Cov, &NewCov, CFPath, false); + &NewFeatures, Env.Cov, &NewCov, CFPath, + /*Verbose=*/false, /*IsSetCoverMerge=*/false); Env.Features.insert(NewFeatures.begin(), NewFeatures.end()); Env.Cov.insert(NewFeatures.begin(), NewFeatures.end()); RemoveFile(CFPath); } + + if (Env.Group) { + for (auto &path : Env.Files) + Env.FilesSizes.push_back(FileSize(path)); + } + Printf("INFO: -fork=%d: %zd seed inputs, starting to fuzz in %s\n", NumJobs, Env.Files.size(), Env.TempDir.c_str()); @@ -337,8 +372,10 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, WriteToFile(Unit({1}), Env.StopFile()); }; + size_t MergeCycle = 20; + size_t JobExecuted = 0; size_t JobId = 1; - Vector Threads; + std::vector Threads; for (int t = 0; t < NumJobs; t++) { Threads.push_back(std::thread(WorkerThread, &FuzzQ, &MergeQ)); FuzzQ.Push(Env.CreateNewJob(JobId++)); @@ -358,7 +395,46 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, Env.RunOneMergeJob(Job.get()); - // Continue if our crash is one of the ignorred ones. + // merge the corpus . + JobExecuted++; + if (Env.Group && JobExecuted >= MergeCycle) { + std::vector CurrentSeedFiles; + for (auto &Dir : CorpusDirs) + GetSizedFilesFromDir(Dir, &CurrentSeedFiles); + std::sort(CurrentSeedFiles.begin(), CurrentSeedFiles.end()); + + auto CFPath = DirPlusFile(Env.TempDir, "merge.txt"); + std::set TmpNewFeatures, TmpNewCov; + std::set TmpFeatures, TmpCov; + Env.Files.clear(); + Env.FilesSizes.clear(); + CrashResistantMerge(Env.Args, {}, CurrentSeedFiles, &Env.Files, + TmpFeatures, &TmpNewFeatures, TmpCov, &TmpNewCov, + CFPath, /*Verbose=*/false, /*IsSetCoverMerge=*/false); + for (auto &path : Env.Files) + Env.FilesSizes.push_back(FileSize(path)); + RemoveFile(CFPath); + JobExecuted = 0; + MergeCycle += 5; + } + + // Since the number of corpus seeds will gradually increase, in order to + // control the number in each group to be about three times the number of + // seeds selected each time, the number of groups is dynamically adjusted. + if (Env.Files.size() < 2000) + Env.NumCorpuses = 12; + else if (Env.Files.size() < 6000) + Env.NumCorpuses = 20; + else if (Env.Files.size() < 12000) + Env.NumCorpuses = 32; + else if (Env.Files.size() < 16000) + Env.NumCorpuses = 40; + else if (Env.Files.size() < 24000) + Env.NumCorpuses = 60; + else + Env.NumCorpuses = 80; + + // Continue if our crash is one of the ignored ones. if (Options.IgnoreTimeouts && ExitCode == Options.TimeoutExitCode) Env.NumTimeouts++; else if (Options.IgnoreOOMs && ExitCode == Options.OOMExitCode) diff --git a/compiler-rt/lib/fuzzer/FuzzerFork.h b/compiler-rt/lib/fuzzer/FuzzerFork.h index b29a43e13fb..fc3e9d636cb 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFork.h +++ b/compiler-rt/lib/fuzzer/FuzzerFork.h @@ -17,8 +17,8 @@ namespace fuzzer { void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, - const Vector &Args, - const Vector &CorpusDirs, int NumJobs); + const std::vector &Args, + const std::vector &CorpusDirs, int NumJobs); } // namespace fuzzer #endif // LLVM_FUZZER_FORK_H diff --git a/compiler-rt/lib/fuzzer/FuzzerIO.cpp b/compiler-rt/lib/fuzzer/FuzzerIO.cpp index 7f149ac6c48..0a58c5377b3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerIO.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerIO.cpp @@ -23,6 +23,14 @@ namespace fuzzer { static FILE *OutputFile = stderr; +FILE *GetOutputFile() { + return OutputFile; +} + +void SetOutputFile(FILE *NewOutputFile) { + OutputFile = NewOutputFile; +} + long GetEpoch(const std::string &Path) { struct stat St; if (stat(Path.c_str(), &St)) @@ -90,11 +98,11 @@ void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path) { fclose(Out); } -void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError, - Vector *VPaths) { + std::vector *VPaths) { long E = Epoch ? *Epoch : 0; - Vector Files; + std::vector Files; ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true); size_t NumLoaded = 0; for (size_t i = 0; i < Files.size(); i++) { @@ -112,8 +120,8 @@ void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, } } -void GetSizedFilesFromDir(const std::string &Dir, Vector *V) { - Vector Files; +void GetSizedFilesFromDir(const std::string &Dir, std::vector *V) { + std::vector Files; ListFilesInDirRecursive(Dir, 0, &Files, /*TopDir*/true); for (auto &File : Files) if (size_t Size = FileSize(File)) diff --git a/compiler-rt/lib/fuzzer/FuzzerIO.h b/compiler-rt/lib/fuzzer/FuzzerIO.h index bde18267ea3..401afa0b447 100644 --- a/compiler-rt/lib/fuzzer/FuzzerIO.h +++ b/compiler-rt/lib/fuzzer/FuzzerIO.h @@ -32,9 +32,9 @@ void WriteToFile(const Unit &U, const std::string &Path); void AppendToFile(const uint8_t *Data, size_t Size, const std::string &Path); void AppendToFile(const std::string &Data, const std::string &Path); -void ReadDirToVectorOfUnits(const char *Path, Vector *V, long *Epoch, +void ReadDirToVectorOfUnits(const char *Path, std::vector *V, long *Epoch, size_t MaxSize, bool ExitOnError, - Vector *VPaths = 0); + std::vector *VPaths = 0); // Returns "Dir/FileName" or equivalent for the current OS. std::string DirPlusFile(const std::string &DirPath, @@ -54,6 +54,10 @@ void DupAndCloseStderr(); void CloseStdout(); +// For testing. +FILE *GetOutputFile(); +void SetOutputFile(FILE *NewOutputFile); + void Printf(const char *Fmt, ...); void VPrintf(bool Verbose, const char *Fmt, ...); @@ -66,7 +70,7 @@ bool IsDirectory(const std::string &Path); size_t FileSize(const std::string &Path); void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - Vector *V, bool TopDir); + std::vector *V, bool TopDir); bool MkDirRecursive(const std::string &Dir); void RmDirRecursive(const std::string &Dir); @@ -85,7 +89,7 @@ struct SizedFile { bool operator<(const SizedFile &B) const { return Size < B.Size; } }; -void GetSizedFilesFromDir(const std::string &Dir, Vector *V); +void GetSizedFilesFromDir(const std::string &Dir, std::vector *V); char GetSeparator(); bool IsSeparator(char C); diff --git a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp index 4706a40959b..3700fb098e5 100644 --- a/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerIOPosix.cpp @@ -53,7 +53,7 @@ std::string Basename(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - Vector *V, bool TopDir) { + std::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; @@ -78,7 +78,6 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, *Epoch = E; } - void IterateDirRecursive(const std::string &Dir, void (*DirPreCallback)(const std::string &Dir), void (*DirPostCallback)(const std::string &Dir), diff --git a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp index 61ad35e281f..6771fc173c9 100644 --- a/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerIOWindows.cpp @@ -111,7 +111,7 @@ size_t FileSize(const std::string &Path) { } void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, - Vector *V, bool TopDir) { + std::vector *V, bool TopDir) { auto E = GetEpoch(Dir); if (Epoch) if (E && *Epoch >= E) return; @@ -159,7 +159,6 @@ void ListFilesInDirRecursive(const std::string &Dir, long *Epoch, *Epoch = E; } - void IterateDirRecursive(const std::string &Dir, void (*DirPreCallback)(const std::string &Dir), void (*DirPostCallback)(const std::string &Dir), @@ -297,9 +296,8 @@ static size_t ParseServerAndShare(const std::string &FileName, return Pos - Offset; } -// Parse the given Ref string from the position Offset, to exactly match the given -// string Patt. -// Returns number of characters considered if successful. +// Parse the given Ref string from the position Offset, to exactly match the +// given string Patt. Returns number of characters considered if successful. static size_t ParseCustomString(const std::string &Ref, size_t Offset, const char *Patt) { size_t Len = strlen(Patt); diff --git a/compiler-rt/lib/fuzzer/FuzzerInternal.h b/compiler-rt/lib/fuzzer/FuzzerInternal.h index 37c8a01dc3c..6637b0034e5 100644 --- a/compiler-rt/lib/fuzzer/FuzzerInternal.h +++ b/compiler-rt/lib/fuzzer/FuzzerInternal.h @@ -35,8 +35,8 @@ public: Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, FuzzingOptions Options); ~Fuzzer(); - void Loop(Vector &CorporaFiles); - void ReadAndExecuteSeedCorpora(Vector &CorporaFiles); + void Loop(std::vector &CorporaFiles); + void ReadAndExecuteSeedCorpora(std::vector &CorporaFiles); void MinimizeCrashLoop(const Unit &U); void RereadOutputCorpus(size_t MaxSize); @@ -72,8 +72,9 @@ public: void TPCUpdateObservedPCs(); // Merge Corpora[1:] into Corpora[0]. - void Merge(const Vector &Corpora); - void CrashResistantMergeInternalStep(const std::string &ControlFilePath); + void Merge(const std::vector &Corpora); + void CrashResistantMergeInternalStep(const std::string &ControlFilePath, + bool IsSetCoverMerge); MutationDispatcher &GetMD() { return MD; } void PrintFinalStats(); void SetMaxInputLen(size_t MaxInputLen); @@ -141,7 +142,7 @@ private: size_t MaxMutationLen = 0; size_t TmpMaxMutationLen = 0; - Vector UniqFeatureSetTmp; + std::vector UniqFeatureSetTmp; // Need to know our own thread. static thread_local bool IsMyThread; diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index 86a78ab7517..3205942f6d8 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -388,7 +388,7 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { void Fuzzer::CheckExitOnSrcPosOrItem() { if (!Options.ExitOnSrcPos.empty()) { - static auto *PCsSet = new Set; + static auto *PCsSet = new std::set; auto HandlePC = [&](const TracePC::PCTableEntry *TE) { if (!PCsSet->insert(TE->PC).second) return; @@ -413,8 +413,8 @@ void Fuzzer::CheckExitOnSrcPosOrItem() { void Fuzzer::RereadOutputCorpus(size_t MaxSize) { if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; - Vector AdditionalCorpus; - Vector AdditionalCorpusPaths; + std::vector AdditionalCorpus; + std::vector AdditionalCorpusPaths; ReadDirToVectorOfUnits( Options.OutputCorpus.c_str(), &AdditionalCorpus, &EpochOfLastReadOfOutputCorpus, MaxSize, @@ -457,7 +457,7 @@ void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { static void WriteFeatureSetToFile(const std::string &FeaturesDir, const std::string &FileName, - const Vector &FeatureSet) { + const std::vector &FeatureSet) { if (FeaturesDir.empty() || FeatureSet.empty()) return; WriteToFile(reinterpret_cast(FeatureSet.data()), FeatureSet.size() * sizeof(FeatureSet[0]), @@ -548,7 +548,7 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && II->U.size() > Size) { auto OldFeaturesFile = Sha1ToString(II->Sha1); - Corpus.Replace(II, {Data, Data + Size}); + Corpus.Replace(II, {Data, Data + Size}, TimeOfUnit); RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile, Sha1ToString(II->Sha1)); return true; @@ -784,7 +784,7 @@ void Fuzzer::PurgeAllocator() { LastAllocatorPurgeAttemptTime = system_clock::now(); } -void Fuzzer::ReadAndExecuteSeedCorpora(Vector &CorporaFiles) { +void Fuzzer::ReadAndExecuteSeedCorpora(std::vector &CorporaFiles) { const size_t kMaxSaneLen = 1 << 20; const size_t kMinDefaultLen = 4096; size_t MaxSize = 0; @@ -849,7 +849,7 @@ void Fuzzer::ReadAndExecuteSeedCorpora(Vector &CorporaFiles) { } } -void Fuzzer::Loop(Vector &CorporaFiles) { +void Fuzzer::Loop(std::vector &CorporaFiles) { auto FocusFunctionOrAuto = Options.FocusFunction; DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles, MD.GetRand()); diff --git a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp index 162453ceae2..24bd11958e8 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMerge.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerMerge.cpp @@ -77,8 +77,8 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { size_t ExpectedStartMarker = 0; const size_t kInvalidStartMarker = -1; size_t LastSeenStartMarker = kInvalidStartMarker; - Vector TmpFeatures; - Set PCs; + std::vector TmpFeatures; + std::set PCs; while (std::getline(IS, Line, '\n')) { std::istringstream ISS1(Line); std::string Marker; @@ -132,15 +132,16 @@ size_t Merger::ApproximateMemoryConsumption() const { // Decides which files need to be merged (add those to NewFiles). // Returns the number of new features added. -size_t Merger::Merge(const Set &InitialFeatures, - Set *NewFeatures, - const Set &InitialCov, Set *NewCov, - Vector *NewFiles) { +size_t Merger::Merge(const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, + std::set *NewCov, + std::vector *NewFiles) { NewFiles->clear(); NewFeatures->clear(); NewCov->clear(); assert(NumFilesInFirstCorpus <= Files.size()); - Set AllFeatures = InitialFeatures; + std::set AllFeatures = InitialFeatures; // What features are in the initial corpus? for (size_t i = 0; i < NumFilesInFirstCorpus; i++) { @@ -150,7 +151,7 @@ size_t Merger::Merge(const Set &InitialFeatures, // Remove all features that we already know from all other inputs. for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) { auto &Cur = Files[i].Features; - Vector Tmp; + std::vector Tmp; std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(), AllFeatures.end(), std::inserter(Tmp, Tmp.begin())); Cur.swap(Tmp); @@ -188,15 +189,16 @@ size_t Merger::Merge(const Set &InitialFeatures, return NewFeatures->size(); } -Set Merger::AllFeatures() const { - Set S; +std::set Merger::AllFeatures() const { + std::set S; for (auto &File : Files) S.insert(File.Features.begin(), File.Features.end()); return S; } // Inner process. May crash if the target crashes. -void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { +void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath, + bool IsSetCoverMerge) { Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str()); Merger M; std::ifstream IF(CFPath); @@ -212,11 +214,11 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { M.Files.size() - M.FirstNotProcessedFile); std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); - Set AllFeatures; + std::set AllFeatures; auto PrintStatsWrapper = [this, &AllFeatures](const char* Where) { this->PrintStats(Where, "\n", 0, AllFeatures.size()); }; - Set AllPCs; + std::set AllPCs; for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { Fuzzer::MaybeExitGracefully(); auto U = FileToVector(M.Files[i].Name); @@ -234,13 +236,14 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { // Collect coverage. We are iterating over the files in this order: // * First, files in the initial corpus ordered by size, smallest first. // * Then, all other files, smallest first. - // So it makes no sense to record all features for all files, instead we - // only record features that were not seen before. - Set UniqFeatures; - TPC.CollectFeatures([&](size_t Feature) { - if (AllFeatures.insert(Feature).second) - UniqFeatures.insert(Feature); - }); + std::set Features; + if (IsSetCoverMerge) + TPC.CollectFeatures([&](size_t Feature) { Features.insert(Feature); }); + else + TPC.CollectFeatures([&](size_t Feature) { + if (AllFeatures.insert(Feature).second) + Features.insert(Feature); + }); TPC.UpdateObservedPCs(); // Show stats. if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1))) @@ -249,7 +252,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { PrintStatsWrapper("LOADED"); // Write the post-run marker and the coverage. OF << "FT " << i; - for (size_t F : UniqFeatures) + for (size_t F : Features) OF << " " << F; OF << "\n"; OF << "COV " << i; @@ -263,15 +266,137 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { PrintStatsWrapper("DONE "); } -static size_t WriteNewControlFile(const std::string &CFPath, - const Vector &OldCorpus, - const Vector &NewCorpus, - const Vector &KnownFiles) { +// Merges all corpora into the first corpus. A file is added into +// the first corpus only if it adds new features. Unlike `Merger::Merge`, +// this implementation calculates an approximation of the minimum set +// of corpora files, that cover all known features (set cover problem). +// Generally, this means that files with more features are preferred for +// merge into the first corpus. When two files have the same number of +// features, the smaller one is preferred. +size_t Merger::SetCoverMerge(const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, + std::set *NewCov, + std::vector *NewFiles) { + assert(NumFilesInFirstCorpus <= Files.size()); + NewFiles->clear(); + NewFeatures->clear(); + NewCov->clear(); + std::set AllFeatures; + // 1 << 21 - 1 is the maximum feature index. + // See 'kFeatureSetSize' in 'FuzzerCorpus.h'. + const uint32_t kFeatureSetSize = 1 << 21; + std::vector Covered(kFeatureSetSize, false); + size_t NumCovered = 0; + + std::set ExistingFeatures = InitialFeatures; + for (size_t i = 0; i < NumFilesInFirstCorpus; ++i) + ExistingFeatures.insert(Files[i].Features.begin(), Files[i].Features.end()); + + // Mark the existing features as covered. + for (const auto &F : ExistingFeatures) { + if (!Covered[F % kFeatureSetSize]) { + ++NumCovered; + Covered[F % kFeatureSetSize] = true; + } + // Calculate an underestimation of the set of covered features + // since the `Covered` bitvector is smaller than the feature range. + AllFeatures.insert(F % kFeatureSetSize); + } + + std::set RemainingFiles; + for (size_t i = NumFilesInFirstCorpus; i < Files.size(); ++i) { + // Construct an incremental sequence which represent the + // indices to all files (excluding those in the initial corpus). + // RemainingFiles = range(NumFilesInFirstCorpus..Files.size()). + RemainingFiles.insert(i); + // Insert this file's unique features to all features. + for (const auto &F : Files[i].Features) + AllFeatures.insert(F % kFeatureSetSize); + } + + // Integrate files into Covered until set is complete. + while (NumCovered != AllFeatures.size()) { + // Index to file with largest number of unique features. + size_t MaxFeaturesIndex = NumFilesInFirstCorpus; + // Indices to remove from RemainingFiles. + std::set RemoveIndices; + // Running max unique feature count. + // Updated upon finding a file with more features. + size_t MaxNumFeatures = 0; + + // Iterate over all files not yet integrated into Covered, + // to find the file which has the largest number of + // features that are not already in Covered. + for (const auto &i : RemainingFiles) { + const auto &File = Files[i]; + size_t CurrentUnique = 0; + // Count number of features in this file + // which are not yet in Covered. + for (const auto &F : File.Features) + if (!Covered[F % kFeatureSetSize]) + ++CurrentUnique; + + if (CurrentUnique == 0) { + // All features in this file are already in Covered: skip next time. + RemoveIndices.insert(i); + } else if (CurrentUnique > MaxNumFeatures || + (CurrentUnique == MaxNumFeatures && + File.Size < Files[MaxFeaturesIndex].Size)) { + // Update the max features file based on unique features + // Break ties by selecting smaller files. + MaxNumFeatures = CurrentUnique; + MaxFeaturesIndex = i; + } + } + // Must be a valid index/ + assert(MaxFeaturesIndex < Files.size()); + // Remove any feature-less files found. + for (const auto &i : RemoveIndices) + RemainingFiles.erase(i); + if (MaxNumFeatures == 0) { + // Did not find a file that adds unique features. + // This means that we should have no remaining files. + assert(RemainingFiles.size() == 0); + assert(NumCovered == AllFeatures.size()); + break; + } + + // MaxFeaturesIndex must be an element of Remaining. + assert(RemainingFiles.find(MaxFeaturesIndex) != RemainingFiles.end()); + // Remove the file with the most features from Remaining. + RemainingFiles.erase(MaxFeaturesIndex); + const auto &MaxFeatureFile = Files[MaxFeaturesIndex]; + // Add the features of the max feature file to Covered. + for (const auto &F : MaxFeatureFile.Features) { + if (!Covered[F % kFeatureSetSize]) { + ++NumCovered; + Covered[F % kFeatureSetSize] = true; + NewFeatures->insert(F); + } + } + // Add the index to this file to the result. + NewFiles->push_back(MaxFeatureFile.Name); + // Update NewCov with the additional coverage + // that MaxFeatureFile provides. + for (const auto &C : MaxFeatureFile.Cov) + if (InitialCov.find(C) == InitialCov.end()) + NewCov->insert(C); + } + + return NewFeatures->size(); +} + +static size_t +WriteNewControlFile(const std::string &CFPath, + const std::vector &OldCorpus, + const std::vector &NewCorpus, + const std::vector &KnownFiles) { std::unordered_set FilesToSkip; for (auto &SF: KnownFiles) FilesToSkip.insert(SF.Name); - Vector FilesToUse; + std::vector FilesToUse; auto MaybeUseFile = [=, &FilesToUse](std::string Name) { if (FilesToSkip.find(Name) == FilesToSkip.end()) FilesToUse.push_back(Name); @@ -299,19 +424,19 @@ static size_t WriteNewControlFile(const std::string &CFPath, } // Outer process. Does not call the target code and thus should not fail. -void CrashResistantMerge(const Vector &Args, - const Vector &OldCorpus, - const Vector &NewCorpus, - Vector *NewFiles, - const Set &InitialFeatures, - Set *NewFeatures, - const Set &InitialCov, - Set *NewCov, - const std::string &CFPath, - bool V /*Verbose*/) { +void CrashResistantMerge(const std::vector &Args, + const std::vector &OldCorpus, + const std::vector &NewCorpus, + std::vector *NewFiles, + const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, + std::set *NewCov, const std::string &CFPath, + bool V, /*Verbose*/ + bool IsSetCoverMerge) { if (NewCorpus.empty() && OldCorpus.empty()) return; // Nothing to merge. size_t NumAttempts = 0; - Vector KnownFiles; + std::vector KnownFiles; if (FileSize(CFPath)) { VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n", CFPath.c_str()); @@ -363,6 +488,7 @@ void CrashResistantMerge(const Vector &Args, // Every inner process should execute at least one input. Command BaseCmd(Args); BaseCmd.removeFlag("merge"); + BaseCmd.removeFlag("set_cover_merge"); BaseCmd.removeFlag("fork"); BaseCmd.removeFlag("collect_data_flow"); for (size_t Attempt = 1; Attempt <= NumAttempts; Attempt++) { @@ -370,14 +496,16 @@ void CrashResistantMerge(const Vector &Args, VPrintf(V, "MERGE-OUTER: attempt %zd\n", Attempt); Command Cmd(BaseCmd); Cmd.addFlag("merge_control_file", CFPath); - Cmd.addFlag("merge_inner", "1"); + // If we are going to use the set cover implementation for + // minimization add the merge_inner=2 internal flag. + Cmd.addFlag("merge_inner", IsSetCoverMerge ? "2" : "1"); if (!V) { Cmd.setOutputFile(getDevNull()); Cmd.combineOutAndErr(); } auto ExitCode = ExecuteCommand(Cmd); if (!ExitCode) { - VPrintf(V, "MERGE-OUTER: succesfull in %zd attempt(s)\n", Attempt); + VPrintf(V, "MERGE-OUTER: successful in %zd attempt(s)\n", Attempt); break; } } @@ -395,7 +523,10 @@ void CrashResistantMerge(const Vector &Args, M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb()); M.Files.insert(M.Files.end(), KnownFiles.begin(), KnownFiles.end()); - M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles); + if (IsSetCoverMerge) + M.SetCoverMerge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles); + else + M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles); VPrintf(V, "MERGE-OUTER: %zd new files with %zd new features added; " "%zd new coverage edges\n", NewFiles->size(), NewFeatures->size(), NewCov->size()); diff --git a/compiler-rt/lib/fuzzer/FuzzerMerge.h b/compiler-rt/lib/fuzzer/FuzzerMerge.h index e0c6bc539bd..42f798e1da1 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMerge.h +++ b/compiler-rt/lib/fuzzer/FuzzerMerge.h @@ -41,6 +41,7 @@ #define LLVM_FUZZER_MERGE_H #include "FuzzerDefs.h" +#include "FuzzerIO.h" #include #include @@ -52,11 +53,11 @@ namespace fuzzer { struct MergeFileInfo { std::string Name; size_t Size = 0; - Vector Features, Cov; + std::vector Features, Cov; }; struct Merger { - Vector Files; + std::vector Files; size_t NumFilesInFirstCorpus = 0; size_t FirstNotProcessedFile = 0; std::string LastFailure; @@ -64,23 +65,28 @@ struct Merger { bool Parse(std::istream &IS, bool ParseCoverage); bool Parse(const std::string &Str, bool ParseCoverage); void ParseOrExit(std::istream &IS, bool ParseCoverage); - size_t Merge(const Set &InitialFeatures, Set *NewFeatures, - const Set &InitialCov, Set *NewCov, - Vector *NewFiles); + size_t Merge(const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, std::set *NewCov, + std::vector *NewFiles); + size_t SetCoverMerge(const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, + std::set *NewCov, + std::vector *NewFiles); size_t ApproximateMemoryConsumption() const; - Set AllFeatures() const; + std::set AllFeatures() const; }; -void CrashResistantMerge(const Vector &Args, - const Vector &OldCorpus, - const Vector &NewCorpus, - Vector *NewFiles, - const Set &InitialFeatures, - Set *NewFeatures, - const Set &InitialCov, - Set *NewCov, - const std::string &CFPath, - bool Verbose); +void CrashResistantMerge(const std::vector &Args, + const std::vector &OldCorpus, + const std::vector &NewCorpus, + std::vector *NewFiles, + const std::set &InitialFeatures, + std::set *NewFeatures, + const std::set &InitialCov, + std::set *NewCov, const std::string &CFPath, + bool Verbose, bool IsSetCoverMerge); } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp index 4650f1becea..d663900fdc3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp @@ -485,7 +485,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { } void MutationDispatcher::PrintRecommendedDictionary() { - Vector V; + std::vector V; for (auto &DE : PersistentAutoDictionary) if (!ManualDictionary.ContainsWord(DE.GetW())) V.push_back(DE); @@ -540,7 +540,7 @@ size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, // Mutates Data in place, returns new size. size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - Vector &Mutators) { + std::vector &Mutators) { assert(MaxSize > 0); // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), // in which case they will return 0. @@ -562,7 +562,7 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, // Mask represents the set of Data bytes that are worth mutating. size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize, - const Vector &Mask) { + const std::vector &Mask) { size_t MaskedSize = std::min(Size, Mask.size()); // * Copy the worthy bytes into a temporary array T // * Mutate T diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.h b/compiler-rt/lib/fuzzer/FuzzerMutate.h index fd37191156d..97704e2160a 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMutate.h +++ b/compiler-rt/lib/fuzzer/FuzzerMutate.h @@ -77,7 +77,7 @@ public: /// that have '1' in Mask. /// Mask.size() should be >= Size. size_t MutateWithMask(uint8_t *Data, size_t Size, size_t MaxSize, - const Vector &Mask); + const std::vector &Mask); /// Applies one of the default mutations. Provided as a service /// to mutation authors. @@ -104,7 +104,7 @@ public: size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, - Vector &Mutators); + std::vector &Mutators); size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To, size_t ToSize, size_t MaxToSize); @@ -133,22 +133,22 @@ public: // entries that led to successful discoveries in the past mutations. Dictionary PersistentAutoDictionary; - Vector CurrentDictionaryEntrySequence; + std::vector CurrentDictionaryEntrySequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; size_t CmpDictionaryEntriesDequeIdx = 0; const Unit *CrossOverWith = nullptr; - Vector MutateInPlaceHere; - Vector MutateWithMaskTemp; + std::vector MutateInPlaceHere; + std::vector MutateWithMaskTemp; // CustomCrossOver needs its own buffer as a custom implementation may call // LLVMFuzzerMutate, which in turn may resize MutateInPlaceHere. - Vector CustomCrossOverInPlaceHere; + std::vector CustomCrossOverInPlaceHere; - Vector Mutators; - Vector DefaultMutators; - Vector CurrentMutatorSequence; + std::vector Mutators; + std::vector DefaultMutators; + std::vector CurrentMutatorSequence; }; } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerOptions.h b/compiler-rt/lib/fuzzer/FuzzerOptions.h index d0c285a6821..72e25610619 100644 --- a/compiler-rt/lib/fuzzer/FuzzerOptions.h +++ b/compiler-rt/lib/fuzzer/FuzzerOptions.h @@ -47,6 +47,7 @@ struct FuzzingOptions { int ReportSlowUnits = 10; bool OnlyASCII = false; bool Entropic = true; + bool ForkCorpusGroups = false; size_t EntropicFeatureFrequencyThreshold = 0xFF; size_t EntropicNumberOfRarestFeatures = 100; bool EntropicScalePerExecTime = false; diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp index d808b9b00fa..af8d1ce50f3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp @@ -157,7 +157,7 @@ ALWAYS_INLINE uintptr_t TracePC::GetNextInstructionPc(uintptr_t PC) { } void TracePC::UpdateObservedPCs() { - Vector CoveredFuncs; + std::vector CoveredFuncs; auto ObservePC = [&](const PCTableEntry *TE) { if (ObservedPCs.insert(TE).second && DoPrintNewPCs) { PrintPC("\tNEW_PC: %p %F %L", "\tNEW_PC: %p", @@ -300,8 +300,8 @@ void TracePC::PrintCoverage(bool PrintAllCounters) { FunctionStr = FunctionStr.substr(3); std::string LineStr = DescribePC("%l", VisualizePC); size_t NumEdges = Last - First; - Vector UncoveredPCs; - Vector CoveredPCs; + std::vector UncoveredPCs; + std::vector CoveredPCs; for (auto TE = First; TE < Last; TE++) if (!ObservedPCs.count(TE)) UncoveredPCs.push_back(TE->PC); @@ -391,6 +391,7 @@ void TracePC::HandleCmp(uintptr_t PC, T Arg1, T Arg2) { ValueProfileMap.AddValue(PC * 128 + 64 + AbsoluteDistance); } +ATTRIBUTE_NO_SANITIZE_MEMORY static size_t InternalStrnlen(const char *S, size_t MaxLen) { size_t Len = 0; for (; Len < MaxLen && S[Len]; Len++) {} @@ -398,7 +399,8 @@ static size_t InternalStrnlen(const char *S, size_t MaxLen) { } // Finds min of (strlen(S1), strlen(S2)). -// Needed bacause one of these strings may actually be non-zero terminated. +// Needed because one of these strings may actually be non-zero terminated. +ATTRIBUTE_NO_SANITIZE_MEMORY static size_t InternalStrnlen2(const char *S1, const char *S2) { size_t Len = 0; for (; S1[Len] && S2[Len]; Len++) {} diff --git a/compiler-rt/lib/fuzzer/FuzzerTracePC.h b/compiler-rt/lib/fuzzer/FuzzerTracePC.h index a93732972f7..af1f9d81e95 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.h +++ b/compiler-rt/lib/fuzzer/FuzzerTracePC.h @@ -169,7 +169,7 @@ private: size_t NumPCTables; size_t NumPCsInPCTables; - Set ObservedPCs; + std::set ObservedPCs; std::unordered_map ObservedFuncs; // PC => Counter. uint8_t *FocusFunctionCounterPtr = nullptr; diff --git a/compiler-rt/lib/fuzzer/FuzzerUtil.cpp b/compiler-rt/lib/fuzzer/FuzzerUtil.cpp index 05185499bdd..aeab70f20c2 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtil.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtil.cpp @@ -43,7 +43,7 @@ void PrintASCIIByte(uint8_t Byte) { else if (Byte >= 32 && Byte < 127) Printf("%c", Byte); else - Printf("\\x%02x", Byte); + Printf("\\%03o", Byte); } void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) { @@ -124,7 +124,7 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) { return true; } -bool ParseDictionaryFile(const std::string &Text, Vector *Units) { +bool ParseDictionaryFile(const std::string &Text, std::vector *Units) { if (Text.empty()) { Printf("ParseDictionaryFile: file does not exist or is empty\n"); return false; diff --git a/compiler-rt/lib/fuzzer/FuzzerUtil.h b/compiler-rt/lib/fuzzer/FuzzerUtil.h index a188a7be32a..71d49097e55 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtil.h +++ b/compiler-rt/lib/fuzzer/FuzzerUtil.h @@ -66,10 +66,10 @@ int CloseProcessPipe(FILE *F); const void *SearchMemory(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen); -std::string CloneArgsWithoutX(const Vector &Args, +std::string CloneArgsWithoutX(const std::vector &Args, const char *X1, const char *X2); -inline std::string CloneArgsWithoutX(const Vector &Args, +inline std::string CloneArgsWithoutX(const std::vector &Args, const char *X) { return CloneArgsWithoutX(Args, X, X); } diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp index 5034b4a28d3..d80b80cccb8 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp @@ -52,6 +52,12 @@ void CrashTrampolineAsm() __asm__("CrashTrampolineAsm"); namespace { +// The signal handler thread uses Zircon exceptions to resume crashed threads +// into libFuzzer's POSIX signal handlers. The associated event is used to +// signal when the thread is running, and when it should stop. +std::thread SignalHandler; +zx_handle_t SignalHandlerEvent = ZX_HANDLE_INVALID; + // Helper function to handle Zircon syscall failures. void ExitOnErr(zx_status_t Status, const char *Syscall) { if (Status != ZX_OK) { @@ -68,23 +74,6 @@ void AlarmHandler(int Seconds) { } } -// CFAOffset is used to reference the stack pointer before entering the -// trampoline (Stack Pointer + CFAOffset = prev Stack Pointer). Before jumping -// to the trampoline we copy all the registers onto the stack. We need to make -// sure that the new stack has enough space to store all the registers. -// -// The trampoline holds CFI information regarding the registers stored in the -// stack, which is then used by the unwinder to restore them. -#if defined(__x86_64__) -// In x86_64 the crashing function might also be using the red zone (128 bytes -// on top of their rsp). -constexpr size_t CFAOffset = 128 + sizeof(zx_thread_state_general_regs_t); -#elif defined(__aarch64__) -// In aarch64 we need to always have the stack pointer aligned to 16 bytes, so we -// make sure that we are keeping that same alignment. -constexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(uintptr_t)16; -#endif - // For the crash handler, we need to call Fuzzer::StaticCrashSignalCallback // without POSIX signal handlers. To achieve this, we use an assembly function // to add the necessary CFI unwinding information and a C function to bridge @@ -163,10 +152,10 @@ constexpr size_t CFAOffset = (sizeof(zx_thread_state_general_regs_t) + 15) & -(u // Produces an assembler immediate operand for the named or numbered register. // This operand contains the offset of the register relative to the CFA. -#define ASM_OPERAND_REG(reg) \ - [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg) - CFAOffset), -#define ASM_OPERAND_NUM(num) \ - [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num]) - CFAOffset), +#define ASM_OPERAND_REG(reg) \ + [reg] "i"(offsetof(zx_thread_state_general_regs_t, reg)), +#define ASM_OPERAND_NUM(num) \ + [x##num] "i"(offsetof(zx_thread_state_general_regs_t, r[num])), // Trampoline to bridge from the assembly below to the static C++ crash // callback. @@ -178,62 +167,57 @@ static void StaticCrashHandler() { } } -// Creates the trampoline with the necessary CFI information to unwind through -// to the crashing call stack: -// * Defining the CFA so that it points to the stack pointer at the point -// of crash. -// * Storing all registers at the point of crash in the stack and refer to them -// via CFI information (relative to the CFA). -// * Setting the return column so the unwinder knows how to continue unwinding. -// * (x86_64) making sure rsp is aligned before calling StaticCrashHandler. -// * Calling StaticCrashHandler that will trigger the unwinder. +// This trampoline function has the necessary CFI information to unwind +// and get a backtrace: +// * The stack contains a copy of all the registers at the point of crash, +// the code has CFI directives specifying how to restore them. +// * A call to StaticCrashHandler, which will print the stacktrace and exit +// the fuzzer, generating a crash artifact. // // The __attribute__((used)) is necessary because the function // is never called; it's just a container around the assembly to allow it to // use operands for compile-time computed constants. __attribute__((used)) void MakeTrampoline() { - __asm__(".cfi_endproc\n" - ".pushsection .text.CrashTrampolineAsm\n" - ".type CrashTrampolineAsm,STT_FUNC\n" -"CrashTrampolineAsm:\n" - ".cfi_startproc simple\n" - ".cfi_signal_frame\n" + __asm__( + ".cfi_endproc\n" + ".pushsection .text.CrashTrampolineAsm\n" + ".type CrashTrampolineAsm,STT_FUNC\n" + "CrashTrampolineAsm:\n" + ".cfi_startproc simple\n" + ".cfi_signal_frame\n" #if defined(__x86_64__) - ".cfi_return_column rip\n" - ".cfi_def_cfa rsp, %c[CFAOffset]\n" - FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) - "mov %%rsp, %%rbp\n" - ".cfi_def_cfa_register rbp\n" - "andq $-16, %%rsp\n" - "call %c[StaticCrashHandler]\n" - "ud2\n" + ".cfi_return_column rip\n" + ".cfi_def_cfa rsp, 0\n" + FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) + "call %c[StaticCrashHandler]\n" + "ud2\n" #elif defined(__aarch64__) - ".cfi_return_column 33\n" - ".cfi_def_cfa sp, %c[CFAOffset]\n" - FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) - ".cfi_offset 33, %c[pc]\n" - ".cfi_offset 30, %c[lr]\n" - "bl %c[StaticCrashHandler]\n" - "brk 1\n" + ".cfi_return_column 33\n" + ".cfi_def_cfa sp, 0\n" + FOREACH_REGISTER(CFI_OFFSET_REG, CFI_OFFSET_NUM) + ".cfi_offset 33, %c[pc]\n" + ".cfi_offset 30, %c[lr]\n" + "bl %c[StaticCrashHandler]\n" + "brk 1\n" #else #error "Unsupported architecture for fuzzing on Fuchsia" #endif - ".cfi_endproc\n" - ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" - ".popsection\n" - ".cfi_startproc\n" - : // No outputs - : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) + ".cfi_endproc\n" + ".size CrashTrampolineAsm, . - CrashTrampolineAsm\n" + ".popsection\n" + ".cfi_startproc\n" + : // No outputs + : FOREACH_REGISTER(ASM_OPERAND_REG, ASM_OPERAND_NUM) #if defined(__aarch64__) - ASM_OPERAND_REG(pc) - ASM_OPERAND_REG(lr) + ASM_OPERAND_REG(pc) ASM_OPERAND_REG(lr) #endif - [StaticCrashHandler] "i" (StaticCrashHandler), - [CFAOffset] "i" (CFAOffset)); + [StaticCrashHandler] "i"(StaticCrashHandler)); } -void CrashHandler(zx_handle_t *Event) { +void CrashHandler() { + assert(SignalHandlerEvent != ZX_HANDLE_INVALID); + // This structure is used to ensure we close handles to objects we create in // this handler. struct ScopedHandle { @@ -251,16 +235,30 @@ void CrashHandler(zx_handle_t *Event) { Self, ZX_EXCEPTION_CHANNEL_DEBUGGER, &Channel.Handle), "_zx_task_create_exception_channel"); - ExitOnErr(_zx_object_signal(*Event, 0, ZX_USER_SIGNAL_0), + ExitOnErr(_zx_object_signal(SignalHandlerEvent, 0, ZX_USER_SIGNAL_0), "_zx_object_signal"); // This thread lives as long as the process in order to keep handling // crashes. In practice, the first crashed thread to reach the end of the // StaticCrashHandler will end the process. while (true) { - ExitOnErr(_zx_object_wait_one(Channel.Handle, ZX_CHANNEL_READABLE, - ZX_TIME_INFINITE, nullptr), - "_zx_object_wait_one"); + zx_wait_item_t WaitItems[] = { + { + .handle = SignalHandlerEvent, + .waitfor = ZX_SIGNAL_HANDLE_CLOSED, + .pending = 0, + }, + { + .handle = Channel.Handle, + .waitfor = ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, + .pending = 0, + }, + }; + auto Status = _zx_object_wait_many( + WaitItems, sizeof(WaitItems) / sizeof(WaitItems[0]), ZX_TIME_INFINITE); + if (Status != ZX_OK || (WaitItems[1].pending & ZX_CHANNEL_READABLE) == 0) { + break; + } zx_exception_info_t ExceptionInfo; ScopedHandle Exception; @@ -296,14 +294,17 @@ void CrashHandler(zx_handle_t *Event) { // onto the stack and jump into a trampoline with CFI instructions on how // to restore it. #if defined(__x86_64__) - uintptr_t StackPtr = GeneralRegisters.rsp - CFAOffset; + uintptr_t StackPtr = + (GeneralRegisters.rsp - (128 + sizeof(GeneralRegisters))) & + -(uintptr_t)16; __unsanitized_memcpy(reinterpret_cast(StackPtr), &GeneralRegisters, sizeof(GeneralRegisters)); GeneralRegisters.rsp = StackPtr; GeneralRegisters.rip = reinterpret_cast(CrashTrampolineAsm); #elif defined(__aarch64__) - uintptr_t StackPtr = GeneralRegisters.sp - CFAOffset; + uintptr_t StackPtr = + (GeneralRegisters.sp - sizeof(GeneralRegisters)) & -(uintptr_t)16; __unsanitized_memcpy(reinterpret_cast(StackPtr), &GeneralRegisters, sizeof(GeneralRegisters)); GeneralRegisters.sp = StackPtr; @@ -327,6 +328,13 @@ void CrashHandler(zx_handle_t *Event) { } } +void StopSignalHandler() { + _zx_handle_close(SignalHandlerEvent); + if (SignalHandler.joinable()) { + SignalHandler.join(); + } +} + } // namespace // Platform specific functions. @@ -356,16 +364,14 @@ void SetSignalHandler(const FuzzingOptions &Options) { return; // Set up the crash handler and wait until it is ready before proceeding. - zx_handle_t Event; - ExitOnErr(_zx_event_create(0, &Event), "_zx_event_create"); + ExitOnErr(_zx_event_create(0, &SignalHandlerEvent), "_zx_event_create"); - std::thread T(CrashHandler, &Event); - zx_status_t Status = - _zx_object_wait_one(Event, ZX_USER_SIGNAL_0, ZX_TIME_INFINITE, nullptr); - _zx_handle_close(Event); + SignalHandler = std::thread(CrashHandler); + zx_status_t Status = _zx_object_wait_one(SignalHandlerEvent, ZX_USER_SIGNAL_0, + ZX_TIME_INFINITE, nullptr); ExitOnErr(Status, "_zx_object_wait_one"); - T.detach(); + std::atexit(StopSignalHandler); } void SleepSeconds(int Seconds) { diff --git a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp index 1a54bb569ec..3598758dbb4 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp @@ -204,7 +204,7 @@ const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt, } std::string DisassembleCmd(const std::string &FileName) { - Vector command_vector; + std::vector command_vector; command_vector.push_back("dumpbin /summary > nul"); if (ExecuteCommand(Command(command_vector)) == 0) return "dumpbin /disasm " + FileName; diff --git a/compiler-rt/lib/gwp_asan/common.h b/compiler-rt/lib/gwp_asan/common.h index 7ce367e3ffe..6b238ad9ecb 100644 --- a/compiler-rt/lib/gwp_asan/common.h +++ b/compiler-rt/lib/gwp_asan/common.h @@ -19,7 +19,28 @@ #include namespace gwp_asan { -enum class Error { + +// Magic header that resides in the AllocatorState so that GWP-ASan bugreports +// can be understood by tools at different versions. Out-of-process crash +// handlers, like crashpad on Fuchsia, take the raw contents of the +// AllocationMetatada array and the AllocatorState, and shove them into the +// minidump. Online unpacking of these structs needs to know from which version +// of GWP-ASan it's extracting the information, as the structures are not +// stable. +struct AllocatorVersionMagic { + // The values are copied into the structure at runtime, during + // `GuardedPoolAllocator::init()` so that GWP-ASan remains completely in the + // `.bss` segment. + static constexpr uint8_t kAllocatorVersionMagic[4] = {'A', 'S', 'A', 'N'}; + uint8_t Magic[4] = {}; + // Update the version number when the AllocatorState or AllocationMetadata + // change. + static constexpr uint16_t kAllocatorVersion = 1; + uint16_t Version = 0; + uint16_t Reserved = 0; +}; + +enum class Error : uint8_t { UNKNOWN, USE_AFTER_FREE, DOUBLE_FREE, @@ -84,6 +105,7 @@ struct AllocationMetadata { // set of information required for understanding a GWP-ASan crash. struct AllocatorState { constexpr AllocatorState() {} + AllocatorVersionMagic VersionMagic{}; // Returns whether the provided pointer is a current sampled allocation that // is owned by this pool. @@ -123,5 +145,38 @@ struct AllocatorState { uintptr_t FailureAddress = 0; }; +// Below are various compile-time checks that the layout of the internal +// GWP-ASan structures are undisturbed. If they are disturbed, the version magic +// number needs to be increased by one, and the asserts need to be updated. +// Out-of-process crash handlers, like breakpad/crashpad, may copy the internal +// GWP-ASan structures into a minidump for offline reconstruction of the crash. +// In order to accomplish this, the offline reconstructor needs to know the +// version of GWP-ASan internal structures that it's unpacking (along with the +// architecture-specific layout info, which is left as an exercise to the crash +// handler). +static_assert(offsetof(AllocatorState, VersionMagic) == 0, ""); +static_assert(sizeof(AllocatorVersionMagic) == 8, ""); +#if defined(__x86_64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__aarch64__) +static_assert(sizeof(AllocatorState) == 56, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 48, ""); +static_assert(sizeof(AllocationMetadata) == 568, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 560, ""); +#elif defined(__i386__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 548, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 544, ""); +#elif defined(__arm__) +static_assert(sizeof(AllocatorState) == 32, ""); +static_assert(offsetof(AllocatorState, FailureAddress) == 28, ""); +static_assert(sizeof(AllocationMetadata) == 560, ""); +static_assert(offsetof(AllocationMetadata, IsDeallocated) == 552, ""); +#endif // defined($ARCHITECTURE) + } // namespace gwp_asan #endif // GWP_ASAN_COMMON_H_ diff --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp index 8ce5fc9c4df..7096b428764 100644 --- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp +++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp @@ -59,6 +59,13 @@ void GuardedPoolAllocator::init(const options::Options &Opts) { SingletonPtr = this; Backtrace = Opts.Backtrace; + State.VersionMagic = {{AllocatorVersionMagic::kAllocatorVersionMagic[0], + AllocatorVersionMagic::kAllocatorVersionMagic[1], + AllocatorVersionMagic::kAllocatorVersionMagic[2], + AllocatorVersionMagic::kAllocatorVersionMagic[3]}, + AllocatorVersionMagic::kAllocatorVersion, + 0}; + State.MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations; const size_t PageSize = getPlatformPageSize(); diff --git a/compiler-rt/lib/hwasan/hwasan.cpp b/compiler-rt/lib/hwasan/hwasan.cpp index cbe0dee66dc..6f0ea64472c 100644 --- a/compiler-rt/lib/hwasan/hwasan.cpp +++ b/compiler-rt/lib/hwasan/hwasan.cpp @@ -16,6 +16,7 @@ #include "hwasan_checks.h" #include "hwasan_dynamic_shadow.h" #include "hwasan_globals.h" +#include "hwasan_mapping.h" #include "hwasan_poisoning.h" #include "hwasan_report.h" #include "hwasan_thread.h" @@ -141,7 +142,7 @@ static void CheckUnwind() { static void HwasanFormatMemoryUsage(InternalScopedString &s) { HwasanThreadList &thread_list = hwasanThreadList(); auto thread_stats = thread_list.GetThreadStats(); - auto *sds = StackDepotGetStats(); + auto sds = StackDepotGetStats(); AllocatorStatCounters asc; GetAllocatorStats(asc); s.append( @@ -151,7 +152,7 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) { internal_getpid(), GetRSS(), thread_stats.n_live_threads, thread_stats.total_stack_size, thread_stats.n_live_threads * thread_list.MemoryUsedPerThread(), - sds->allocated, sds->n_uniq_ids, asc[AllocatorStatMapped]); + sds.allocated, sds.n_uniq_ids, asc[AllocatorStatMapped]); } #if SANITIZER_ANDROID @@ -319,7 +320,7 @@ void __hwasan_init_static() { InitializeSingleGlobal(global); } -void __hwasan_init() { +__attribute__((constructor(0))) void __hwasan_init() { CHECK(!hwasan_init_is_running); if (hwasan_inited) return; hwasan_init_is_running = 1; @@ -344,7 +345,7 @@ void __hwasan_init() { // Needs to be called here because flags()->random_tags might not have been // initialized when InitInstrumentation() was called. - GetCurrentThread()->InitRandomState(); + GetCurrentThread()->EnsureRandomStateInited(); SetPrintfAndReportCallback(AppendToErrorMessageBuffer); // This may call libc -> needs initialized shadow. @@ -360,6 +361,7 @@ void __hwasan_init() { HwasanTSDThreadInit(); HwasanAllocatorInit(); + HwasanInstallAtForkHandler(); #if HWASAN_CONTAINS_UBSAN __ubsan::InitAsPlugin(); @@ -390,8 +392,15 @@ void __hwasan_print_shadow(const void *p, uptr sz) { uptr shadow_last = MemToShadow(ptr_raw + sz - 1); Printf("HWASan shadow map for %zx .. %zx (pointer tag %x)\n", ptr_raw, ptr_raw + sz, GetTagFromPointer((uptr)p)); - for (uptr s = shadow_first; s <= shadow_last; ++s) - Printf(" %zx: %x\n", ShadowToMem(s), *(tag_t *)s); + for (uptr s = shadow_first; s <= shadow_last; ++s) { + tag_t mem_tag = *reinterpret_cast(s); + uptr granule_addr = ShadowToMem(s); + if (mem_tag && mem_tag < kShadowAlignment) + Printf(" %zx: %02x(%02x)\n", granule_addr, mem_tag, + *reinterpret_cast(granule_addr + kShadowAlignment - 1)); + else + Printf(" %zx: %02x\n", granule_addr, mem_tag); + } } sptr __hwasan_test_shadow(const void *p, uptr sz) { diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h index 7338b696ad3..371c43f3cbd 100644 --- a/compiler-rt/lib/hwasan/hwasan.h +++ b/compiler-rt/lib/hwasan/hwasan.h @@ -107,6 +107,8 @@ void InitThreads(); void InitializeInterceptors(); void HwasanAllocatorInit(); +void HwasanAllocatorLock(); +void HwasanAllocatorUnlock(); void *hwasan_malloc(uptr size, StackTrace *stack); void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack); @@ -140,6 +142,8 @@ void HwasanAtExit(); void HwasanOnDeadlySignal(int signo, void *info, void *context); +void HwasanInstallAtForkHandler(); + void UpdateMemoryUsage(); void AppendToErrorMessageBuffer(const char *buffer); @@ -183,25 +187,34 @@ void HwasanTagMismatch(uptr addr, uptr access_info, uptr *registers_frame, RunFreeHooks(ptr); \ } while (false) -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) +#if HWASAN_WITH_INTERCEPTORS // For both bionic and glibc __sigset_t is an unsigned long. typedef unsigned long __hw_sigset_t; // Setjmp and longjmp implementations are platform specific, and hence the -// interception code is platform specific too. As yet we've only implemented -// the interception for AArch64. -typedef unsigned long long __hw_register_buf[22]; +// interception code is platform specific too. +# if defined(__aarch64__) +constexpr size_t kHwRegisterBufSize = 22; +# elif defined(__x86_64__) +constexpr size_t kHwRegisterBufSize = 8; +# endif +typedef unsigned long long __hw_register_buf[kHwRegisterBufSize]; struct __hw_jmp_buf_struct { // NOTE: The machine-dependent definition of `__sigsetjmp' // assume that a `__hw_jmp_buf' begins with a `__hw_register_buf' and that // `__mask_was_saved' follows it. Do not move these members or add others // before it. + // + // We add a __magic field to our struct to catch cases where libc's setjmp + // populated the jmp_buf instead of our interceptor. __hw_register_buf __jmpbuf; // Calling environment. - int __mask_was_saved; // Saved the signal mask? + unsigned __mask_was_saved : 1; // Saved the signal mask? + unsigned __magic : 31; // Used to distinguish __hw_jmp_buf from jmp_buf. __hw_sigset_t __saved_mask; // Saved signal mask. }; typedef struct __hw_jmp_buf_struct __hw_jmp_buf[1]; typedef struct __hw_jmp_buf_struct __hw_sigjmp_buf[1]; -#endif // HWASAN_WITH_INTERCEPTORS && __aarch64__ +constexpr unsigned kHwJmpBufMagic = 0x248ACE77; +#endif // HWASAN_WITH_INTERCEPTORS #define ENSURE_HWASAN_INITED() \ do { \ diff --git a/compiler-rt/lib/hwasan/hwasan_allocation_functions.cpp b/compiler-rt/lib/hwasan/hwasan_allocation_functions.cpp index 6c2a6077866..9cd82dbabd1 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocation_functions.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocation_functions.cpp @@ -14,28 +14,21 @@ #include "hwasan.h" #include "interception/interception.h" +#include "sanitizer_common/sanitizer_allocator_dlsym.h" #include "sanitizer_common/sanitizer_allocator_interface.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if !SANITIZER_FUCHSIA + using namespace __hwasan; -static uptr allocated_for_dlsym; -static const uptr kDlsymAllocPoolSize = 1024; -static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize]; +struct DlsymAlloc : public DlSymAllocator { + static bool UseImpl() { return !hwasan_inited; } +}; -static bool IsInDlsymAllocPool(const void *ptr) { - uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - return off < sizeof(alloc_memory_for_dlsym); -} - -static void *AllocateFromLocalPool(uptr size_in_bytes) { - uptr size_in_words = RoundUpTo(size_in_bytes, kWordSize) / kWordSize; - void *mem = (void *)&alloc_memory_for_dlsym[allocated_for_dlsym]; - allocated_for_dlsym += size_in_words; - CHECK_LT(allocated_for_dlsym, kDlsymAllocPoolSize); - return mem; -} +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; CHECK_NE(memptr, 0); @@ -43,16 +36,19 @@ int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) { return res; } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_memalign(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_memalign(alignment, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_aligned_alloc(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_aligned_alloc(alignment, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer___libc_memalign(uptr alignment, uptr size) { GET_MALLOC_STACK_TRACE; void *ptr = hwasan_memalign(alignment, size, &stack); @@ -61,87 +57,92 @@ void *__sanitizer___libc_memalign(uptr alignment, uptr size) { return ptr; } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_valloc(uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_valloc(size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_pvalloc(uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_pvalloc(size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_free(void *ptr) { - GET_MALLOC_STACK_TRACE; - if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + if (!ptr) return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; hwasan_free(ptr, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cfree(void *ptr) { - GET_MALLOC_STACK_TRACE; - if (!ptr || UNLIKELY(IsInDlsymAllocPool(ptr))) + if (!ptr) return; + if (DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Free(ptr); + GET_MALLOC_STACK_TRACE; hwasan_free(ptr, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_malloc_usable_size(const void *ptr) { return __sanitizer_get_allocated_size(ptr); } +SANITIZER_INTERFACE_ATTRIBUTE struct __sanitizer_struct_mallinfo __sanitizer_mallinfo() { __sanitizer_struct_mallinfo sret; internal_memset(&sret, 0, sizeof(sret)); return sret; } +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_mallopt(int cmd, int value) { return 0; } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_malloc_stats(void) { // FIXME: implement, but don't call REAL(malloc_stats)! } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_calloc(uptr nmemb, uptr size) { + if (DlsymAlloc::Use()) + return DlsymAlloc::Callocate(nmemb, size); GET_MALLOC_STACK_TRACE; - if (UNLIKELY(!hwasan_inited)) - // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. - return AllocateFromLocalPool(nmemb * size); return hwasan_calloc(nmemb, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_realloc(void *ptr, uptr size) { + if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr)) + return DlsymAlloc::Realloc(ptr, size); GET_MALLOC_STACK_TRACE; - if (UNLIKELY(IsInDlsymAllocPool(ptr))) { - uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym; - uptr copy_size = Min(size, kDlsymAllocPoolSize - offset); - void *new_ptr; - if (UNLIKELY(!hwasan_inited)) { - new_ptr = AllocateFromLocalPool(copy_size); - } else { - copy_size = size; - new_ptr = hwasan_malloc(copy_size, &stack); - } - internal_memcpy(new_ptr, ptr, copy_size); - return new_ptr; - } return hwasan_realloc(ptr, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_reallocarray(void *ptr, uptr nmemb, uptr size) { GET_MALLOC_STACK_TRACE; return hwasan_reallocarray(ptr, nmemb, size, &stack); } +SANITIZER_INTERFACE_ATTRIBUTE void *__sanitizer_malloc(uptr size) { - GET_MALLOC_STACK_TRACE; if (UNLIKELY(!hwasan_init_is_running)) ENSURE_HWASAN_INITED(); - if (UNLIKELY(!hwasan_inited)) - // Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym. - return AllocateFromLocalPool(size); + if (DlsymAlloc::Use()) + return DlsymAlloc::Allocate(size); + GET_MALLOC_STACK_TRACE; return hwasan_malloc(size, &stack); } +} // extern "C" + #if HWASAN_WITH_INTERCEPTORS # define INTERCEPTOR_ALIAS(RET, FN, ARGS...) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS) \ @@ -170,3 +171,5 @@ INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value); INTERCEPTOR_ALIAS(void, malloc_stats, void); # endif #endif // #if HWASAN_WITH_INTERCEPTORS + +#endif // SANITIZER_FUCHSIA diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cpp b/compiler-rt/lib/hwasan/hwasan_allocator.cpp index ef6d4d6c767..9e1729964e2 100644 --- a/compiler-rt/lib/hwasan/hwasan_allocator.cpp +++ b/compiler-rt/lib/hwasan/hwasan_allocator.cpp @@ -107,6 +107,10 @@ void HwasanAllocatorInit() { tail_magic[i] = GetCurrentThread()->GenerateRandomTag(); } +void HwasanAllocatorLock() { allocator.ForceLock(); } + +void HwasanAllocatorUnlock() { allocator.ForceUnlock(); } + void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) { allocator.SwallowCache(cache); } @@ -158,8 +162,11 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment, internal_memset(allocated, flags()->malloc_fill_byte, fill_size); } if (size != orig_size) { - internal_memcpy(reinterpret_cast(allocated) + orig_size, tail_magic, - size - orig_size - 1); + u8 *tail = reinterpret_cast(allocated) + orig_size; + uptr tail_length = size - orig_size; + internal_memcpy(tail, tail_magic, tail_length - 1); + // Short granule is excluded from magic tail, so we explicitly untag. + tail[tail_length - 1] = 0; } void *user_ptr = allocated; @@ -201,21 +208,37 @@ static bool PointerAndMemoryTagsMatch(void *tagged_ptr) { return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1); } +static bool CheckInvalidFree(StackTrace *stack, void *untagged_ptr, + void *tagged_ptr) { + // This function can return true if halt_on_error is false. + if (!MemIsApp(reinterpret_cast(untagged_ptr)) || + !PointerAndMemoryTagsMatch(tagged_ptr)) { + ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); + return true; + } + return false; +} + static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK(tagged_ptr); HWASAN_FREE_HOOK(tagged_ptr); - if (!PointerAndMemoryTagsMatch(tagged_ptr)) - ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); + bool in_taggable_region = + InTaggableRegion(reinterpret_cast(tagged_ptr)); + void *untagged_ptr = in_taggable_region ? UntagPtr(tagged_ptr) : tagged_ptr; + + if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr)) + return; - void *untagged_ptr = InTaggableRegion(reinterpret_cast(tagged_ptr)) - ? UntagPtr(tagged_ptr) - : tagged_ptr; void *aligned_ptr = reinterpret_cast( RoundDownTo(reinterpret_cast(untagged_ptr), kShadowAlignment)); tag_t pointer_tag = GetTagFromPointer(reinterpret_cast(tagged_ptr)); Metadata *meta = reinterpret_cast(allocator.GetMetaData(aligned_ptr)); + if (!meta) { + ReportInvalidFree(stack, reinterpret_cast(tagged_ptr)); + return; + } uptr orig_size = meta->get_requested_size(); u32 free_context_id = StackDepotPut(*stack); u32 alloc_context_id = meta->alloc_context_id; @@ -228,7 +251,11 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { CHECK_LT(tail_size, kShadowAlignment); void *tail_beg = reinterpret_cast( reinterpret_cast(aligned_ptr) + orig_size); - if (tail_size && internal_memcmp(tail_beg, tail_magic, tail_size)) + tag_t short_granule_memtag = *(reinterpret_cast( + reinterpret_cast(tail_beg) + tail_size)); + if (tail_size && + (internal_memcmp(tail_beg, tail_magic, tail_size) || + (in_taggable_region && pointer_tag != short_granule_memtag))) ReportTailOverwritten(stack, reinterpret_cast(tagged_ptr), orig_size, tail_magic); } @@ -243,8 +270,7 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size); internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size); } - if (InTaggableRegion(reinterpret_cast(tagged_ptr)) && - flags()->tag_in_free && malloc_bisect(stack, 0) && + if (in_taggable_region && flags()->tag_in_free && malloc_bisect(stack, 0) && atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) { // Always store full 8-bit tags on free to maximize UAF detection. tag_t tag; @@ -278,13 +304,15 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) { static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old, uptr new_size, uptr alignment) { - if (!PointerAndMemoryTagsMatch(tagged_ptr_old)) - ReportInvalidFree(stack, reinterpret_cast(tagged_ptr_old)); - + void *untagged_ptr_old = + InTaggableRegion(reinterpret_cast(tagged_ptr_old)) + ? UntagPtr(tagged_ptr_old) + : tagged_ptr_old; + if (CheckInvalidFree(stack, untagged_ptr_old, tagged_ptr_old)) + return nullptr; void *tagged_ptr_new = HwasanAllocate(stack, new_size, alignment, false /*zeroise*/); if (tagged_ptr_old && tagged_ptr_new) { - void *untagged_ptr_old = UntagPtr(tagged_ptr_old); Metadata *meta = reinterpret_cast(allocator.GetMetaData(untagged_ptr_old)); internal_memcpy( @@ -305,6 +333,8 @@ static void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) { } HwasanChunkView FindHeapChunkByAddress(uptr address) { + if (!allocator.PointerIsMine(reinterpret_cast(address))) + return HwasanChunkView(); void *block = allocator.GetBlockBegin(reinterpret_cast(address)); if (!block) return HwasanChunkView(); diff --git a/compiler-rt/lib/hwasan/hwasan_exceptions.cpp b/compiler-rt/lib/hwasan/hwasan_exceptions.cpp index 169e7876cb5..6ed1da33542 100644 --- a/compiler-rt/lib/hwasan/hwasan_exceptions.cpp +++ b/compiler-rt/lib/hwasan/hwasan_exceptions.cpp @@ -29,8 +29,8 @@ typedef _Unwind_Reason_Code PersonalityFn(int version, _Unwind_Action actions, // is statically linked and the sanitizer runtime and the program are linked // against different unwinders. The _Unwind_Context data structure is opaque so // it may be incompatible between unwinders. -typedef _Unwind_Word GetGRFn(_Unwind_Context* context, int index); -typedef _Unwind_Word GetCFAFn(_Unwind_Context* context); +typedef uintptr_t GetGRFn(_Unwind_Context* context, int index); +typedef uintptr_t GetCFAFn(_Unwind_Context* context); extern "C" SANITIZER_INTERFACE_ATTRIBUTE _Unwind_Reason_Code __hwasan_personality_wrapper(int version, _Unwind_Action actions, diff --git a/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp b/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp index e299a7e862e..94e5c5fb69c 100644 --- a/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp +++ b/compiler-rt/lib/hwasan/hwasan_fuchsia.cpp @@ -130,7 +130,7 @@ static void ThreadCreateHook(void *hook, bool aborted) { static void ThreadStartHook(void *hook, thrd_t self) { Thread *thread = static_cast(hook); FinishThreadInitialization(thread); - thread->InitRandomState(); + thread->EnsureRandomStateInited(); } // This is the function that sets up the stack ring buffer and enables us to use @@ -180,6 +180,8 @@ void HwasanTSDThreadInit() {} // function is unneeded. void InstallAtExitHandler() {} +void HwasanInstallAtForkHandler() {} + // TODO(fxbug.dev/81499): Once we finalize the tagged pointer ABI in zircon, we should come back // here and implement the appropriate check that TBI is enabled. void InitializeOsSupport() {} diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp index 68f8adec077..f96ed880410 100644 --- a/compiler-rt/lib/hwasan/hwasan_interceptors.cpp +++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cpp @@ -49,15 +49,14 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*), DEFINE_REAL(int, vfork) DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork) -#endif // HWASAN_WITH_INTERCEPTORS -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) // Get and/or change the set of blocked signals. extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set, __hw_sigset_t *__restrict __oset); #define SIG_BLOCK 0 #define SIG_SETMASK 2 extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) { + env[0].__magic = kHwJmpBufMagic; env[0].__mask_was_saved = (savemask && sigprocmask(SIG_BLOCK, (__hw_sigset_t *)0, &env[0].__saved_mask) == 0); @@ -66,8 +65,14 @@ extern "C" int __sigjmp_save(__hw_sigjmp_buf env, int savemask) { static void __attribute__((always_inline)) InternalLongjmp(__hw_register_buf env, int retval) { +# if defined(__aarch64__) + constexpr size_t kSpIndex = 13; +# elif defined(__x86_64__) + constexpr size_t kSpIndex = 6; +# endif + // Clear all memory tags on the stack between here and where we're going. - unsigned long long stack_pointer = env[13]; + unsigned long long stack_pointer = env[kSpIndex]; // The stack pointer should never be tagged, so we don't need to clear the // tag for this function call. __hwasan_handle_longjmp((void *)stack_pointer); @@ -78,6 +83,7 @@ InternalLongjmp(__hw_register_buf env, int retval) { // Must implement this ourselves, since we don't know the order of registers // in different libc implementations and many implementations mangle the // stack pointer so we can't use it without knowing the demangling scheme. +# if defined(__aarch64__) register long int retval_tmp asm("x1") = retval; register void *env_address asm("x0") = &env[0]; asm volatile("ldp x19, x20, [%0, #0<<3];" @@ -100,9 +106,36 @@ InternalLongjmp(__hw_register_buf env, int retval) { "br x30;" : "+r"(env_address) : "r"(retval_tmp)); +# elif defined(__x86_64__) + register long int retval_tmp asm("%rsi") = retval; + register void *env_address asm("%rdi") = &env[0]; + asm volatile( + // Restore registers. + "mov (0*8)(%0),%%rbx;" + "mov (1*8)(%0),%%rbp;" + "mov (2*8)(%0),%%r12;" + "mov (3*8)(%0),%%r13;" + "mov (4*8)(%0),%%r14;" + "mov (5*8)(%0),%%r15;" + "mov (6*8)(%0),%%rsp;" + "mov (7*8)(%0),%%rdx;" + // Return 1 if retval is 0. + "mov $1,%%rax;" + "test %1,%1;" + "cmovnz %1,%%rax;" + "jmp *%%rdx;" ::"r"(env_address), + "r"(retval_tmp)); +# endif } INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) { + Printf( + "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or " + "there is a bug in HWASan.\n"); + return REAL(siglongjmp)(env, val); + } + if (env[0].__mask_was_saved) // Restore the saved signal mask. (void)sigprocmask(SIG_SETMASK, &env[0].__saved_mask, @@ -114,32 +147,24 @@ INTERCEPTOR(void, siglongjmp, __hw_sigjmp_buf env, int val) { // _setjmp on start_thread. Hence we have to intercept the longjmp on // pthread_exit so the __hw_jmp_buf order matches. INTERCEPTOR(void, __libc_longjmp, __hw_jmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) + return REAL(__libc_longjmp)(env, val); InternalLongjmp(env[0].__jmpbuf, val); } INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) { + if (env[0].__magic != kHwJmpBufMagic) { + Printf( + "WARNING: Unexpected bad jmp_buf. Either setjmp was not called or " + "there is a bug in HWASan.\n"); + return REAL(longjmp)(env, val); + } InternalLongjmp(env[0].__jmpbuf, val); } #undef SIG_BLOCK #undef SIG_SETMASK -#endif // HWASAN_WITH_INTERCEPTORS && __aarch64__ - -static void BeforeFork() { - StackDepotLockAll(); -} - -static void AfterFork() { - StackDepotUnlockAll(); -} - -INTERCEPTOR(int, fork, void) { - ENSURE_HWASAN_INITED(); - BeforeFork(); - int pid = REAL(fork)(); - AfterFork(); - return pid; -} +# endif // HWASAN_WITH_INTERCEPTORS namespace __hwasan { @@ -156,10 +181,11 @@ void InitializeInterceptors() { static int inited = 0; CHECK_EQ(inited, 0); - INTERCEPT_FUNCTION(fork); - #if HWASAN_WITH_INTERCEPTORS #if defined(__linux__) + INTERCEPT_FUNCTION(__libc_longjmp); + INTERCEPT_FUNCTION(longjmp); + INTERCEPT_FUNCTION(siglongjmp); INTERCEPT_FUNCTION(vfork); #endif // __linux__ INTERCEPT_FUNCTION(pthread_create); diff --git a/compiler-rt/lib/hwasan/hwasan_interface_internal.h b/compiler-rt/lib/hwasan/hwasan_interface_internal.h index 25c0f94fe51..ef771add411 100644 --- a/compiler-rt/lib/hwasan/hwasan_interface_internal.h +++ b/compiler-rt/lib/hwasan/hwasan_interface_internal.h @@ -168,54 +168,6 @@ void __hwasan_thread_exit(); SANITIZER_INTERFACE_ATTRIBUTE void __hwasan_print_memory_usage(); -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_memalign(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_aligned_alloc(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer___libc_memalign(uptr alignment, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_valloc(uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_pvalloc(uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_free(void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cfree(void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -uptr __sanitizer_malloc_usable_size(const void *ptr); - -SANITIZER_INTERFACE_ATTRIBUTE -__hwasan::__sanitizer_struct_mallinfo __sanitizer_mallinfo(); - -SANITIZER_INTERFACE_ATTRIBUTE -int __sanitizer_mallopt(int cmd, int value); - -SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_malloc_stats(void); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_calloc(uptr nmemb, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_realloc(void *ptr, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_reallocarray(void *ptr, uptr nmemb, uptr size); - -SANITIZER_INTERFACE_ATTRIBUTE -void * __sanitizer_malloc(uptr size); - SANITIZER_INTERFACE_ATTRIBUTE void *__hwasan_memcpy(void *dst, const void *src, uptr size); SANITIZER_INTERFACE_ATTRIBUTE diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cpp b/compiler-rt/lib/hwasan/hwasan_linux.cpp index e22723529f4..ba9e23621cc 100644 --- a/compiler-rt/lib/hwasan/hwasan_linux.cpp +++ b/compiler-rt/lib/hwasan/hwasan_linux.cpp @@ -15,30 +15,30 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD -#include "hwasan.h" -#include "hwasan_dynamic_shadow.h" -#include "hwasan_interface_internal.h" -#include "hwasan_mapping.h" -#include "hwasan_report.h" -#include "hwasan_thread.h" -#include "hwasan_thread_list.h" +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sanitizer_common/sanitizer_common.h" -#include "sanitizer_common/sanitizer_procmaps.h" +# include "hwasan.h" +# include "hwasan_dynamic_shadow.h" +# include "hwasan_interface_internal.h" +# include "hwasan_mapping.h" +# include "hwasan_report.h" +# include "hwasan_thread.h" +# include "hwasan_thread_list.h" +# include "sanitizer_common/sanitizer_common.h" +# include "sanitizer_common/sanitizer_procmaps.h" +# include "sanitizer_common/sanitizer_stackdepot.h" // Configurations of HWASAN_WITH_INTERCEPTORS and SANITIZER_ANDROID. // @@ -50,10 +50,10 @@ // Tested with check-hwasan on x86_64-linux. // HWASAN_WITH_INTERCEPTORS=ON, SANITIZER_ANDROID=ON // Tested with check-hwasan on aarch64-linux-android. -#if !SANITIZER_ANDROID +# if !SANITIZER_ANDROID SANITIZER_INTERFACE_ATTRIBUTE THREADLOCAL uptr __hwasan_tls; -#endif +# endif namespace __hwasan { @@ -111,9 +111,9 @@ static void InitializeShadowBaseAddress(uptr shadow_size_bytes) { } void InitializeOsSupport() { -#define PR_SET_TAGGED_ADDR_CTRL 55 -#define PR_GET_TAGGED_ADDR_CTRL 56 -#define PR_TAGGED_ADDR_ENABLE (1UL << 0) +# define PR_SET_TAGGED_ADDR_CTRL 55 +# define PR_GET_TAGGED_ADDR_CTRL 56 +# define PR_TAGGED_ADDR_ENABLE (1UL << 0) // Check we're running on a kernel that can use the tagged address ABI. int local_errno = 0; if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0), @@ -164,9 +164,9 @@ void InitializeOsSupport() { Die(); } } -#undef PR_SET_TAGGED_ADDR_CTRL -#undef PR_GET_TAGGED_ADDR_CTRL -#undef PR_TAGGED_ADDR_ENABLE +# undef PR_SET_TAGGED_ADDR_CTRL +# undef PR_GET_TAGGED_ADDR_CTRL +# undef PR_TAGGED_ADDR_ENABLE } bool InitShadow() { @@ -241,17 +241,16 @@ bool MemIsApp(uptr p) { CHECK(GetTagFromPointer(p) == 0); # endif - return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd); + return (p >= kHighMemStart && p <= kHighMemEnd) || + (p >= kLowMemStart && p <= kLowMemEnd); } -void InstallAtExitHandler() { - atexit(HwasanAtExit); -} +void InstallAtExitHandler() { atexit(HwasanAtExit); } // ---------------------- TSD ---------------- {{{1 extern "C" void __hwasan_thread_enter() { - hwasanThreadList().CreateCurrentThread()->InitRandomState(); + hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited(); } extern "C" void __hwasan_thread_exit() { @@ -262,7 +261,7 @@ extern "C" void __hwasan_thread_exit() { hwasanThreadList().ReleaseThread(t); } -#if HWASAN_WITH_INTERCEPTORS +# if HWASAN_WITH_INTERCEPTORS static pthread_key_t tsd_key; static bool tsd_key_inited = false; @@ -286,22 +285,18 @@ void HwasanTSDInit() { tsd_key_inited = true; CHECK_EQ(0, pthread_key_create(&tsd_key, HwasanTSDDtor)); } -#else +# else void HwasanTSDInit() {} void HwasanTSDThreadInit() {} -#endif +# endif -#if SANITIZER_ANDROID -uptr *GetCurrentThreadLongPtr() { - return (uptr *)get_android_tls_ptr(); -} -#else -uptr *GetCurrentThreadLongPtr() { - return &__hwasan_tls; -} -#endif +# if SANITIZER_ANDROID +uptr *GetCurrentThreadLongPtr() { return (uptr *)get_android_tls_ptr(); } +# else +uptr *GetCurrentThreadLongPtr() { return &__hwasan_tls; } +# endif -#if SANITIZER_ANDROID +# if SANITIZER_ANDROID void AndroidTestTlsSlot() { uptr kMagicValue = 0x010203040A0B0C0D; uptr *tls_ptr = GetCurrentThreadLongPtr(); @@ -316,9 +311,9 @@ void AndroidTestTlsSlot() { } *tls_ptr = old_value; } -#else +# else void AndroidTestTlsSlot() {} -#endif +# endif static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { // Access type is passed in a platform dependent way (see below) and encoded @@ -326,32 +321,32 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { // recoverable. Valid values of Y are 0 to 4, which are interpreted as // log2(access_size), and 0xF, which means that access size is passed via // platform dependent register (see below). -#if defined(__aarch64__) +# if defined(__aarch64__) // Access type is encoded in BRK immediate as 0x900 + 0xXY. For Y == 0xF, // access size is stored in X1 register. Access address is always in X0 // register. uptr pc = (uptr)info->si_addr; const unsigned code = ((*(u32 *)pc) >> 5) & 0xffff; if ((code & 0xff00) != 0x900) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const bool is_store = code & 0x10; const bool recover = code & 0x20; const uptr addr = uc->uc_mcontext.regs[0]; const unsigned size_log = code & 0xf; if (size_log > 4 && size_log != 0xf) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const uptr size = size_log == 0xf ? uc->uc_mcontext.regs[1] : 1U << size_log; -#elif defined(__x86_64__) +# elif defined(__x86_64__) // Access type is encoded in the instruction following INT3 as // NOP DWORD ptr [EAX + 0x40 + 0xXY]. For Y == 0xF, access size is stored in // RSI register. Access address is always in RDI register. uptr pc = (uptr)uc->uc_mcontext.gregs[REG_RIP]; - uint8_t *nop = (uint8_t*)pc; - if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || + uint8_t *nop = (uint8_t *)pc; + if (*nop != 0x0f || *(nop + 1) != 0x1f || *(nop + 2) != 0x40 || *(nop + 3) < 0x40) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const unsigned code = *(nop + 3); const bool is_store = code & 0x10; @@ -359,13 +354,13 @@ static AccessInfo GetAccessInfo(siginfo_t *info, ucontext_t *uc) { const uptr addr = uc->uc_mcontext.gregs[REG_RDI]; const unsigned size_log = code & 0xf; if (size_log > 4 && size_log != 0xf) - return AccessInfo{}; // Not ours. + return AccessInfo{}; // Not ours. const uptr size = size_log == 0xf ? uc->uc_mcontext.gregs[REG_RSI] : 1U << size_log; -#else -# error Unsupported architecture -#endif +# else +# error Unsupported architecture +# endif return AccessInfo{addr, size, is_store, !is_store, recover}; } @@ -378,12 +373,12 @@ static bool HwasanOnSIGTRAP(int signo, siginfo_t *info, ucontext_t *uc) { SignalContext sig{info, uc}; HandleTagMismatch(ai, StackTrace::GetNextInstructionPc(sig.pc), sig.bp, uc); -#if defined(__aarch64__) +# if defined(__aarch64__) uc->uc_mcontext.pc += 4; -#elif defined(__x86_64__) -#else -# error Unsupported architecture -#endif +# elif defined(__x86_64__) +# else +# error Unsupported architecture +# endif return true; } @@ -396,7 +391,7 @@ static void OnStackUnwind(const SignalContext &sig, const void *, void HwasanOnDeadlySignal(int signo, void *info, void *context) { // Probably a tag mismatch. if (signo == SIGTRAP) - if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t*)context)) + if (HwasanOnSIGTRAP(signo, (siginfo_t *)info, (ucontext_t *)context)) return; HandleDeadlySignal(info, context, GetTid(), &OnStackUnwind, nullptr); @@ -435,6 +430,18 @@ uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) { return AddTagToPointer(p, tag); } -} // namespace __hwasan +void HwasanInstallAtForkHandler() { + auto before = []() { + HwasanAllocatorLock(); + StackDepotLockAll(); + }; + auto after = []() { + StackDepotUnlockAll(); + HwasanAllocatorUnlock(); + }; + pthread_atfork(before, after, after); +} -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD +} // namespace __hwasan + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD diff --git a/compiler-rt/lib/hwasan/hwasan_report.cpp b/compiler-rt/lib/hwasan/hwasan_report.cpp index 44047c9fdaf..66d3d155d40 100644 --- a/compiler-rt/lib/hwasan/hwasan_report.cpp +++ b/compiler-rt/lib/hwasan/hwasan_report.cpp @@ -37,7 +37,7 @@ namespace __hwasan { class ScopedReport { public: ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); error_message_ptr_ = fatal ? &error_message_ : nullptr; ++hwasan_report_count; } @@ -45,7 +45,7 @@ class ScopedReport { ~ScopedReport() { void (*report_cb)(const char *); { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); report_cb = error_report_callback_; error_message_ptr_ = nullptr; } @@ -61,7 +61,7 @@ class ScopedReport { } static void MaybeAppendToErrorMessage(const char *msg) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); if (!error_message_ptr_) return; uptr len = internal_strlen(msg); @@ -72,7 +72,7 @@ class ScopedReport { } static void SetErrorReportCallback(void (*callback)(const char *)) { - BlockingMutexLock lock(&error_message_lock_); + Lock lock(&error_message_lock_); error_report_callback_ = callback; } @@ -82,12 +82,12 @@ class ScopedReport { bool fatal; static InternalMmapVector *error_message_ptr_; - static BlockingMutex error_message_lock_; + static Mutex error_message_lock_; static void (*error_report_callback_)(const char *); }; InternalMmapVector *ScopedReport::error_message_ptr_; -BlockingMutex ScopedReport::error_message_lock_; +Mutex ScopedReport::error_message_lock_; void (*ScopedReport::error_report_callback_)(const char *); // If there is an active ScopedReport, append to its error message. @@ -351,14 +351,16 @@ static void ShowHeapOrGlobalCandidate(uptr untagged_addr, tag_t *candidate, uptr size = GetGlobalSizeFromDescriptor(mem); if (size == 0) // We couldn't find the size of the global from the descriptors. - Printf("%p is located to the %s of a global variable in (%s+0x%x)\n", - untagged_addr, candidate == left ? "right" : "left", module_name, - module_address); + Printf( + "%p is located to the %s of a global variable in " + "\n #0 0x%x (%s+0x%x)\n", + untagged_addr, candidate == left ? "right" : "left", mem, + module_name, module_address); else Printf( "%p is located to the %s of a %zd-byte global variable in " - "(%s+0x%x)\n", - untagged_addr, candidate == left ? "right" : "left", size, + "\n #0 0x%x (%s+0x%x)\n", + untagged_addr, candidate == left ? "right" : "left", size, mem, module_name, module_address); } Printf("%s", d.Default()); @@ -372,6 +374,12 @@ void PrintAddressDescription( int num_descriptions_printed = 0; uptr untagged_addr = UntagAddr(tagged_addr); + if (MemIsShadow(untagged_addr)) { + Printf("%s%p is HWAsan shadow memory.\n%s", d.Location(), untagged_addr, + d.Default()); + return; + } + // Print some very basic information about the address, if it's a heap. HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr); if (uptr beg = chunk.Beg()) { @@ -510,7 +518,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows, InternalScopedString s; for (tag_t *row = beg_row; row < end_row; row += row_len) { s.append("%s", row == center_row_beg ? "=>" : " "); - s.append("%p:", row); + s.append("%p:", (void *)row); for (uptr i = 0; i < row_len; i++) { s.append("%s", row + i == tag_ptr ? "[" : " "); print_tag(s, &row[i]); @@ -549,28 +557,48 @@ static void PrintTagsAroundAddr(tag_t *tag_ptr) { "description of short granule tags\n"); } +uptr GetTopPc(StackTrace *stack) { + return stack->size ? StackTrace::GetPreviousInstructionPc(stack->trace[0]) + : 0; +} + void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { ScopedReport R(flags()->halt_on_error); uptr untagged_addr = UntagAddr(tagged_addr); tag_t ptr_tag = GetTagFromPointer(tagged_addr); - tag_t *tag_ptr = reinterpret_cast(MemToShadow(untagged_addr)); - tag_t mem_tag = *tag_ptr; + tag_t *tag_ptr = nullptr; + tag_t mem_tag = 0; + if (MemIsApp(untagged_addr)) { + tag_ptr = reinterpret_cast(MemToShadow(untagged_addr)); + if (MemIsShadow(reinterpret_cast(tag_ptr))) + mem_tag = *tag_ptr; + else + tag_ptr = nullptr; + } Decorator d; Printf("%s", d.Error()); - uptr pc = stack->size ? stack->trace[0] : 0; + uptr pc = GetTopPc(stack); const char *bug_type = "invalid-free"; - Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, - untagged_addr, pc); + const Thread *thread = GetCurrentThread(); + if (thread) { + Report("ERROR: %s: %s on address %p at pc %p on thread T%zd\n", + SanitizerToolName, bug_type, untagged_addr, pc, thread->unique_id()); + } else { + Report("ERROR: %s: %s on address %p at pc %p on unknown thread\n", + SanitizerToolName, bug_type, untagged_addr, pc); + } Printf("%s", d.Access()); - Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); + if (tag_ptr) + Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); Printf("%s", d.Default()); stack->Print(); PrintAddressDescription(tagged_addr, 0, nullptr); - PrintTagsAroundAddr(tag_ptr); + if (tag_ptr) + PrintTagsAroundAddr(tag_ptr); ReportErrorSummary(bug_type, stack); } @@ -578,6 +606,15 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size, const u8 *expected) { uptr tail_size = kShadowAlignment - (orig_size % kShadowAlignment); + u8 actual_expected[kShadowAlignment]; + internal_memcpy(actual_expected, expected, tail_size); + tag_t ptr_tag = GetTagFromPointer(tagged_addr); + // Short granule is stashed in the last byte of the magic string. To avoid + // confusion, make the expected magic string contain the short granule tag. + if (orig_size % kShadowAlignment != 0) { + actual_expected[tail_size - 1] = ptr_tag; + } + ScopedReport R(flags()->halt_on_error); Decorator d; uptr untagged_addr = UntagAddr(tagged_addr); @@ -614,14 +651,13 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size, s.append("Expected: "); for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.append(".. "); - for (uptr i = 0; i < tail_size; i++) - s.append("%02x ", expected[i]); + for (uptr i = 0; i < tail_size; i++) s.append("%02x ", actual_expected[i]); s.append("\n"); s.append(" "); for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.append(" "); for (uptr i = 0; i < tail_size; i++) - s.append("%s ", expected[i] != tail[i] ? "^^" : " "); + s.append("%s ", actual_expected[i] != tail[i] ? "^^" : " "); s.append("\nThis error occurs when a buffer overflow overwrites memory\n" "to the right of a heap object, but within the %zd-byte granule, e.g.\n" @@ -647,11 +683,11 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, GetCurrentThread()->stack_allocations()); Decorator d; - Printf("%s", d.Error()); uptr untagged_addr = UntagAddr(tagged_addr); // TODO: when possible, try to print heap-use-after-free, etc. const char *bug_type = "tag-mismatch"; - uptr pc = stack->size ? stack->trace[0] : 0; + uptr pc = GetTopPc(stack); + Printf("%s", d.Error()); Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, untagged_addr, pc); @@ -666,12 +702,33 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, tag_t mem_tag = *tag_ptr; Printf("%s", d.Access()); - Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", - is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, - mem_tag, t->unique_id()); + if (mem_tag && mem_tag < kShadowAlignment) { + tag_t *granule_ptr = reinterpret_cast((untagged_addr + offset) & + ~(kShadowAlignment - 1)); + // If offset is 0, (untagged_addr + offset) is not aligned to granules. + // This is the offset of the leftmost accessed byte within the bad granule. + u8 in_granule_offset = (untagged_addr + offset) & (kShadowAlignment - 1); + tag_t short_tag = granule_ptr[kShadowAlignment - 1]; + // The first mismatch was a short granule that matched the ptr_tag. + if (short_tag == ptr_tag) { + // If the access starts after the end of the short granule, then the first + // bad byte is the first byte of the access; otherwise it is the first + // byte past the end of the short granule + if (mem_tag > in_granule_offset) { + offset += mem_tag - in_granule_offset; + } + } + Printf( + "%s of size %zu at %p tags: %02x/%02x(%02x) (ptr/mem) in thread T%zd\n", + is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, + mem_tag, short_tag, t->unique_id()); + } else { + Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", + is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, + mem_tag, t->unique_id()); + } if (offset != 0) - Printf("Invalid access starting at offset [%zu, %zu)\n", offset, - Min(access_size, static_cast(offset) + (1 << kShadowScale))); + Printf("Invalid access starting at offset %zu\n", offset); Printf("%s", d.Default()); stack->Print(); diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp.S b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S similarity index 87% rename from compiler-rt/lib/hwasan/hwasan_setjmp.S rename to compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S index 381af63363c..744748a5101 100644 --- a/compiler-rt/lib/hwasan/hwasan_setjmp.S +++ b/compiler-rt/lib/hwasan/hwasan_setjmp_aarch64.S @@ -1,4 +1,4 @@ -//===-- hwasan_setjmp.S --------------------------------------------------------===// +//===-- hwasan_setjmp_aarch64.S -------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -29,7 +29,7 @@ // Hence we have to write this function in assembly. .section .text -.file "hwasan_setjmp.S" +.file "hwasan_setjmp_aarch64.S" .global __interceptor_setjmp ASM_TYPE_FUNCTION(__interceptor_setjmp) @@ -80,24 +80,19 @@ __interceptor_sigsetjmp: ASM_SIZE(__interceptor_sigsetjmp) -.macro ALIAS first second - .globl \second +.macro WEAK_ALIAS first second + .weak \second .equ \second\(), \first .endm #if SANITIZER_ANDROID -ALIAS __interceptor_sigsetjmp, sigsetjmp -.weak sigsetjmp - -ALIAS __interceptor_setjmp_bionic, setjmp -.weak setjmp +WEAK_ALIAS __interceptor_sigsetjmp, sigsetjmp +WEAK_ALIAS __interceptor_setjmp_bionic, setjmp #else -ALIAS __interceptor_sigsetjmp, __sigsetjmp -.weak __sigsetjmp +WEAK_ALIAS __interceptor_sigsetjmp, __sigsetjmp #endif -ALIAS __interceptor_setjmp, _setjmp -.weak _setjmp +WEAK_ALIAS __interceptor_setjmp, _setjmp #endif // We do not need executable stack. diff --git a/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S b/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S new file mode 100644 index 00000000000..7566c1ea0a5 --- /dev/null +++ b/compiler-rt/lib/hwasan/hwasan_setjmp_x86_64.S @@ -0,0 +1,82 @@ +//===-- hwasan_setjmp_x86_64.S --------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// setjmp interceptor for x86_64. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_asm.h" + +#if HWASAN_WITH_INTERCEPTORS && defined(__x86_64__) +#include "sanitizer_common/sanitizer_platform.h" + +// We want to save the context of the calling function. +// That requires +// 1) No modification of the return address by this function. +// 2) No modification of the stack pointer by this function. +// 3) (no modification of any other saved register, but that's not really going +// to occur, and hence isn't as much of a worry). +// +// There's essentially no way to ensure that the compiler will not modify the +// stack pointer when compiling a C function. +// Hence we have to write this function in assembly. +// +// TODO: Handle Intel CET. + +.section .text +.file "hwasan_setjmp_x86_64.S" + +.global __interceptor_setjmp +ASM_TYPE_FUNCTION(__interceptor_setjmp) +__interceptor_setjmp: + CFI_STARTPROC + _CET_ENDBR + xorl %esi, %esi + jmp __interceptor_sigsetjmp + CFI_ENDPROC +ASM_SIZE(__interceptor_setjmp) + +.global __interceptor_sigsetjmp +ASM_TYPE_FUNCTION(__interceptor_sigsetjmp) +__interceptor_sigsetjmp: + CFI_STARTPROC + _CET_ENDBR + + // Save callee save registers. + mov %rbx, (0*8)(%rdi) + mov %rbp, (1*8)(%rdi) + mov %r12, (2*8)(%rdi) + mov %r13, (3*8)(%rdi) + mov %r14, (4*8)(%rdi) + mov %r15, (5*8)(%rdi) + + // Save SP as it was in caller's frame. + lea 8(%rsp), %rdx + mov %rdx, (6*8)(%rdi) + + // Save return address. + mov (%rsp), %rax + mov %rax, (7*8)(%rdi) + + jmp __sigjmp_save + + CFI_ENDPROC +ASM_SIZE(__interceptor_sigsetjmp) + + +.macro WEAK_ALIAS first second + .weak \second + .equ \second\(), \first +.endm + +WEAK_ALIAS __interceptor_sigsetjmp, __sigsetjmp +WEAK_ALIAS __interceptor_setjmp, _setjmp +#endif + +// We do not need executable stack. +NO_EXEC_STACK_DIRECTIVE diff --git a/compiler-rt/lib/hwasan/hwasan_thread.cpp b/compiler-rt/lib/hwasan/hwasan_thread.cpp index ee747a3beea..c776ae179ce 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.cpp +++ b/compiler-rt/lib/hwasan/hwasan_thread.cpp @@ -1,15 +1,15 @@ +#include "hwasan_thread.h" + #include "hwasan.h" -#include "hwasan_mapping.h" -#include "hwasan_thread.h" -#include "hwasan_poisoning.h" #include "hwasan_interface_internal.h" - +#include "hwasan_mapping.h" +#include "hwasan_poisoning.h" +#include "sanitizer_common/sanitizer_atomic.h" #include "sanitizer_common/sanitizer_file.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" - namespace __hwasan { static u32 RandomSeed() { @@ -27,6 +27,7 @@ static u32 RandomSeed() { void Thread::InitRandomState() { random_state_ = flags()->random_tags ? RandomSeed() : unique_id_; + random_state_inited_ = true; // Push a random number of zeros onto the ring buffer so that the first stack // tag base will be random. @@ -40,18 +41,19 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size, CHECK_EQ(0, stack_top_); CHECK_EQ(0, stack_bottom_); - static u64 unique_id; - unique_id_ = unique_id++; + static atomic_uint64_t unique_id; + unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed); + if (auto sz = flags()->heap_history_size) heap_allocations_ = HeapAllocationsRingBuffer::New(sz); - InitStackAndTls(state); #if !SANITIZER_FUCHSIA // Do not initialize the stack ring buffer just yet on Fuchsia. Threads will // be initialized before we enter the thread itself, so we will instead call // this later. InitStackRingBuffer(stack_buffer_start, stack_buffer_size); #endif + InitStackAndTls(state); } void Thread::InitStackRingBuffer(uptr stack_buffer_start, @@ -108,10 +110,9 @@ void Thread::Destroy() { } void Thread::Print(const char *Prefix) { - Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, - unique_id_, this, stack_bottom(), stack_top(), - stack_top() - stack_bottom(), - tls_begin(), tls_end()); + Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, unique_id_, + (void *)this, stack_bottom(), stack_top(), + stack_top() - stack_bottom(), tls_begin(), tls_end()); } static u32 xorshift(u32 state) { @@ -124,17 +125,21 @@ static u32 xorshift(u32 state) { // Generate a (pseudo-)random non-zero tag. tag_t Thread::GenerateRandomTag(uptr num_bits) { DCHECK_GT(num_bits, 0); - if (tagging_disabled_) return 0; + if (tagging_disabled_) + return 0; tag_t tag; const uptr tag_mask = (1ULL << num_bits) - 1; do { if (flags()->random_tags) { - if (!random_buffer_) + if (!random_buffer_) { + EnsureRandomStateInited(); random_buffer_ = random_state_ = xorshift(random_state_); + } CHECK(random_buffer_); tag = random_buffer_ & tag_mask; random_buffer_ >>= num_bits; } else { + EnsureRandomStateInited(); random_state_ += 1; tag = random_state_ & tag_mask; } diff --git a/compiler-rt/lib/hwasan/hwasan_thread.h b/compiler-rt/lib/hwasan/hwasan_thread.h index 9f20afe1dc7..3db7c1a9454 100644 --- a/compiler-rt/lib/hwasan/hwasan_thread.h +++ b/compiler-rt/lib/hwasan/hwasan_thread.h @@ -28,12 +28,17 @@ class Thread { void Init(uptr stack_buffer_start, uptr stack_buffer_size, const InitState *state = nullptr); - void InitRandomState(); + void InitStackAndTls(const InitState *state = nullptr); // Must be called from the thread itself. void InitStackRingBuffer(uptr stack_buffer_start, uptr stack_buffer_size); + inline void EnsureRandomStateInited() { + if (UNLIKELY(!random_state_inited_)) + InitRandomState(); + } + void Destroy(); uptr stack_top() { return stack_top_; } @@ -70,6 +75,7 @@ class Thread { // via mmap() and *must* be valid in zero-initialized state. void ClearShadowForThreadStackAndTLS(); void Print(const char *prefix); + void InitRandomState(); uptr vfork_spill_; uptr stack_top_; uptr stack_bottom_; @@ -89,6 +95,8 @@ class Thread { bool announced_; + bool random_state_inited_; // Whether InitRandomState() has been called. + friend struct ThreadListHead; }; diff --git a/compiler-rt/lib/hwasan/hwasan_type_test.cpp b/compiler-rt/lib/hwasan/hwasan_type_test.cpp index 8cff495bae1..5307073fb40 100644 --- a/compiler-rt/lib/hwasan/hwasan_type_test.cpp +++ b/compiler-rt/lib/hwasan/hwasan_type_test.cpp @@ -19,7 +19,7 @@ #define CHECK_TYPE_SIZE_FITS(TYPE) \ COMPILER_CHECK(sizeof(__hw_##TYPE) <= sizeof(TYPE)) -#if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__) +#if HWASAN_WITH_INTERCEPTORS CHECK_TYPE_SIZE_FITS(jmp_buf); CHECK_TYPE_SIZE_FITS(sigjmp_buf); #endif diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index 98bc756ae53..38b8c058246 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -56,7 +56,7 @@ // tramp: jmp QWORD [addr] // addr: .bytes // -// Note: is equilavent to