diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 1cf2dadd1d80..58b279efe04b 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2129,21 +2129,32 @@ object that overloads ``operator&``. ``__builtin_operator_new`` and ``__builtin_operator_delete`` ------------------------------------------------------------ -``__builtin_operator_new`` allocates memory just like a non-placement non-class -*new-expression*. This is exactly like directly calling the normal -non-placement ``::operator new``, except that it allows certain optimizations +A call to ``__builtin_operator_new(args)`` is exactly the same as a call to +``::operator new(args)``, except that it allows certain optimizations that the C++ standard does not permit for a direct function call to ``::operator new`` (in particular, removing ``new`` / ``delete`` pairs and -merging allocations). +merging allocations), and that the call is required to resolve to a +`replaceable global allocation function +`_. -Likewise, ``__builtin_operator_delete`` deallocates memory just like a -non-class *delete-expression*, and is exactly like directly calling the normal -``::operator delete``, except that it permits optimizations. Only the unsized -form of ``__builtin_operator_delete`` is currently available. +Likewise, ``__builtin_operator_delete`` is exactly the same as a call to +``::operator delete(args)``, except that it permits optimizations +and that the call is required to resolve to a +`replaceable global deallocation function +`_. These builtins are intended for use in the implementation of ``std::allocator`` and other similar allocation libraries, and are only available in C++. +Query for this feature with ``__has_builtin(__builtin_operator_new)`` or +``__has_builtin(__builtin_operator_delete)``: + + * If the value is at least ``201802L``, the builtins behave as described above. + + * If the value is non-zero, the builtins may not support calling arbitrary + replaceable global (de)allocation functions, but do support calling at least + ``::operator new(size_t)`` and ``::operator delete(void*)``. + ``__unique_stable_name`` ------------------------ diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index d74edb8a8adb..ca0f991c24e3 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -116,6 +116,7 @@ class ObjCPropertyDecl; class ObjCPropertyImplDecl; class ObjCProtocolDecl; class ObjCTypeParamDecl; +class OMPTraitInfo; struct ParsedTargetAttr; class Preprocessor; class Stmt; @@ -2962,6 +2963,14 @@ OPT_LIST(V) }; llvm::StringMap SectionInfos; + + /// Return a new OMPTraitInfo object owned by this context. + OMPTraitInfo &getNewOMPTraitInfo(); + +private: + /// All OMPTraitInfo objects live in this collection, one per + /// `pragma omp [begin] declare variant` directive. + SmallVector OMPTraitInfoVector; }; /// Utility function for constructing a nullary selector. diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index a781797c2d56..29c251ef7ee6 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -2703,6 +2703,12 @@ class OMPReductionClause final friend OMPVarListClause; friend TrailingObjects; + /// Reduction modifier. + OpenMPReductionClauseModifier Modifier = OMPC_REDUCTION_unknown; + + /// Reduction modifier location. + SourceLocation ModifierLoc; + /// Location of ':'. SourceLocation ColonLoc; @@ -2716,18 +2722,22 @@ class OMPReductionClause final /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. - /// \param EndLoc Ending location of the clause. + /// \param ModifierLoc Modifier location. /// \param ColonLoc Location of ':'. + /// \param EndLoc Ending location of the clause. /// \param N Number of the variables in the clause. /// \param QualifierLoc The nested-name qualifier with location information /// \param NameInfo The full name info for reduction identifier. OMPReductionClause(SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, unsigned N, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, + OpenMPReductionClauseModifier Modifier, unsigned N, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) : OMPVarListClause(OMPC_reduction, StartLoc, LParenLoc, EndLoc, N), - OMPClauseWithPostUpdate(this), ColonLoc(ColonLoc), + OMPClauseWithPostUpdate(this), Modifier(Modifier), + ModifierLoc(ModifierLoc), ColonLoc(ColonLoc), QualifierLoc(QualifierLoc), NameInfo(NameInfo) {} /// Build an empty clause. @@ -2739,6 +2749,12 @@ class OMPReductionClause final N), OMPClauseWithPostUpdate(this) {} + /// Sets reduction modifier. + void setModifier(OpenMPReductionClauseModifier M) { Modifier = M; } + + /// Sets location of the modifier. + void setModifierLoc(SourceLocation Loc) { ModifierLoc = Loc; } + /// Sets location of ':' symbol in clause. void setColonLoc(SourceLocation CL) { ColonLoc = CL; } @@ -2808,6 +2824,7 @@ class OMPReductionClause final /// /// \param StartLoc Starting location of the clause. /// \param LParenLoc Location of '('. + /// \param ModifierLoc Modifier location. /// \param ColonLoc Location of ':'. /// \param EndLoc Ending location of the clause. /// \param VL The variables in the clause. @@ -2838,8 +2855,9 @@ class OMPReductionClause final /// OpenMP region with this clause. static OMPReductionClause * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, ArrayRef VL, - NestedNameSpecifierLoc QualifierLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, OpenMPReductionClauseModifier Modifier, + ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, ArrayRef RHSExprs, ArrayRef ReductionOps, Stmt *PreInit, Expr *PostUpdate); @@ -2850,6 +2868,12 @@ class OMPReductionClause final /// \param N The number of variables. static OMPReductionClause *CreateEmpty(const ASTContext &C, unsigned N); + /// Returns modifier. + OpenMPReductionClauseModifier getModifier() const { return Modifier; } + + /// Returns modifier location. + SourceLocation getModifierLoc() const { return ModifierLoc; } + /// Gets location of ':' symbol in clause. SourceLocation getColonLoc() const { return ColonLoc; } @@ -6985,6 +7009,80 @@ class OMPInclusiveClause final } }; +/// This represents clause 'exclusive' in the '#pragma omp scan' directive. +/// +/// \code +/// #pragma omp scan exclusive(a,b) +/// \endcode +/// In this example directive '#pragma omp scan' has clause 'exclusive' +/// with the variables 'a' and 'b'. +class OMPExclusiveClause final + : public OMPVarListClause, + private llvm::TrailingObjects { + friend class OMPClauseReader; + friend OMPVarListClause; + friend TrailingObjects; + + /// Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + OMPExclusiveClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPVarListClause(OMPC_exclusive, StartLoc, + LParenLoc, EndLoc, N) {} + + /// Build an empty clause. + /// + /// \param N Number of variables. + explicit OMPExclusiveClause(unsigned N) + : OMPVarListClause(OMPC_exclusive, SourceLocation(), + SourceLocation(), SourceLocation(), + N) {} + +public: + /// Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the original variables. + static OMPExclusiveClause *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef VL); + + /// Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + static OMPExclusiveClause *CreateEmpty(const ASTContext &C, unsigned N); + + child_range children() { + return child_range(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + 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() == OMPC_exclusive; + } +}; + /// This class implements a simple visitor for OMPClause /// subclasses. template class Ptr, typename RetTy> @@ -7042,22 +7140,27 @@ class OMPClausePrinter final : public OMPClauseVisitor { /// collection of selector sets, each with an associated kind and an ordered /// collection of selectors. A selector has a kind, an optional score/condition, /// and an ordered collection of properties. -struct OMPTraitInfo { +class OMPTraitInfo { + /// Private constructor accesible only by ASTContext. + OMPTraitInfo() {} + friend class ASTContext; + +public: struct OMPTraitProperty { llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid; }; struct OMPTraitSelector { Expr *ScoreOrCondition = nullptr; llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid; - llvm::SmallVector Properties; + llvm::SmallVector Properties; }; struct OMPTraitSet { llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid; - llvm::SmallVector Selectors; + llvm::SmallVector Selectors; }; /// The outermost level of selector sets. - llvm::SmallVector Sets; + llvm::SmallVector Sets; bool anyScoreOrCondition( llvm::function_ref Cond) { @@ -7083,6 +7186,7 @@ struct OMPTraitInfo { void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; }; llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI); +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo *TI); } // namespace clang diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 94f68f555fdf..4bd489f4ba6d 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3190,6 +3190,13 @@ bool RecursiveASTVisitor::VisitOMPInclusiveClause( return true; } +template +bool RecursiveASTVisitor::VisitOMPExclusiveClause( + OMPExclusiveClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + template bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { TRY_TO(VisitOMPClauseList(C)); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index e04ed4252c4f..ddbc4a5d7e42 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -3763,7 +3763,7 @@ def OMPDeclareVariant : InheritableAttr { OMPTraitInfoArgument<"TraitInfos">, ]; let AdditionalMembers = [{ - OMPTraitInfo &getTraitInfo() { return traitInfos; } + OMPTraitInfo &getTraitInfo() { return *traitInfos; } void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy) const; }]; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 0a1d6668ec29..469af4167f8a 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -706,6 +706,8 @@ def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_unexpected_template_in_unqualified_id : Error< "'template' keyword not permitted here">; +def err_unexpected_template_in_destructor_name : Error< + "'template' keyword not permitted in destructor name">; def err_unexpected_template_after_using : Error< "'template' keyword not permitted after 'using' keyword">; def err_two_right_angle_brackets_need_space : Error< diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index 1e4b2b116a98..bfb41ab105ea 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -218,6 +218,9 @@ #ifndef OPENMP_SCAN_CLAUSE #define OPENMP_SCAN_CLAUSE(Name) #endif +#ifndef OPENMP_REDUCTION_MODIFIER +#define OPENMP_REDUCTION_MODIFIER(Name) +#endif // OpenMP clauses. OPENMP_CLAUSE(allocator, OMPAllocatorClause) @@ -285,9 +288,11 @@ OPENMP_CLAUSE(depobj, OMPDepobjClause) OPENMP_CLAUSE(destroy, OMPDestroyClause) OPENMP_CLAUSE(detach, OMPDetachClause) OPENMP_CLAUSE(inclusive, OMPInclusiveClause) +OPENMP_CLAUSE(exclusive, OMPExclusiveClause) // Clauses allowed for OpenMP directive 'scan'. OPENMP_SCAN_CLAUSE(inclusive) +OPENMP_SCAN_CLAUSE(exclusive) // Clauses allowed for OpenMP directive 'parallel'. OPENMP_PARALLEL_CLAUSE(if) @@ -1105,6 +1110,10 @@ OPENMP_DEPOBJ_CLAUSE(depend) OPENMP_DEPOBJ_CLAUSE(destroy) OPENMP_DEPOBJ_CLAUSE(update) +// Modifiers for 'reduction' clause. +OPENMP_REDUCTION_MODIFIER(default) + +#undef OPENMP_REDUCTION_MODIFIER #undef OPENMP_SCAN_CLAUSE #undef OPENMP_DEVICE_MODIFIER #undef OPENMP_DEPOBJ_CLAUSE diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h index 46eeffe999d9..b567f89b986e 100644 --- a/clang/include/clang/Basic/OpenMPKinds.h +++ b/clang/include/clang/Basic/OpenMPKinds.h @@ -168,6 +168,13 @@ struct OpenMPScheduleTy final { OpenMPScheduleClauseModifier M2 = OMPC_SCHEDULE_MODIFIER_unknown; }; +/// OpenMP modifiers for 'reduction' clause. +enum OpenMPReductionClauseModifier { +#define OPENMP_REDUCTION_MODIFIER(Name) OMPC_REDUCTION_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_REDUCTION_unknown, +}; + OpenMPClauseKind getOpenMPClauseKind(llvm::StringRef Str); const char *getOpenMPClauseName(OpenMPClauseKind Kind); diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ed5c100020e1..b6f65227ab2e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3086,7 +3086,7 @@ class Parser : public CodeCompletionHandler { SmallVector MapTypeModifiersLoc; bool IsMapTypeImplicit = false; - SourceLocation DepLinMapLastLoc; + SourceLocation ExtraModifierLoc; }; /// Parses clauses with list. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b7c58e0e73e8..000f72da8e42 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10675,12 +10675,17 @@ class Sema final { DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc); + SourceLocation ExtraModifierLoc); /// Called on well-formed 'inclusive' clause. OMPClause *ActOnOpenMPInclusiveClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// Called on well-formed 'exclusive' clause. + OMPClause *ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// Called on well-formed 'allocate' clause. OMPClause * ActOnOpenMPAllocateClause(Expr *Allocator, ArrayRef VarList, @@ -10708,9 +10713,10 @@ class Sema final { SourceLocation EndLoc); /// Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( - ArrayRef VarList, SourceLocation StartLoc, - SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// Called on well-formed 'task_reduction' clause. @@ -12481,8 +12487,8 @@ class Sema final { /// codegen'ed yet. bool checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); - /// Finishes analysis of the deferred functions calls that may be declared as - /// host during device compilation. + /// Finishes analysis of the deferred functions calls that may be not + /// properly declared for device compilation. void finalizeSYCLDelayedAnalysis(const FunctionDecl *Caller, const FunctionDecl *Callee, SourceLocation Loc); diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 7d4ef7c43a9d..5bdc9ca2ddbf 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -22,7 +22,7 @@ #include "llvm/ADT/APSInt.h" namespace clang { -struct OMPTraitInfo; +class OMPTraitInfo; /// An object for streaming information from a record. class ASTRecordReader @@ -260,7 +260,7 @@ class ASTRecordReader } /// Read an OMPTraitInfo object, advancing Idx. - OMPTraitInfo readOMPTraitInfo(); + OMPTraitInfo *readOMPTraitInfo(); /// Read an OpenMP clause, advancing Idx. OMPClause *readOMPClause(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index 924aa5d4b758..491207c9de90 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -267,7 +267,7 @@ class ASTRecordWriter void AddCXXDefinitionData(const CXXRecordDecl *D); /// Write an OMPTraitInfo object. - void writeOMPTraitInfo(const OMPTraitInfo &TI); + void writeOMPTraitInfo(const OMPTraitInfo *TI); void writeOMPClause(OMPClause *C); diff --git a/clang/include/clang/StaticAnalyzer/Core/Analyses.def b/clang/include/clang/StaticAnalyzer/Core/Analyses.def index 377451576148..c4e5f5be6fd7 100644 --- a/clang/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/clang/include/clang/StaticAnalyzer/Core/Analyses.def @@ -14,41 +14,80 @@ #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) #endif -ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) +ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", + CreateRegionStoreManager) #ifndef ANALYSIS_CONSTRAINTS #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) #endif -ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) -ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", CreateZ3ConstraintManager) +ANALYSIS_CONSTRAINTS(RangeConstraints, "range", + "Use constraint tracking of concrete value ranges", + CreateRangeConstraintManager) + +ANALYSIS_CONSTRAINTS(Z3Constraints, "z3", "Use Z3 contraint solver", + CreateZ3ConstraintManager) #ifndef ANALYSIS_DIAGNOSTICS #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) #endif -ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis results using HTML (not allowing for multi-file bugs)", createHTMLSingleFileDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", createSarifDiagnosticConsumer) -ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", + createHTMLDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS( + HTML_SINGLE_FILE, "html-single-file", + "Output analysis results using HTML (not allowing for multi-file bugs)", + createHTMLSingleFileDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", + createPlistDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS( + PLIST_MULTI_FILE, "plist-multi-file", + "Output analysis results using Plists (allowing for multi-file bugs)", + createPlistMultiFileDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", + "Output analysis results using HTML wrapped with Plists", + createPlistHTMLDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", + createSarifDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results to stderr", + createTextPathDiagnosticConsumer) + +ANALYSIS_DIAGNOSTICS(TEXT_MINIMAL, "text-minimal", + "Emits minimal diagnostics to stderr, stating only the " + "warning message and the associated notes. Usually " + "used in addition to other analysis types", + createTextMinimalPathDiagnosticConsumer) #ifndef ANALYSIS_PURGE #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) #endif -ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement") -ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block") -ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints") +ANALYSIS_PURGE( + PurgeStmt, "statement", + "Purge symbols, bindings, and constraints before every statement") + +ANALYSIS_PURGE( + PurgeBlock, "block", + "Purge symbols, bindings, and constraints before every basic block") + +ANALYSIS_PURGE(PurgeNone, "none", + "Do not purge symbols, bindings, or constraints") #ifndef ANALYSIS_INLINING_MODE #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) #endif -ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level") -ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined") +ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions as top level") + +ANALYSIS_INLINING_MODE( + NoRedundancy, "noredundancy", + "Do not analyze a function which has been previously inlined") #undef ANALYSIS_STORE #undef ANALYSIS_CONSTRAINTS @@ -56,4 +95,3 @@ ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function #undef ANALYSIS_PURGE #undef ANALYSIS_INLINING_MODE #undef ANALYSIS_IPA - diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index f85c37379158..935b2bb7b937 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -96,11 +96,7 @@ class ConstraintManager { // If StTrue is infeasible, asserting the falseness of Cond is unnecessary // because the existing constraints already establish this. if (!StTrue) { -#ifndef __OPTIMIZE__ - // This check is expensive and should be disabled even in Release+Asserts - // builds. - // FIXME: __OPTIMIZE__ is a GNU extension that Clang implements but MSVC - // does not. Is there a good equivalent there? +#ifdef EXPENSIVE_CHECKS assert(assume(State, Cond, false) && "System is over constrained."); #endif return ProgramStatePair((ProgramStateRef)nullptr, State); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b4c24bbf30ec..0d5d8cf888f2 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1010,6 +1010,9 @@ ASTContext::~ASTContext() { for (APValue *Value : APValueCleanups) Value->~APValue(); + + // Destroy the OMPTraitInfo objects that life here. + llvm::DeleteContainerPointers(OMPTraitInfoVector); } void ASTContext::setTraversalScope(const std::vector &TopLevelDecls) { @@ -10861,3 +10864,8 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->getTargetOpts().Features); } } + +OMPTraitInfo &ASTContext::getNewOMPTraitInfo() { + OMPTraitInfoVector.push_back(new OMPTraitInfo()); + return *OMPTraitInfoVector.back(); +} diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index 2c76f86713fb..a5ff68c18778 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -159,7 +159,7 @@ void OMPDeclareVariantAttr::printPrettyPragma( OS << ")"; } OS << " match("; - traitInfos.print(OS, Policy); + traitInfos->print(OS, Policy); OS << ")"; } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8fd67a0250..fc7912d6fdca 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -147,6 +147,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -235,6 +236,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } @@ -701,14 +703,16 @@ void OMPReductionClause::setReductionOps(ArrayRef ReductionOps) { OMPReductionClause *OMPReductionClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef VL, + SourceLocation ModifierLoc, SourceLocation EndLoc, SourceLocation ColonLoc, + OpenMPReductionClauseModifier Modifier, ArrayRef VL, NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, ArrayRef Privates, ArrayRef LHSExprs, ArrayRef RHSExprs, ArrayRef ReductionOps, Stmt *PreInit, Expr *PostUpdate) { void *Mem = C.Allocate(totalSizeToAlloc(5 * VL.size())); - OMPReductionClause *Clause = new (Mem) OMPReductionClause( - StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); + auto *Clause = new (Mem) + OMPReductionClause(StartLoc, LParenLoc, ModifierLoc, EndLoc, ColonLoc, + Modifier, VL.size(), QualifierLoc, NameInfo); Clause->setVarRefs(VL); Clause->setPrivates(Privates); Clause->setLHSExprs(LHSExprs); @@ -1268,6 +1272,24 @@ OMPInclusiveClause *OMPInclusiveClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPInclusiveClause(N); } +OMPExclusiveClause *OMPExclusiveClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(totalSizeToAlloc(VL.size())); + auto *Clause = + new (Mem) OMPExclusiveClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPExclusiveClause *OMPExclusiveClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc(N)); + return new (Mem) OMPExclusiveClause(N); +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// @@ -1575,6 +1597,9 @@ void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { if (!Node->varlist_empty()) { OS << "reduction("; + if (Node->getModifierLoc().isValid()) + OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier()) + << ", "; NestedNameSpecifier *QualifierLoc = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = @@ -1833,6 +1858,14 @@ void OMPClausePrinter::VisitOMPInclusiveClause(OMPInclusiveClause *Node) { } } +void OMPClausePrinter::VisitOMPExclusiveClause(OMPExclusiveClause *Node) { + if (!Node->varlist_empty()) { + OS << "exclusive"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + void OMPTraitInfo::getAsVariantMatchInfo( ASTContext &ASTCtx, llvm::omp::VariantMatchInfo &VMI) const { for (const OMPTraitSet &Set : Sets) { @@ -1936,3 +1969,7 @@ llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, TI.print(OS, Policy); return OS; } +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const OMPTraitInfo *TI) { + return TI ? OS << *TI : OS; +} diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a31a65fad35f..cd39024cd838 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -798,6 +798,9 @@ void OMPClauseProfiler::VisitOMPNontemporalClause( void OMPClauseProfiler::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} } // namespace diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index a905dff440d7..e8bf41dc07be 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -159,6 +159,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #define OPENMP_DEVICE_MODIFIER(Name) .Case(#Name, OMPC_DEVICE_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEVICE_unknown); + case OMPC_reduction: + return llvm::StringSwitch(Str) +#define OPENMP_REDUCTION_MODIFIER(Name) .Case(#Name, OMPC_REDUCTION_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_REDUCTION_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -172,7 +177,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: - case OMPC_reduction: case OMPC_task_reduction: case OMPC_in_reduction: case OMPC_aligned: @@ -213,6 +217,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -395,6 +400,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'device' clause modifier"); + case OMPC_reduction: + switch (Type) { + case OMPC_REDUCTION_unknown: + return "unknown"; +#define OPENMP_REDUCTION_MODIFIER(Name) \ + case OMPC_REDUCTION_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'reduction' clause modifier"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -408,7 +423,6 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_private: case OMPC_firstprivate: case OMPC_shared: - case OMPC_reduction: case OMPC_task_reduction: case OMPC_in_reduction: case OMPC_aligned: @@ -449,6 +463,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e33c77ee7435..b9327197c842 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13615,6 +13615,13 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_y, 0, 1024); case AMDGPU::BI__builtin_r600_read_tidig_z: return emitRangedBuiltin(*this, Intrinsic::r600_read_tidig_z, 0, 1024); + case AMDGPU::BI__builtin_amdgcn_alignbit: { + llvm::Value *Src0 = EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = EmitScalarExpr(E->getArg(1)); + llvm::Value *Src2 = EmitScalarExpr(E->getArg(2)); + Function *F = CGM.getIntrinsic(Intrinsic::fshr, Src0->getType()); + return Builder.CreateCall(F, { Src0, Src1, Src2 }); + } default: return nullptr; } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index b00027586767..58c5334776f3 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -11393,7 +11393,7 @@ static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, SmallVector VariantExprs; SmallVector VMIs; for (const auto *A : FD->specific_attrs()) { - const OMPTraitInfo &TI = A->getTraitInfos(); + const OMPTraitInfo &TI = *A->getTraitInfos(); VMIs.push_back(VariantMatchInfo()); TI.getAsVariantMatchInfo(CGM.getContext(), VMIs.back()); VariantExprs.push_back(A->getVariantFuncRef()); diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e05829f0a890..bef36bf4693b 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -4617,6 +4617,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 685749fc31ab..f2666a8bd171 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -3015,6 +3015,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(TT_CSharpNullConditionalLSquare)) return false; + // No space between consecutive commas '[,,]'. + if (Left.is(tok::comma) && Right.is(tok::comma)) + return false; + // Possible space inside `?[ 0 ]`. if (Left.is(TT_CSharpNullConditionalLSquare)) return Style.SpacesInSquareBrackets; diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index b8d91c19228f..a0b97ea7514d 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2884,6 +2884,22 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, // Parse the '~'. SourceLocation TildeLoc = ConsumeToken(); + if (TemplateSpecified) { + // C++ [temp.names]p3: + // A name prefixed by the keyword template shall be a template-id [...] + // + // A template-id cannot begin with a '~' token. This would never work + // anyway: x.~A() would specify that the destructor is a template, + // not that 'A' is a template. + // + // FIXME: Suggest replacing the attempted destructor name with a correct + // destructor name and recover. (This is not trivial if this would become + // a pseudo-destructor name). + Diag(*TemplateKWLoc, diag::err_unexpected_template_in_destructor_name) + << Tok.getLocation(); + return true; + } + if (SS.isEmpty() && Tok.is(tok::kw_decltype)) { DeclSpec DS(AttrFactory); SourceLocation EndLoc = ParseDecltypeSpecifier(DS); @@ -2903,7 +2919,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, ParsedType ObjectType, // If the user wrote ~T::T, correct it to T::~T. DeclaratorScopeObj DeclScopeObj(*this, SS); - if (!TemplateSpecified && NextToken().is(tok::coloncolon)) { + if (NextToken().is(tok::coloncolon)) { // Don't let ParseOptionalCXXScopeSpecifier() "correct" // `int A; struct { ~A::A(); };` to `int A; struct { ~A:A(); };`, // it will confuse this recovery logic. diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index bb239c833b82..7ae9885abe2b 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -754,7 +755,7 @@ static bool parseDeclareSimdClauses( "Unexpected linear modifier."); if (P.getActions().CheckOpenMPLinearModifier( static_cast(Data.ExtraModifier), - Data.DepLinMapLastLoc)) + Data.ExtraModifierLoc)) Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), Data.ExtraModifier); @@ -1365,7 +1366,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, } // Parse inner context selectors. - OMPTraitInfo TI; + OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo(); parseOMPContextSelectors(Loc, TI); // Parse ')' @@ -2344,7 +2345,8 @@ bool Parser::ParseOpenMPSimpleVarList( /// from-clause | is_device_ptr-clause | task_reduction-clause | /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | -/// depobj-clause | destroy-clause | detach-clause | inclusive-clause +/// depobj-clause | destroy-clause | detach-clause | inclusive-clause | +/// exclusive-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -2514,6 +2516,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_allocate: case OMPC_nontemporal: case OMPC_inclusive: + case OMPC_exclusive: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_device_type: @@ -3014,6 +3017,17 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // Handle reduction-identifier for reduction clause. if (Kind == OMPC_reduction || Kind == OMPC_task_reduction || Kind == OMPC_in_reduction) { + Data.ExtraModifier = OMPC_REDUCTION_unknown; + if (Kind == OMPC_reduction && getLangOpts().OpenMP >= 50 && + (Tok.is(tok::identifier) || Tok.is(tok::kw_default)) && + NextToken().is(tok::comma)) { + // Parse optional reduction modifier. + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.ExtraModifierLoc = Tok.getLocation(); + ConsumeToken(); + assert(Tok.is(tok::comma) && "Expected comma."); + (void)ConsumeToken(); + } ColonProtectionRAIIObject ColonRAII(*this); if (getLangOpts().CPlusPlus) ParseOptionalCXXScopeSpecifier(Data.ReductionOrMapperIdScopeSpec, @@ -3038,7 +3052,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, ColonProtectionRAIIObject ColonRAII(*this); Data.ExtraModifier = getOpenMPSimpleClauseType( Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""); - Data.DepLinMapLastLoc = Tok.getLocation(); + Data.ExtraModifierLoc = Tok.getLocation(); if (Data.ExtraModifier == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -3063,7 +3077,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ExtraModifier = OMPC_LINEAR_val; if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); - Data.DepLinMapLastLoc = ConsumeToken(); + Data.ExtraModifierLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } @@ -3076,13 +3090,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, !isOpenMPTaskLoopDirective(DKind)) && Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); - Data.DepLinMapLastLoc = Tok.getLocation(); - if (Data.ExtraModifier == OMPC_LASTPRIVATE_unknown) { - SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, - StopBeforeMatch); - } else { - ConsumeToken(); - } + Data.ExtraModifierLoc = Tok.getLocation(); + ConsumeToken(); assert(Tok.is(tok::colon) && "Expected colon."); Data.ColonLoc = ConsumeToken(); } @@ -3094,7 +3103,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // map-type-modifier. The map-type can also be delete which has the same // spelling of the C++ delete keyword. Data.ExtraModifier = OMPC_MAP_unknown; - Data.DepLinMapLastLoc = Tok.getLocation(); + Data.ExtraModifierLoc = Tok.getLocation(); // Check for presence of a colon in the map clause. TentativeParsingAction TPA(*this); @@ -3239,7 +3248,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// Parsing of OpenMP clause 'private', 'firstprivate', 'lastprivate', /// 'shared', 'copyin', 'copyprivate', 'flush', 'reduction', 'task_reduction', -/// 'in_reduction', 'nontemporal' or 'inclusive'. +/// 'in_reduction', 'nontemporal', 'exclusive' or 'inclusive'. /// /// private-clause: /// 'private' '(' list ')' @@ -3254,7 +3263,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// aligned-clause: /// 'aligned' '(' list [ ':' alignment ] ')' /// reduction-clause: -/// 'reduction' '(' reduction-identifier ':' list ')' +/// 'reduction' '(' [ modifier ',' ] reduction-identifier ':' list ')' /// task_reduction-clause: /// 'task_reduction' '(' reduction-identifier ':' list ')' /// in_reduction-clause: @@ -3283,6 +3292,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'nontemporal' '(' list ')' /// inclusive-clause: /// 'inclusive' '(' list ')' +/// exclusive-clause: +/// 'exclusive' '(' list ')' /// /// For 'linear' clause linear-list may have the following forms: /// list @@ -3306,6 +3317,6 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, - Data.IsMapTypeImplicit, Data.DepLinMapLastLoc); + Data.IsMapTypeImplicit, Data.ExtraModifierLoc); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 8c488da6cf0f..11cc43a16db1 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5100,6 +5100,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: continue; case OMPC_allocator: case OMPC_flush: @@ -5702,7 +5703,7 @@ void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, OMPTraitInfo &TI, SourceRange SR) { auto *NewAttr = - OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, TI, SR); + OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); FD->addAttr(NewAttr); } @@ -11084,6 +11085,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_order: case OMPC_destroy: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11820,6 +11822,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -12258,6 +12261,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12482,6 +12486,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_destroy: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12713,6 +12718,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_order: case OMPC_detach: case OMPC_inclusive: + case OMPC_exclusive: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12826,7 +12832,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef MapTypeModifiers, ArrayRef MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc) { + SourceLocation ExtraModifierLoc) { SourceLocation StartLoc = Locs.StartLoc; SourceLocation LParenLoc = Locs.LParenLoc; SourceLocation EndLoc = Locs.EndLoc; @@ -12843,15 +12849,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected lastprivate modifier."); Res = ActOnOpenMPLastprivateClause( VarList, static_cast(ExtraModifier), - DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); + ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_reduction: - Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionOrMapperIdScopeSpec, - ReductionOrMapperId); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown && + "Unexpected lastprivate modifier."); + Res = ActOnOpenMPReductionClause( + VarList, static_cast(ExtraModifier), + StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc, + ReductionOrMapperIdScopeSpec, ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, @@ -12868,7 +12877,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( VarList, TailExpr, StartLoc, LParenLoc, - static_cast(ExtraModifier), DepLinMapLastLoc, + static_cast(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: @@ -12888,7 +12897,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast(ExtraModifier), DepLinMapLastLoc, + static_cast(ExtraModifier), ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: @@ -12897,7 +12906,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPMapClause( MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec, ReductionOrMapperId, static_cast(ExtraModifier), - IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs); + IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs); break; case OMPC_to: Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, @@ -12923,6 +12932,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_inclusive: Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_exclusive: + Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_depobj: case OMPC_final: @@ -14694,10 +14706,19 @@ static bool actOnOMPReductionKindClause( } OMPClause *Sema::ActOnOpenMPReductionClause( - ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions) { + if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) { + Diag(LParenLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_reduction, /*First=*/0, + /*Last=*/OMPC_REDUCTION_unknown) + << getOpenMPClauseName(OMPC_reduction); + return nullptr; + } + ReductionData RD(VarList.size()); if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, @@ -14706,8 +14727,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return nullptr; return OMPReductionClause::Create( - Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier, + RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, buildPreInits(Context, RD.ExprCaptures), buildPostUpdate(*this, RD.ExprPostUpdates)); @@ -18008,3 +18029,31 @@ OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef VarList, return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 333d6d7576f4..d2ae78227feb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -399,7 +399,8 @@ static void instantiateOMPDeclareVariantAttr( // Copy the template version of the OMPTraitInfo and run substitute on all // score and condition expressiosn. - OMPTraitInfo TI = Attr.getTraitInfos(); + OMPTraitInfo &TI = S.getASTContext().getNewOMPTraitInfo(); + TI = *Attr.getTraitInfos(); // Try to substitute template parameters in score and condition expressions. auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) { diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index d23208bde60f..e49208a947ad 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -28,6 +28,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" @@ -1721,17 +1722,16 @@ class TreeTransform { /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPReductionClause(ArrayRef VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId, - ArrayRef UnresolvedReductions) { + OMPClause *RebuildOMPReductionClause( + ArrayRef VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef UnresolvedReductions) { return getSema().ActOnOpenMPReductionClause( - VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, - ReductionId, UnresolvedReductions); + VarList, Modifier, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'task_reduction' clause. @@ -2069,6 +2069,18 @@ class TreeTransform { EndLoc); } + /// Build a new OpenMP 'exclusive' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPExclusiveClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// Build a new OpenMP 'order' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -9078,8 +9090,9 @@ TreeTransform::TransformOMPReductionClause(OMPReductionClause *C) { UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPReductionClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), - C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); + Vars, C->getModifier(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getColonLoc(), C->getEndLoc(), + ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template @@ -9555,6 +9568,21 @@ TreeTransform::TransformOMPInclusiveClause(OMPInclusiveClause *C) { Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template +OMPClause * +TreeTransform::TransformOMPExclusiveClause(OMPExclusiveClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPExclusiveClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + template OMPClause * TreeTransform::TransformOMPOrderClause(OMPOrderClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ac111776fe76..c2d28f436241 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11845,6 +11845,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_inclusive: C = OMPInclusiveClause::CreateEmpty(Context, Record.readInt()); break; + case OMPC_exclusive: + C = OMPExclusiveClause::CreateEmpty(Context, Record.readInt()); + break; case OMPC_order: C = new (Context) OMPOrderClause(); break; @@ -12090,7 +12093,9 @@ void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); + C->setModifierLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); + C->setModifier(Record.readEnum()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); @@ -12665,14 +12670,24 @@ void OMPClauseReader::VisitOMPInclusiveClause(OMPInclusiveClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); +} + void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) { C->setKind(Record.readEnum()); C->setLParenLoc(Record.readSourceLocation()); C->setKindKwLoc(Record.readSourceLocation()); } -OMPTraitInfo ASTRecordReader::readOMPTraitInfo() { - OMPTraitInfo TI; +OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() { + OMPTraitInfo &TI = getContext().getNewOMPTraitInfo(); TI.Sets.resize(readUInt32()); for (auto &Set : TI.Sets) { Set.Kind = readEnum(); @@ -12687,5 +12702,5 @@ OMPTraitInfo ASTRecordReader::readOMPTraitInfo() { Property.Kind = readEnum(); } } - return TI; + return &TI; } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bb2ecb53c7ce..3bd7b825cdc8 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2744,7 +2744,7 @@ class AttrReader { return Reader.readVersionTuple(); } - OMPTraitInfo readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } + OMPTraitInfo *readOMPTraitInfo() { return Reader.readOMPTraitInfo(); } template T *GetLocalDeclAs(uint32_t LocalID) { return Reader.GetLocalDeclAs(LocalID); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a5d5b0f47144..ec75ff5965a0 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6242,7 +6242,9 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); + Record.AddSourceLocation(C->getModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); + Record.writeEnum(C->getModifier()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); for (auto *VE : C->varlists()) @@ -6611,15 +6613,22 @@ void OMPClauseWriter::VisitOMPInclusiveClause(OMPInclusiveClause *C) { Record.AddStmt(VE); } +void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); +} + void OMPClauseWriter::VisitOMPOrderClause(OMPOrderClause *C) { Record.writeEnum(C->getKind()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getKindKwLoc()); } -void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo &TI) { - writeUInt32(TI.Sets.size()); - for (const auto &Set : TI.Sets) { +void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) { + writeUInt32(TI->Sets.size()); + for (const auto &Set : TI->Sets) { writeEnum(Set.Kind); writeUInt32(Set.Selectors.size()); for (const auto &Selector : Set.Selectors) { diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp index bd8b84d464b6..f9b493bf9bb0 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp @@ -31,18 +31,30 @@ class IteratorRangeChecker std::unique_ptr OutOfRangeBugType; - void verifyDereference(CheckerContext &C, const SVal &Val) const; - void verifyIncrement(CheckerContext &C, const SVal &Iter) const; - void verifyDecrement(CheckerContext &C, const SVal &Iter) const; + void verifyDereference(CheckerContext &C, SVal Val) const; + void verifyIncrement(CheckerContext &C, SVal Iter) const; + void verifyDecrement(CheckerContext &C, SVal Iter) const; void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, - const SVal &LHS, const SVal &RHS) const; - void reportBug(const StringRef &Message, const SVal &Val, - CheckerContext &C, ExplodedNode *ErrNode) const; + SVal LHS, SVal RHS) const; + void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const; + void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const; + void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const; + void reportBug(const StringRef &Message, SVal Val, CheckerContext &C, + ExplodedNode *ErrNode) const; + public: IteratorRangeChecker(); void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + using AdvanceFn = void (IteratorRangeChecker::*)(CheckerContext &, SVal, + SVal) const; + + CallDescriptionMap AdvanceFunctions = { + {{{"std", "advance"}, 2}, &IteratorRangeChecker::verifyAdvance}, + {{{"std", "prev"}, 2}, &IteratorRangeChecker::verifyPrev}, + {{{"std", "next"}, 2}, &IteratorRangeChecker::verifyNext}, + }; }; bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); @@ -107,11 +119,23 @@ void IteratorRangeChecker::checkPreCall(const CallEvent &Call, verifyDereference(C, Call.getArgSVal(0)); } } + } else { + const AdvanceFn *Verifier = AdvanceFunctions.lookup(Call); + if (Verifier) { + if (Call.getNumArgs() > 1) { + (this->**Verifier)(C, Call.getArgSVal(0), Call.getArgSVal(1)); + } else { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + (this->**Verifier)( + C, Call.getArgSVal(0), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); + } + } } } void IteratorRangeChecker::verifyDereference(CheckerContext &C, - const SVal &Val) const { + SVal Val) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Val); if (Pos && isPastTheEnd(State, *Pos)) { @@ -123,24 +147,21 @@ void IteratorRangeChecker::verifyDereference(CheckerContext &C, } } -void IteratorRangeChecker::verifyIncrement(CheckerContext &C, - const SVal &Iter) const { +void IteratorRangeChecker::verifyIncrement(CheckerContext &C, SVal Iter) const { auto &BVF = C.getSValBuilder().getBasicValueFactory(); verifyRandomIncrOrDecr(C, OO_Plus, Iter, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); } -void IteratorRangeChecker::verifyDecrement(CheckerContext &C, - const SVal &Iter) const { +void IteratorRangeChecker::verifyDecrement(CheckerContext &C, SVal Iter) const { auto &BVF = C.getSValBuilder().getBasicValueFactory(); verifyRandomIncrOrDecr(C, OO_Minus, Iter, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); } void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, - OverloadedOperatorKind Op, - const SVal &LHS, - const SVal &RHS) const { + OverloadedOperatorKind Op, + SVal LHS, SVal RHS) const { auto State = C.getState(); auto Value = RHS; @@ -180,9 +201,24 @@ void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, } } -void IteratorRangeChecker::reportBug(const StringRef &Message, - const SVal &Val, CheckerContext &C, - ExplodedNode *ErrNode) const { +void IteratorRangeChecker::verifyAdvance(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_PlusEqual, LHS, RHS); +} + +void IteratorRangeChecker::verifyPrev(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_Minus, LHS, RHS); +} + +void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS, + SVal RHS) const { + verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS); +} + +void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val, + CheckerContext &C, + ExplodedNode *ErrNode) const { auto R = std::make_unique(*OutOfRangeBugType, Message, ErrNode); R->markInteresting(Val); diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt index 081d922ede80..dc2a6279b737 100644 --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -45,6 +45,7 @@ add_clang_library(clangStaticAnalyzerCore SValBuilder.cpp SVals.cpp SymbolManager.cpp + TextDiagnostics.cpp WorkList.cpp LINK_LIBS @@ -56,5 +57,6 @@ add_clang_library(clangStaticAnalyzerCore clangFrontend clangLex clangRewrite + clangToolingCore ) diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 002b6070ddcd..184fdcfb3d4b 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -66,11 +66,9 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { const bool SupportsCrossFileDiagnostics; public: - HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, - const std::string& prefix, - const Preprocessor &pp, - bool supportsMultipleFiles) - : Directory(prefix), PP(pp), AnalyzerOpts(AnalyzerOpts), + HTMLDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &OutputDir, + const Preprocessor &pp, bool supportsMultipleFiles) + : Directory(OutputDir), PP(pp), AnalyzerOpts(AnalyzerOpts), SupportsCrossFileDiagnostics(supportsMultipleFiles) {} ~HTMLDiagnostics() override { FlushDiagnostics(nullptr); } @@ -136,16 +134,45 @@ class HTMLDiagnostics : public PathDiagnosticConsumer { void ento::createHTMLDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, true)); + const std::string &OutputDir, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + + // FIXME: HTML is currently our default output type, but if the output + // directory isn't specified, it acts like if it was in the minimal text + // output mode. This doesn't make much sense, we should have the minimal text + // as our default. In the case of backward compatibility concerns, this could + // be preserved with -analyzer-config-compatibility-mode=true. + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); + + // TODO: Emit an error here. + if (OutputDir.empty()) + return; + + C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, true)); } void ento::createHTMLSingleFileDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &OutputDir, const Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + + // TODO: Emit an error here. + if (OutputDir.empty()) + return; + + C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, false)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); +} + +void ento::createPlistHTMLDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { - C.push_back(new HTMLDiagnostics(AnalyzerOpts, prefix, PP, false)); + const cross_tu::CrossTranslationUnitContext &CTU) { + createHTMLDiagnosticConsumer( + AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, + CTU); + createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index babd1401a5a7..9b6369aee7a8 100644 --- a/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -45,8 +45,8 @@ namespace { AnalyzerOptions &AnOpts; const bool SupportsCrossFileDiagnostics; public: - PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, const std::string &prefix, - const Preprocessor &PP, + PlistDiagnostics(AnalyzerOptions &AnalyzerOpts, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU, bool supportsMultipleFiles); @@ -582,19 +582,32 @@ PlistDiagnostics::PlistDiagnostics( void ento::createPlistDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &s, const Preprocessor &PP, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU, + + // TODO: Emit an error here. + if (OutputFile.empty()) + return; + + C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU, /*supportsMultipleFiles*/ false)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU); } void ento::createPlistMultiFileDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &s, const Preprocessor &PP, + const std::string &OutputFile, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - C.push_back(new PlistDiagnostics(AnalyzerOpts, s, PP, CTU, + + // TODO: Emit an error here. + if (OutputFile.empty()) + return; + + C.push_back(new PlistDiagnostics(AnalyzerOpts, OutputFile, PP, CTU, /*supportsMultipleFiles*/ true)); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputFile, PP, CTU); } + void PlistDiagnostics::FlushDiagnosticsImpl( std::vector &Diags, FilesMade *filesMade) { diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp index eed45aed620f..8c2e85601576 100644 --- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -50,8 +50,14 @@ class SarifDiagnostics : public PathDiagnosticConsumer { void ento::createSarifDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string &Output, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &) { + const cross_tu::CrossTranslationUnitContext &CTU) { + + // TODO: Emit an error here. + if (Output.empty()) + return; + C.push_back(new SarifDiagnostics(AnalyzerOpts, Output, PP.getLangOpts())); + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, Output, PP, CTU); } static StringRef getFileName(const FileEntry &FE) { diff --git a/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp new file mode 100644 index 000000000000..07e5685e604c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Core/TextDiagnostics.cpp @@ -0,0 +1,148 @@ +//===--- TextDiagnostics.cpp - Text Diagnostics for Paths -------*- 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 TextDiagnostics object. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathDiagnostic.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" +#include "clang/CrossTU/CrossTranslationUnit.h" +#include "clang/Frontend/ASTUnit.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Casting.h" + +using namespace clang; +using namespace ento; +using namespace tooling; + +namespace { +/// Emitsd minimal diagnostics (report message + notes) for the 'none' output +/// type to the standard error, or to to compliment many others. Emits detailed +/// diagnostics in textual format for the 'text' output type. +class TextDiagnostics : public PathDiagnosticConsumer { + DiagnosticsEngine &DiagEng; + LangOptions LO; + const bool IncludePath = false; + const bool ShouldEmitAsError = false; + const bool ApplyFixIts = false; + +public: + TextDiagnostics(DiagnosticsEngine &DiagEng, LangOptions LO, + bool ShouldIncludePath, const AnalyzerOptions &AnOpts) + : DiagEng(DiagEng), LO(LO), IncludePath(ShouldIncludePath), + ShouldEmitAsError(AnOpts.AnalyzerWerror), + ApplyFixIts(AnOpts.ShouldApplyFixIts) {} + ~TextDiagnostics() override {} + + StringRef getName() const override { return "TextDiagnostics"; } + + bool supportsLogicalOpControlFlow() const override { return true; } + bool supportsCrossFileDiagnostics() const override { return true; } + + PathGenerationScheme getGenerationScheme() const override { + return IncludePath ? Minimal : None; + } + + void FlushDiagnosticsImpl(std::vector &Diags, + FilesMade *filesMade) override { + unsigned WarnID = + ShouldEmitAsError + ? DiagEng.getCustomDiagID(DiagnosticsEngine::Error, "%0") + : DiagEng.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); + unsigned NoteID = DiagEng.getCustomDiagID(DiagnosticsEngine::Note, "%0"); + SourceManager &SM = DiagEng.getSourceManager(); + + Replacements Repls; + auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, + ArrayRef Ranges, + ArrayRef Fixits) { + if (!ApplyFixIts) { + DiagEng.Report(Loc, ID) << String << Ranges << Fixits; + return; + } + + DiagEng.Report(Loc, ID) << String << Ranges; + for (const FixItHint &Hint : Fixits) { + Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); + + if (llvm::Error Err = Repls.add(Repl)) { + llvm::errs() << "Error applying replacement " << Repl.toString() + << ": " << Err << "\n"; + } + } + }; + + for (std::vector::iterator I = Diags.begin(), + E = Diags.end(); + I != E; ++I) { + const PathDiagnostic *PD = *I; + reportPiece(WarnID, PD->getLocation().asLocation(), + PD->getShortDescription(), PD->path.back()->getRanges(), + PD->path.back()->getFixits()); + + // First, add extra notes, even if paths should not be included. + for (const auto &Piece : PD->path) { + if (!isa(Piece.get())) + continue; + + reportPiece(NoteID, Piece->getLocation().asLocation(), + Piece->getString(), Piece->getRanges(), Piece->getFixits()); + } + + if (!IncludePath) + continue; + + // Then, add the path notes if necessary. + PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); + for (const auto &Piece : FlatPath) { + if (isa(Piece.get())) + continue; + + reportPiece(NoteID, Piece->getLocation().asLocation(), + Piece->getString(), Piece->getRanges(), Piece->getFixits()); + } + } + + if (!ApplyFixIts || Repls.empty()) + return; + + Rewriter Rewrite(SM, LO); + if (!applyAllReplacements(Repls, Rewrite)) { + llvm::errs() << "An error occured during applying fix-it.\n"; + } + + Rewrite.overwriteChangedFiles(); + } +}; +} // end anonymous namespace + +void ento::createTextPathDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &Prefix, const clang::Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), + /*ShouldIncludePath*/ true, AnalyzerOpts)); +} + +void ento::createTextMinimalPathDiagnosticConsumer( + AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, + const std::string &Prefix, const clang::Preprocessor &PP, + const cross_tu::CrossTranslationUnitContext &CTU) { + C.emplace_back(new TextDiagnostics(PP.getDiagnostics(), PP.getLangOpts(), + /*ShouldIncludePath*/ false, + AnalyzerOpts)); +} diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index a908aede68bb..2e3aa0669061 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -34,8 +34,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" -#include "clang/Tooling/Core/Replacement.h" -#include "clang/Tooling/Tooling.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/FileSystem.h" @@ -49,7 +47,6 @@ using namespace clang; using namespace ento; -using namespace tooling; #define DEBUG_TYPE "AnalysisConsumer" @@ -64,126 +61,6 @@ STATISTIC(NumVisitedBlocksInAnalyzedFunctions, STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); -//===----------------------------------------------------------------------===// -// Special PathDiagnosticConsumers. -//===----------------------------------------------------------------------===// - -void ento::createPlistHTMLDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &prefix, const Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &CTU) { - createHTMLDiagnosticConsumer( - AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, - CTU); - createPlistMultiFileDiagnosticConsumer(AnalyzerOpts, C, prefix, PP, CTU); -} - -void ento::createTextPathDiagnosticConsumer( - AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &Prefix, const clang::Preprocessor &PP, - const cross_tu::CrossTranslationUnitContext &CTU) { - llvm_unreachable("'text' consumer should be enabled on ClangDiags"); -} - -namespace { -class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { - DiagnosticsEngine &Diag; - LangOptions LO; - - bool IncludePath = false; - bool ShouldEmitAsError = false; - bool ApplyFixIts = false; - -public: - ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag, LangOptions LO) - : Diag(Diag), LO(LO) {} - ~ClangDiagPathDiagConsumer() override {} - StringRef getName() const override { return "ClangDiags"; } - - bool supportsLogicalOpControlFlow() const override { return true; } - bool supportsCrossFileDiagnostics() const override { return true; } - - PathGenerationScheme getGenerationScheme() const override { - return IncludePath ? Minimal : None; - } - - void enablePaths() { IncludePath = true; } - void enableWerror() { ShouldEmitAsError = true; } - void enableApplyFixIts() { ApplyFixIts = true; } - - void FlushDiagnosticsImpl(std::vector &Diags, - FilesMade *filesMade) override { - unsigned WarnID = - ShouldEmitAsError - ? Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0") - : Diag.getCustomDiagID(DiagnosticsEngine::Warning, "%0"); - unsigned NoteID = Diag.getCustomDiagID(DiagnosticsEngine::Note, "%0"); - SourceManager &SM = Diag.getSourceManager(); - - Replacements Repls; - auto reportPiece = [&](unsigned ID, FullSourceLoc Loc, StringRef String, - ArrayRef Ranges, - ArrayRef Fixits) { - if (!ApplyFixIts) { - Diag.Report(Loc, ID) << String << Ranges << Fixits; - return; - } - - Diag.Report(Loc, ID) << String << Ranges; - for (const FixItHint &Hint : Fixits) { - Replacement Repl(SM, Hint.RemoveRange, Hint.CodeToInsert); - - if (llvm::Error Err = Repls.add(Repl)) { - llvm::errs() << "Error applying replacement " << Repl.toString() - << ": " << Err << "\n"; - } - } - }; - - for (std::vector::iterator I = Diags.begin(), - E = Diags.end(); - I != E; ++I) { - const PathDiagnostic *PD = *I; - reportPiece(WarnID, PD->getLocation().asLocation(), - PD->getShortDescription(), PD->path.back()->getRanges(), - PD->path.back()->getFixits()); - - // First, add extra notes, even if paths should not be included. - for (const auto &Piece : PD->path) { - if (!isa(Piece.get())) - continue; - - reportPiece(NoteID, Piece->getLocation().asLocation(), - Piece->getString(), Piece->getRanges(), Piece->getFixits()); - } - - if (!IncludePath) - continue; - - // Then, add the path notes if necessary. - PathPieces FlatPath = PD->path.flatten(/*ShouldFlattenMacros=*/true); - for (const auto &Piece : FlatPath) { - if (isa(Piece.get())) - continue; - - reportPiece(NoteID, Piece->getLocation().asLocation(), - Piece->getString(), Piece->getRanges(), Piece->getFixits()); - } - } - - if (!ApplyFixIts || Repls.empty()) - return; - - Rewriter Rewrite(SM, LO); - if (!applyAllReplacements(Repls, Rewrite)) { - llvm::errs() << "An error occured during applying fix-it.\n"; - } - - Rewrite.overwriteChangedFiles(); - } -}; -} // end anonymous namespace - //===----------------------------------------------------------------------===// // AnalysisConsumer declaration. //===----------------------------------------------------------------------===// @@ -269,31 +146,16 @@ class AnalysisConsumer : public AnalysisASTConsumer, } void DigestAnalyzerOptions() { - if (Opts->AnalysisDiagOpt != PD_NONE) { - // Create the PathDiagnosticConsumer. - ClangDiagPathDiagConsumer *clangDiags = - new ClangDiagPathDiagConsumer(PP.getDiagnostics(), PP.getLangOpts()); - PathConsumers.push_back(clangDiags); - - if (Opts->AnalyzerWerror) - clangDiags->enableWerror(); - - if (Opts->ShouldApplyFixIts) - clangDiags->enableApplyFixIts(); - - if (Opts->AnalysisDiagOpt == PD_TEXT) { - clangDiags->enablePaths(); - - } else if (!OutDir.empty()) { - switch (Opts->AnalysisDiagOpt) { - default: + switch (Opts->AnalysisDiagOpt) { + case PD_NONE: + break; #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \ case PD_##NAME: \ CREATEFN(*Opts.get(), PathConsumers, OutDir, PP, CTU); \ break; #include "clang/StaticAnalyzer/Core/Analyses.def" - } - } + default: + llvm_unreachable("Unkown analyzer output type!"); } // Create the analyzer component creators. @@ -329,20 +191,19 @@ class AnalysisConsumer : public AnalysisASTConsumer, else if (Mode == AM_Path) { llvm::errs() << " (Path, "; switch (IMode) { - case ExprEngine::Inline_Minimal: - llvm::errs() << " Inline_Minimal"; - break; - case ExprEngine::Inline_Regular: - llvm::errs() << " Inline_Regular"; - break; + case ExprEngine::Inline_Minimal: + llvm::errs() << " Inline_Minimal"; + break; + case ExprEngine::Inline_Regular: + llvm::errs() << " Inline_Regular"; + break; } llvm::errs() << ")"; - } - else + } else assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); - llvm::errs() << ": " << Loc.getFilename() << ' ' - << getFunctionName(D) << '\n'; + llvm::errs() << ": " << Loc.getFilename() << ' ' << getFunctionName(D) + << '\n'; } } @@ -485,7 +346,7 @@ class AnalysisConsumer : public AnalysisASTConsumer, /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set. void reportAnalyzerProgress(StringRef S); -}; +}; // namespace } // end anonymous namespace diff --git a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 6f1151ab0c11..5e7dd8f18cd7 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -21,6 +21,4 @@ add_clang_library(clangStaticAnalyzerFrontend clangLex clangStaticAnalyzerCheckers clangStaticAnalyzerCore - clangRewrite - clangToolingCore ) diff --git a/clang/test/Analysis/iterator-range.cpp b/clang/test/Analysis/iterator-range.cpp index 71af17a1f3d0..babcfdec99d6 100644 --- a/clang/test/Analysis/iterator-range.cpp +++ b/clang/test/Analysis/iterator-range.cpp @@ -359,6 +359,423 @@ void subscript_positive_end(const std::vector &V) { auto j = i[1]; // expected-warning{{Past-the-end iterator dereferenced}} FIXME: expect warning Iterator incremented behind the past-the-end iterator } +// +// std::advance() +// + +// std::advance() by +1 + +void advance_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 1); // no-warning +} + +void advance_plus_1_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::advance() by -1 + +void advance_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, -1); // no-warning +} + +void advance_minus_1_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, -1); // no-warning +} + +// std::advance() by +2 + +void advance_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 2); // no-warning +} + +void advance_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void advance_plus_2_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::advance() by -2 + +void advance_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void advance_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, -2); // no-warning +} + +void advance_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, -2); // no-warning +} + +void advance_minus_2_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, -2); // no-warning +} + +// std::advance() by 0 + +void advance_0_begin(const std::vector &V) { + auto i = V.begin(); + std::advance(i, 0); // no-warning +} + +void advance_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + std::advance(i, 0); // no-warning +} + +void advance_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + std::advance(i, 0); // no-warning +} + +void advance_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + std::advance(i, 0); // no-warning +} + +void advance_0_end(const std::vector &V) { + auto i = V.end(); + std::advance(i, 0); // no-warning +} + +// +// std::next() +// + +// std::next() by +1 (default) + +void next_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i); // no-warning +} + +void next_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i); // no-warning +} + +void next_plus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::next() by -1 + +void next_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, -1); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, -1); // no-warning +} + +void next_minus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, -1); // no-warning +} + +// std::next() by +2 + +void next_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, 2); // no-warning +} + +void next_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void next_plus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, 2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::next() by -2 + +void next_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, -2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void next_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, -2); // no-warning +} + +void next_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, -2); // no-warning +} + +void next_minus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, -2); // no-warning +} + +// std::next() by 0 + +void next_0_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::next(i, 0); // no-warning +} + +void next_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::next(i, 0); // no-warning +} + +void next_0_end(const std::vector &V) { + auto i = V.end(); + auto j = std::next(i, 0); // no-warning +} + +// +// std::prev() +// + +// std::prev() by +1 (default) + +void prev_plus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i); // no-warning +} + +void prev_plus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i); // no-warning +} + +// std::prev() by -1 + +void prev_minus_1_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, -1); // no-warning +} + +void prev_minus_1_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, -1); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::prev() by +2 + +void prev_plus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, 2); // expected-warning{{Iterator decremented ahead of its valid range}} +} + +void prev_plus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, 2); // no-warning +} + +void prev_plus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, 2); // no-warning +} + +void prev_plus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, 2); // no-warning +} + +// std::prev() by -2 + +void prev_minus_2_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, -2); // no-warning +} + +void prev_minus_2_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +void prev_minus_2_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, -2); // expected-warning{{Iterator incremented behind the past-the-end iterator}} +} + +// std::prev() by 0 + +void prev_0_begin(const std::vector &V) { + auto i = V.begin(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_behind_begin(const std::vector &V) { + auto i = ++V.begin(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_unknown(const std::vector &V) { + auto i = return_any_iterator(V.begin()); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_ahead_of_end(const std::vector &V) { + auto i = --V.end(); + auto j = std::prev(i, 0); // no-warning +} + +void prev_0_end(const std::vector &V) { + auto i = V.end(); + auto j = std::prev(i, 0); // no-warning +} + // // Structure member dereference operators // diff --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp index 35fd15f0cc64..2c762237037d 100644 --- a/clang/test/CXX/drs/dr4xx.cpp +++ b/clang/test/CXX/drs/dr4xx.cpp @@ -297,13 +297,11 @@ namespace dr420 { // dr420: yes void test2(T p) { p->template Y::~Y(); p->~Y(); - // FIXME: This is ill-formed, but this diagnostic is terrible. We should - // reject this in the parser. - p->template ~Y(); // expected-error 2{{no member named '~typename Y'}} + p->template ~Y(); // expected-error {{'template' keyword not permitted in destructor name}} } template struct Y {}; - template void test2(Y*); // expected-note {{instantiation}} - template void test2(ptr >); // expected-note {{instantiation}} + template void test2(Y*); + template void test2(ptr >); void test3(int *p, ptr q) { typedef int Int; diff --git a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl index 85e921cbe12a..0aa3e4144c52 100644 --- a/clang/test/CodeGenOpenCL/builtins-amdgcn.cl +++ b/clang/test/CodeGenOpenCL/builtins-amdgcn.cl @@ -596,7 +596,7 @@ kernel void test_mbcnt_hi(global uint* out, uint src0, uint src1) { } // CHECK-LABEL: @test_alignbit( -// CHECK: tail call i32 @llvm.amdgcn.alignbit(i32 %src0, i32 %src1, i32 %src2) +// CHECK: tail call i32 @llvm.fshr.i32(i32 %src0, i32 %src1, i32 %src2) kernel void test_alignbit(global uint* out, uint src0, uint src1, uint src2) { *out = __builtin_amdgcn_alignbit(src0, src1, src2); } diff --git a/clang/test/Driver/hip-device-compile.hip b/clang/test/Driver/hip-device-compile.hip index b6f1f1cf218e..c442d23581ce 100644 --- a/clang/test/Driver/hip-device-compile.hip +++ b/clang/test/Driver/hip-device-compile.hip @@ -42,7 +42,7 @@ // CHECK-NOT: {{"*.llvm-link"}} // CHECK-NOT: {{".*opt"}} // CHECK-NOT: {{".*llc"}} -// CHECK-NOT: {{".*lld"}} +// CHECK-NOT: {{".*lld.*"}} // CHECK-NOT: {{".*clang-offload-bundler"}} // CHECK-NOT: {{".*ld.*"}} @@ -67,6 +67,6 @@ // BUNDLE: {{"*.llvm-link"}} // BUNDLE: {{".*opt"}} // BUNDLE: {{".*llc"}} -// BUNDLE: {{".*lld"}} +// BUNDLE: {{".*lld.*"}} // BUNDLE: {{".*clang-offload-bundler"}} diff --git a/clang/test/Driver/hip-toolchain-no-rdc.hip b/clang/test/Driver/hip-toolchain-no-rdc.hip index cda852e2d8c7..4371334577f7 100644 --- a/clang/test/Driver/hip-toolchain-no-rdc.hip +++ b/clang/test/Driver/hip-toolchain-no-rdc.hip @@ -38,7 +38,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_A_803:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_A_803:.*out]]" [[OBJ_DEV_A_803]] // @@ -67,7 +67,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_A_900:".*-gfx900-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_A_900:.*out]]" [[OBJ_DEV_A_900]] // @@ -112,7 +112,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_B_803:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_B_803:.*out]]" [[OBJ_DEV_B_803]] // @@ -141,7 +141,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV_B_900:".*-gfx900-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV_B_900:.*out]]" [[OBJ_DEV_B_900]] // diff --git a/clang/test/Driver/hip-toolchain-rdc.hip b/clang/test/Driver/hip-toolchain-rdc.hip index 18fd1d7b09a0..203784f2ab43 100644 --- a/clang/test/Driver/hip-toolchain-rdc.hip +++ b/clang/test/Driver/hip-toolchain-rdc.hip @@ -44,7 +44,7 @@ // CHECK-SAME: "-filetype=obj" // CHECK-SAME: "-o" [[OBJ_DEV1:".*-gfx803-.*o"]] -// CHECK: [[LLD: ".*lld"]] "-flavor" "gnu" "-shared" +// CHECK: [[LLD: ".*lld.*"]] "-flavor" "gnu" "-shared" // CHECK-SAME: "-o" "[[IMG_DEV1:.*out]]" [[OBJ_DEV1]] // CHECK: [[CLANG]] "-cc1" "-triple" "amdgcn-amd-amdhsa" diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp index fa96dfce67ff..7ba40d8dc1cc 100644 --- a/clang/test/OpenMP/parallel_ast_print.cpp +++ b/clang/test/OpenMP/parallel_ast_print.cpp @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=45 -ast-print %s | FileCheck %s -// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=45 -ast-print %s | FileCheck %s -// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -x c++ -std=c++11 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=45 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s // expected-no-diagnostics #ifndef HEADER @@ -89,7 +89,7 @@ class S8 : public S7 { #pragma omp parallel shared(a) shared(this->a) shared(S7 < S1 > ::a) for (int k = 0; k < a.a; ++k) ++this->a.a; -#pragma omp parallel reduction(^ : S7 < S1 > ::a) reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a]) +#pragma omp parallel reduction(default, ^ : S7 < S1 > ::a) reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a]) for (int k = 0; k < a.a; ++k) ++this->a.a; } @@ -113,7 +113,7 @@ class S8 : public S7 { // CHECK: #pragma omp parallel private(this->a) private(this->a) private(this->S7::a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) firstprivate(this->S7::a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) shared(this->S7::a) -// CHECK: #pragma omp parallel reduction(^: this->S7::a) reduction(+: this->S7::b[:this->S7::a.a]) +// CHECK: #pragma omp parallel reduction(default, ^: this->S7::a) reduction(+: this->S7::b[:this->S7::a.a]) // CHECK: #pragma omp parallel private(this->a) private(this->a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) @@ -152,7 +152,7 @@ T tmain(T argc, T *argv) { a=2; #pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) if (parallel:argc > 0) num_threads(C) copyin(S::TS, thrp) proc_bind(master) reduction(+:c, arr1[argc]) reduction(max:e, arr[:C][0:10]) foo(); -#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(&& : g) +#pragma omp parallel if (C) num_threads(s) proc_bind(close) reduction(^:e, f, arr[0:C][:argc]) reduction(default, && : g) foo(); return 0; } @@ -166,7 +166,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(C) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:C][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(C) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:C][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() // CHECK: template<> int tmain(int argc, int *argv) { // CHECK-NEXT: int b = argc, c, d, e, f, g; @@ -177,7 +177,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(5) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:5][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(5) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:5][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() // CHECK: template<> long tmain(long argc, long *argv) { // CHECK-NEXT: long b = argc, c, d, e, f, g; @@ -188,7 +188,7 @@ T tmain(T argc, T *argv) { // CHECK-NEXT: a = 2; // CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) if(parallel: argc > 0) num_threads(1) copyin(S::TS,thrp) proc_bind(master) reduction(+: c,arr1[argc]) reduction(max: e,arr[:1][0:10]) // CHECK-NEXT: foo() -// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(&&: g) +// CHECK-NEXT: #pragma omp parallel if(1) num_threads(s) proc_bind(close) reduction(^: e,f,arr[0:1][:argc]) reduction(default, &&: g) // CHECK-NEXT: foo() enum Enum { }; diff --git a/clang/test/OpenMP/parallel_reduction_codegen.cpp b/clang/test/OpenMP/parallel_reduction_codegen.cpp index 60bf35803076..eeea0384ac04 100644 --- a/clang/test/OpenMP/parallel_reduction_codegen.cpp +++ b/clang/test/OpenMP/parallel_reduction_codegen.cpp @@ -1,14 +1,14 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s -// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s -// RUN: %clang_cc1 -verify -fopenmp -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s - -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s -// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=LAMBDA %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck -check-prefix=BLOCKS %s + +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -triple x86_64-apple-darwin10 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp-simd -fopenmp-version=50 -x c++ -triple x86_64-apple-darwin10 -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -std=c++11 -DLAMBDA -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 -x c++ -fblocks -DBLOCKS -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck --check-prefix SIMD-ONLY0 %s // SIMD-ONLY0-NOT: {{__kmpc|__tgt}} // expected-no-diagnostics #ifndef HEADER @@ -31,7 +31,7 @@ struct SS { int b : 4; int &c; SS(int &d) : a(0), b(0), c(d) { -#pragma omp parallel reduction(+: a, b, c) +#pragma omp parallel reduction(default, +: a, b, c) #ifdef LAMBDA [&]() { ++this->a, --b, (this)->c /= 1; @@ -91,7 +91,7 @@ struct SST { //CHECK: call void {{.+}}@__kmpc_fork_call( //CHECK: ret void void foo_array_sect(short x[1]) { -#pragma omp parallel reduction(+ : x[:]) +#pragma omp parallel reduction(default, + : x[:]) {} } diff --git a/clang/test/OpenMP/parallel_reduction_messages.c b/clang/test/OpenMP/parallel_reduction_messages.c index f88f8e056495..61a3e9300436 100644 --- a/clang/test/OpenMP/parallel_reduction_messages.c +++ b/clang/test/OpenMP/parallel_reduction_messages.c @@ -1,8 +1,19 @@ -// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -ferror-limit 150 -o - %s int incomplete[]; void test() { + int a; +#pragma omp parallel reduction( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(unknown // expected-error {{expected expression}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(default, // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-note {{to match this '('}} + ; +#pragma omp parallel reduction(unknown, +: a) // expected-error {{expected 'default' in OpenMP clause 'reduction'}} + ; +#pragma omp parallel reduction(default, + : a) + ; #pragma omp parallel reduction(+ : incomplete) // expected-error {{a reduction list item with incomplete type 'int []'}} ; } diff --git a/clang/test/OpenMP/scan_ast_print.cpp b/clang/test/OpenMP/scan_ast_print.cpp index efcaa2da138a..4b9eca6f7ec9 100644 --- a/clang/test/OpenMP/scan_ast_print.cpp +++ b/clang/test/OpenMP/scan_ast_print.cpp @@ -39,11 +39,11 @@ int main(int argc, char **argv) { // CHECK: static int a; #pragma omp for simd for (int i = 0; i < 10; ++i) { -#pragma omp scan inclusive(a) +#pragma omp scan exclusive(a, argc) } // CHECK-NEXT: #pragma omp for simd // CHECK-NEXT: for (int i = 0; i < 10; ++i) { -// CHECK-NEXT: #pragma omp scan inclusive(a){{$}} +// CHECK-NEXT: #pragma omp scan exclusive(a,argc){{$}} return tmain(argc) + tmain(argv[0][0]) + a; } diff --git a/clang/test/OpenMP/scan_messages.cpp b/clang/test/OpenMP/scan_messages.cpp index 3be998d0f96e..9f093858c249 100644 --- a/clang/test/OpenMP/scan_messages.cpp +++ b/clang/test/OpenMP/scan_messages.cpp @@ -54,25 +54,25 @@ T tmain(T argc) { #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) { -#pragma omp scan inclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} +#pragma omp scan exclusive(argc) // expected-note 2 {{previous 'scan' directive used here}} case 1: -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} break; default: { -#pragma omp scan inclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} +#pragma omp scan exclusive(argc) // expected-error {{exactly one 'scan' directive must appear in the loop body of an enclosing directive}} } break; } #pragma omp simd for (int i = 0; i < 10; ++i) for (;;) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} for (;;) { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { label: -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) { @@ -91,6 +91,16 @@ int main(int argc, char **argv) { } #pragma omp simd for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) inclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { +#pragma omp scan exclusive(argc) exclusive(argc) // expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} + ; + } +#pragma omp simd + for (int i = 0; i < 10; ++i) { #pragma omp scan untied // expected-error {{unexpected OpenMP clause 'untied' in directive '#pragma omp scan'}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} #pragma omp scan unknown // expected-warning {{extra tokens at the end of '#pragma omp scan' are ignored}} expected-error {{exactly one of 'inclusive' or 'exclusive' clauses is expected}} } @@ -117,18 +127,18 @@ int main(int argc, char **argv) { #pragma omp simd for (int i = 0; i < 10; ++i) do { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } while (argc); #pragma omp simd for (int i = 0; i < 10; ++i) switch (argc) -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: -#pragma omp scan inclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} +#pragma omp scan exclusive(argc) // expected-error {{'#pragma omp scan' cannot be an immediate substatement}} switch (argc) case 1: { -#pragma omp scan inclusive(argc) +#pragma omp scan exclusive(argc) } #pragma omp simd for (int i = 0; i < 10; ++i) diff --git a/clang/test/SemaCXX/pseudo-destructors.cpp b/clang/test/SemaCXX/pseudo-destructors.cpp index 0cd139047432..b71b523de683 100644 --- a/clang/test/SemaCXX/pseudo-destructors.cpp +++ b/clang/test/SemaCXX/pseudo-destructors.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -emit-llvm-only -verify -std=c++11 %s struct A {}; enum Foo { F }; @@ -92,6 +92,9 @@ namespace PR11339 { template using Id = T; void AliasTemplate(int *p) { p->~Id(); + p->template ~Id(); // expected-error {{'template' keyword not permitted in destructor name}} + (0).~Id(); + (0).template ~Id(); // expected-error {{'template' keyword not permitted in destructor name}} } namespace dotPointerAccess { diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt index cc5712726169..8d4a6a597a20 100644 --- a/clang/tools/driver/CMakeLists.txt +++ b/clang/tools/driver/CMakeLists.txt @@ -58,7 +58,7 @@ endif() # Support plugins. if(CLANG_PLUGIN_SUPPORT) - export_executable_symbols(clang) + export_executable_symbols_for_plugins(clang) endif() add_dependencies(clang clang-resource-headers) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 31a0f364a348..ae7fd4271799 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2312,6 +2312,9 @@ void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { void OMPClauseEnqueue::VisitOMPInclusiveClause(const OMPInclusiveClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPExclusiveClause(const OMPExclusiveClause *C) { + VisitOMPClauseList(C); +} void OMPClauseEnqueue::VisitOMPAllocateClause(const OMPAllocateClause *C) { VisitOMPClauseList(C); Visitor->AddStmt(C->getAllocator()); diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp index 0b770b4dfd3c..17b8e070c36a 100644 --- a/clang/unittests/Format/FormatTestCSharp.cpp +++ b/clang/unittests/Format/FormatTestCSharp.cpp @@ -640,9 +640,12 @@ TEST_F(FormatTestCSharp, CSharpSpaces) { verifyFormat(R"(private float[,] Values;)", Style); verifyFormat(R"(Result this[Index x] => Foo(x);)", Style); + verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style); + Style.SpacesInSquareBrackets = true; verifyFormat(R"(private float[ , ] Values;)", Style); verifyFormat(R"(string dirPath = args?[ 0 ];)", Style); + verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style); } TEST_F(FormatTestCSharp, CSharpNullableTypes) { diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 8692517fe214..da29a1c74428 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -107,7 +107,7 @@ static std::string ReadPCHRecord(StringRef type) { .Case("IdentifierInfo *", "Record.readIdentifier()") .Case("StringRef", "Record.readString()") .Case("ParamIdx", "ParamIdx::deserialize(Record.readInt())") - .Case("OMPTraitInfo", "Record.readOMPTraitInfo()") + .Case("OMPTraitInfo *", "Record.readOMPTraitInfo()") .Default("Record.readInt()"); } @@ -131,7 +131,7 @@ static std::string WritePCHRecord(StringRef type, StringRef name) { .Case("StringRef", "AddString(" + std::string(name) + ");\n") .Case("ParamIdx", "push_back(" + std::string(name) + ".serialize());\n") - .Case("OMPTraitInfo", + .Case("OMPTraitInfo *", "writeOMPTraitInfo(" + std::string(name) + ");\n") .Default("push_back(" + std::string(name) + ");\n"); } @@ -363,7 +363,7 @@ namespace { OS << " if (SA->get" << getUpperName() << "().isValid())\n "; OS << " OS << \" \" << SA->get" << getUpperName() << "().getSourceIndex();\n"; - } else if (type == "OMPTraitInfo") { + } else if (type == "OMPTraitInfo *") { OS << " OS << \" \" << SA->get" << getUpperName() << "();\n"; } else { llvm_unreachable("Unknown SimpleArgument type!"); @@ -1334,7 +1334,7 @@ createArgument(const Record &Arg, StringRef Attr, else if (ArgName == "VersionArgument") Ptr = std::make_unique(Arg, Attr); else if (ArgName == "OMPTraitInfoArgument") - Ptr = std::make_unique(Arg, Attr, "OMPTraitInfo"); + Ptr = std::make_unique(Arg, Attr, "OMPTraitInfo *"); if (!Ptr) { // Search in reverse order so that the most-derived type is handled first. diff --git a/compiler-rt/lib/msan/msan_interceptors.cpp b/compiler-rt/lib/msan/msan_interceptors.cpp index 4cdce7e29af1..9b1340b0104e 100644 --- a/compiler-rt/lib/msan/msan_interceptors.cpp +++ b/compiler-rt/lib/msan/msan_interceptors.cpp @@ -824,30 +824,6 @@ INTERCEPTOR(int, prlimit64, int pid, int resource, void *new_rlimit, #define MSAN_MAYBE_INTERCEPT_PRLIMIT64 #endif -#if SANITIZER_FREEBSD -// FreeBSD's define uname() as -// static __inline int uname(struct utsname *name) { -// return __xuname(SYS_NMLN, (void*)name); -// } -INTERCEPTOR(int, __xuname, int size, void *utsname) { - ENSURE_MSAN_INITED(); - int res = REAL(__xuname)(size, utsname); - if (!res) - __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); - return res; -} -#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(__xuname) -#else -INTERCEPTOR(int, uname, struct utsname *utsname) { - ENSURE_MSAN_INITED(); - int res = REAL(uname)(utsname); - if (!res) - __msan_unpoison(utsname, __sanitizer::struct_utsname_sz); - return res; -} -#define MSAN_INTERCEPT_UNAME INTERCEPT_FUNCTION(uname) -#endif - INTERCEPTOR(int, gethostname, char *name, SIZE_T len) { ENSURE_MSAN_INITED(); int res = REAL(gethostname)(name, len); @@ -1705,7 +1681,6 @@ void InitializeInterceptors() { MSAN_MAYBE_INTERCEPT_GETRLIMIT64; MSAN_MAYBE_INTERCEPT_PRLIMIT; MSAN_MAYBE_INTERCEPT_PRLIMIT64; - MSAN_INTERCEPT_UNAME; INTERCEPT_FUNCTION(gethostname); MSAN_MAYBE_INTERCEPT_EPOLL_WAIT; MSAN_MAYBE_INTERCEPT_EPOLL_PWAIT; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc index 6daed4a6736c..1671273174de 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -9735,9 +9735,6 @@ INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); - if (ss != nullptr) { - COMMON_INTERCEPTOR_READ_RANGE(ctx, ss, struct_stack_t_sz); - } int r = REAL(sigaltstack)(ss, oss); if (r == 0 && oss != nullptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); @@ -9749,6 +9746,40 @@ INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { #define INIT_SIGALTSTACK #endif +#if SANITIZER_INTERCEPT_UNAME +INTERCEPTOR(int, uname, struct utsname *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); + int res = REAL(uname)(utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) +#else +#define INIT_UNAME +#endif + +#if SANITIZER_INTERCEPT___XUNAME +// FreeBSD's define uname() as +// static __inline int uname(struct utsname *name) { +// return __xuname(SYS_NMLN, (void*)name); +// } +INTERCEPTOR(int, __xuname, int size, void *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); + int res = REAL(__xuname)(size, utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) +#else +#define INIT___XUNAME +#endif + #include "sanitizer_common_interceptors_netbsd_compat.inc" static void InitializeCommonInterceptors() { @@ -10055,6 +10086,8 @@ static void InitializeCommonInterceptors() { INIT_QSORT; INIT_QSORT_R; INIT_SIGALTSTACK; + INIT_UNAME; + INIT___XUNAME; INIT___PRINTF_CHK; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp index 9e3b4f13a436..16b4c9b633d8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_s390.cpp @@ -15,14 +15,15 @@ #if SANITIZER_LINUX && SANITIZER_S390 -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" - +#include #include #include #include #include +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + namespace __sanitizer { // --------------- sanitizer_libc.h @@ -122,8 +123,12 @@ static bool FixedCVE_2016_2143() { // adjust this for their own kernels. struct utsname buf; unsigned int major, minor, patch = 0; + // Depending on the concrete sanitizer being used, uname may or may not + // be intercepted. Make sure we use the libc version in either case. + using Uname = int (*)(struct utsname *); + Uname uname = reinterpret_cast(dlsym(RTLD_NEXT, "uname")); // This should never fail, but just in case... - if (uname(&buf)) + if (uname == nullptr || uname(&buf)) return false; const char *ptr = buf.release; major = internal_simple_strtoll(ptr, &ptr, 10); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 8d08c0de1770..9dd6d285f594 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -597,5 +597,7 @@ (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) #define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) #define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/compiler-rt/test/msan/sigaltstack.cpp b/compiler-rt/test/msan/sigaltstack.cpp index 4b97bb461d47..c1b8b7eefee1 100644 --- a/compiler-rt/test/msan/sigaltstack.cpp +++ b/compiler-rt/test/msan/sigaltstack.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx_msan -O0 -g %s -o %t && not %run %t +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t // #include #include @@ -11,10 +11,5 @@ int main(void) { assert(sigaltstack(nullptr, &old_ss) == 0); __msan_check_mem_is_initialized(&old_ss, sizeof(stack_t)); - stack_t ss; - sigaltstack(&ss, nullptr); -// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -// CHECK: in main {{.*}}sigaltstack.cpp:15 - return 0; } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c b/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c new file mode 100644 index 000000000000..0bf7e0fd98e3 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/Posix/uname.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t + +#include +#include +#include + +int main() { + struct utsname buf; + int err = uname(&buf); + assert(err == 0); + printf("%s %s %s %s %s\n", buf.sysname, buf.nodename, buf.release, + buf.version, buf.machine); +} diff --git a/libcxx/docs/index.rst b/libcxx/docs/index.rst index 7abdb10cb77d..f763f3aa0f60 100644 --- a/libcxx/docs/index.rst +++ b/libcxx/docs/index.rst @@ -100,7 +100,7 @@ Linux i386, x86_64 Clang, GCC libc++abi The following minimum compiler versions are strongly recommended. -* Clang 3.5 and above +* Clang 4.0 and above * GCC 5.0 and above. The C++03 dialect is only supported for Clang compilers. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp index e303c820847f..edd4e52fe3be 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t.pass.cpp @@ -11,9 +11,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME change this to XFAIL. -// UNSUPPORTED: no-aligned-allocation && !gcc - // Aligned allocation was not provided before macosx10.14 and as a result we // get availability errors when the deployment target is older than macosx10.14. // However, AppleClang 10 (and older) don't trigger availability errors, and diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp index ed7a53743f0e..91e3a1bf0654 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow.pass.cpp @@ -11,9 +11,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // Aligned allocation was not provided before macosx10.14 and as a result we // get availability errors when the deployment target is older than macosx10.14. // However, AppleClang 10 (and older) don't trigger availability errors, and diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp index 49aa2bce3ea2..5aa47a5bc236 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp @@ -31,8 +31,6 @@ // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.8 // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.7 -// XFAIL: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp index cb9a2ef7f6ca..3cc153ecb2a2 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_replace.pass.cpp @@ -9,9 +9,6 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // UNSUPPORTED: sanitizer-new-delete -// NOTE: GCC doesn't provide the -faligned-allocation flag to test for -// XFAIL: no-aligned-allocation && !gcc - // test operator new replacement #include diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp index 0d96db5de485..f0da4d674615 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t.pass.cpp @@ -33,9 +33,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails to compile/link. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp index 4b621f78a726..7edb003c2581 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow.pass.cpp @@ -33,9 +33,6 @@ // asan and msan will not call the new handler. // UNSUPPORTED: sanitizer-new-delete -// FIXME turn this into an XFAIL -// UNSUPPORTED: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails to compile/link. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp index 892eac205826..95931b715d9d 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp @@ -31,9 +31,6 @@ // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.8 // XFAIL: (apple-clang-9 || apple-clang-10) && with_system_cxx_lib=macosx10.7 -// NOTE: gcc doesn't provide -faligned-allocation flag to test for -// XFAIL: no-aligned-allocation && !gcc - // On Windows libc++ doesn't provide its own definitions for new/delete // but instead depends on the ones in VCRuntime. However VCRuntime does not // yet provide aligned new/delete definitions so this test fails. diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp index 32c27d5899ec..3a17266d1756 100644 --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_replace.pass.cpp @@ -9,9 +9,6 @@ // UNSUPPORTED: c++98, c++03, c++11, c++14 // UNSUPPORTED: sanitizer-new-delete -// NOTE: GCC doesn't provide a -faligned-allocation flag -// XFAIL: no-aligned-allocation && !gcc - // test operator new replacement #include diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py index cc7691402f2a..a9a353916a9c 100644 --- a/libcxx/utils/libcxx/test/config.py +++ b/libcxx/utils/libcxx/test/config.py @@ -452,10 +452,6 @@ def configure_features(self): if self.cxx.hasCompileFlag('-faligned-allocation'): self.config.available_features.add('-faligned-allocation') - else: - # FIXME remove this once more than just clang-4.0 support - # C++17 aligned allocation. - self.config.available_features.add('no-aligned-allocation') if self.cxx.hasCompileFlag('-fdelayed-template-parsing'): self.config.available_features.add('fdelayed-template-parsing') diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index e172b708afcf..15b04d6fe332 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -108,12 +108,21 @@ StringRef getOutputSectionName(const InputSectionBase *s) { } } - // This check is for -z keep-text-section-prefix. This option separates text - // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or - // ".text.exit". - // When enabled, this allows identifying the hot code region (.text.hot) in - // the final binary which can be selectively mapped to huge pages or mlocked, - // for instance. + // A BssSection created for a common symbol is identified as "COMMON" in + // linker scripts. It should go to .bss section. + if (s->name == "COMMON") + return ".bss"; + + if (script->hasSectionsCommand) + return s->name; + + // When no SECTIONS is specified, emulate GNU ld's internal linker scripts + // by grouping sections with certain prefixes. + + // GNU ld places text sections with prefix ".text.hot.", ".text.unlikely.", + // ".text.startup." or ".text.exit." before others. We provide an option -z + // keep-text-section-prefix to group such sections into separate output + // sections. This is more flexible. See also sortISDBySectionOrder(). if (config->zKeepTextSectionPrefix) for (StringRef v : {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) @@ -127,11 +136,6 @@ StringRef getOutputSectionName(const InputSectionBase *s) { if (isSectionPrefix(v, s->name)) return v.drop_back(); - // CommonSection is identified as "COMMON" in linker scripts. - // By default, it should go to .bss section. - if (s->name == "COMMON") - return ".bss"; - return s->name; } diff --git a/lld/test/ELF/linkerscript/data-commands-gc.s b/lld/test/ELF/linkerscript/data-commands-gc.s index 0add6ba27e94..0262d7334e3e 100644 --- a/lld/test/ELF/linkerscript/data-commands-gc.s +++ b/lld/test/ELF/linkerscript/data-commands-gc.s @@ -4,7 +4,7 @@ # RUN: ld.lld --gc-sections -o %t %t.o --script %t.script # RUN: llvm-objdump -t %t | FileCheck %s -# CHECK: 0000000000000008 g .rodata 0000000000000000 bar +# CHECK: 0000000000000008 g .rodata.bar 0000000000000000 bar .section .rodata.bar .quad 0x1122334455667788 diff --git a/lld/test/ELF/linkerscript/icf-output-sections.s b/lld/test/ELF/linkerscript/icf-output-sections.s index f23d7fff06b0..ae9203abaea4 100644 --- a/lld/test/ELF/linkerscript/icf-output-sections.s +++ b/lld/test/ELF/linkerscript/icf-output-sections.s @@ -28,13 +28,19 @@ # SEC2: .text.foo PROGBITS 0000000000000000 001000 000001 # SEC2-NEXT: .text.bar PROGBITS 0000000000000001 001001 000001 -## .text.bar* are orphans that get assigned to .text. +## .text.bar* are orphan sections. # RUN: echo 'SECTIONS { .text.foo : {*(.text.foo*)} }' > %t3.script -# RUN: ld.lld %t.o --script %t3.script --icf=all --print-icf-sections -o %t | FileCheck --check-prefix=ICF2 %s -# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC3 %s +# RUN: ld.lld %t.o -T %t3.script --icf=all --print-icf-sections -o %t3 | FileCheck --check-prefix=ICF3 %s +# RUN: llvm-readelf -S %t3 | FileCheck --check-prefix=SEC3 %s +# ICF3: selected section {{.*}}.o:(.text.foo0) +# ICF3-NEXT: removing identical section {{.*}}.o:(.text.foo1) + +# SEC3: Name Type Address Off Size # SEC3: .text.foo PROGBITS 0000000000000000 001000 000001 -# SEC3-NEXT: .text PROGBITS 0000000000000004 001004 000001 +# SEC3-NEXT: .text PROGBITS 0000000000000004 001004 000000 +# SEC3-NEXT: .text.bar0 PROGBITS 0000000000000004 001004 000001 +# SEC3-NEXT: .text.bar1 PROGBITS 0000000000000005 001005 000001 .section .text.foo0,"ax" ret diff --git a/lld/test/ELF/linkerscript/linkorder.s b/lld/test/ELF/linkerscript/linkorder.s index 44547b8ab002..042e8b3293fe 100644 --- a/lld/test/ELF/linkerscript/linkorder.s +++ b/lld/test/ELF/linkerscript/linkorder.s @@ -1,11 +1,11 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text : { *(.text.bar) *(.text.foo) } }" > %t.script +# RUN: echo "SECTIONS { .rodata : {*(.rodata*)} .text : {*(.text.bar) *(.text.foo)} }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-objdump -s %t | FileCheck %s -# RUN: echo "SECTIONS { .text : { *(.text.foo) *(.text.bar) } }" > %t.script +# RUN: echo "SECTIONS { .rodata : {*(.rodata*)} .text : {*(.text.foo) *(.text.bar)} }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o # RUN: llvm-objdump -s %t | FileCheck --check-prefix=INV %s diff --git a/lld/test/ELF/linkerscript/linkorder2.s b/lld/test/ELF/linkerscript/linkorder2.s index 4a538b6190e7..5b2eeea08abb 100644 --- a/lld/test/ELF/linkerscript/linkorder2.s +++ b/lld/test/ELF/linkerscript/linkorder2.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text : { *(.text.*) } }" > %t.script +# RUN: echo 'SECTIONS { .rodata : {*(.rodata.*)} .text : {*(.text.*)} }' > %t.script # RUN: echo "_bar" > %t.ord # RUN: echo "_foo" >> %t.ord diff --git a/lld/test/ELF/linkerscript/memory3.s b/lld/test/ELF/linkerscript/memory3.s index b9d609e59e31..56fc36d67a31 100644 --- a/lld/test/ELF/linkerscript/memory3.s +++ b/lld/test/ELF/linkerscript/memory3.s @@ -18,6 +18,6 @@ # CHECK: 0 00000000 0000000000000000 # CHECK: 1 .text 00000001 0000000000001000 -.section .text.foo,"ax",%progbits +.section .text,"ax",%progbits foo: nop diff --git a/lld/test/ELF/linkerscript/orphan-report.s b/lld/test/ELF/linkerscript/orphan-report.s index 5203a6d20de2..3dca23267ec6 100644 --- a/lld/test/ELF/linkerscript/orphan-report.s +++ b/lld/test/ELF/linkerscript/orphan-report.s @@ -24,7 +24,7 @@ # RUN: %t.o 2>&1 | FileCheck %s --check-prefixes=COMMON,DYNSYM,SYMTAB # COMMON: {{.*}}.o:(.text) is being placed in '.text' -# COMMON-NEXT: {{.*}}.o:(.text.2) is being placed in '.text' +# COMMON-NEXT: {{.*}}.o:(.text.2) is being placed in '.text.2' # COMMON-NEXT: :(.comment) is being placed in '.comment' # DYNSYM-NEXT: :(.dynsym) is being placed in '.dynsym' # DYNSYM-NEXT: :(.gnu.hash) is being placed in '.gnu.hash' diff --git a/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test b/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test index 973a4881850e..18dc5019ee1e 100644 --- a/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test +++ b/lld/test/ELF/linkerscript/symbol-assign-many-passes2.test @@ -22,7 +22,7 @@ SECTIONS { b = c + 1; c = d + 1; d = e + 1; - *(.text); + *(.text*); } e = .; } diff --git a/lld/test/ELF/mips-npic-call-pic-script.s b/lld/test/ELF/mips-npic-call-pic-script.s index 0ce1bfe94779..041c62101f7f 100644 --- a/lld/test/ELF/mips-npic-call-pic-script.s +++ b/lld/test/ELF/mips-npic-call-pic-script.s @@ -87,13 +87,13 @@ __start: # ORPH1: Disassembly of section .text: # ORPH1-EMPTY: # ORPH1-NEXT: <__start>: -# ORPH1-NEXT: 20000: jal 131156 <__LA25Thunk_foo1a> +# ORPH1-NEXT: 20000: jal 131168 <__LA25Thunk_foo1a> # ORPH1-NEXT: 20004: nop -# ORPH1-NEXT: 20008: jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 20008: jal 131216 <__LA25Thunk_foo2> # ORPH1-NEXT: 2000c: nop -# ORPH1-NEXT: 20010: jal 131172 <__LA25Thunk_foo1b> +# ORPH1-NEXT: 20010: jal 131184 <__LA25Thunk_foo1b> # ORPH1-NEXT: 20014: nop -# ORPH1-NEXT: 20018: jal 131208 <__LA25Thunk_foo2> +# ORPH1-NEXT: 20018: jal 131216 <__LA25Thunk_foo2> # ORPH1-NEXT: 2001c: nop # ORPH1-NEXT: 20020: jal 131120 <__LA25Thunk_fpic> # ORPH1-NEXT: 20024: nop @@ -113,16 +113,16 @@ __start: # ORPH1-NEXT: 20050: nop # ORPH1: <__LA25Thunk_foo1a>: -# ORPH1-NEXT: 20054: lui $25, 2 -# ORPH1-NEXT: 20058: j 131200 -# ORPH1-NEXT: 2005c: addiu $25, $25, 128 -# ORPH1-NEXT: 20060: nop +# ORPH1-NEXT: 20060: lui $25, 2 +# ORPH1-NEXT: j 131200 +# ORPH1-NEXT: addiu $25, $25, 128 +# ORPH1-NEXT: nop # ORPH1: <__LA25Thunk_foo1b>: -# ORPH1-NEXT: 20064: lui $25, 2 -# ORPH1-NEXT: 20068: j 131204 -# ORPH1-NEXT: 2006c: addiu $25, $25, 132 -# ORPH1-NEXT: 20070: nop +# ORPH1-NEXT: 20070: lui $25, 2 +# ORPH1-NEXT: j 131204 +# ORPH1-NEXT: addiu $25, $25, 132 +# ORPH1-NEXT: nop # ORPH1: : # ORPH1-NEXT: 20080: nop @@ -131,17 +131,17 @@ __start: # ORPH1-NEXT: 20084: nop # ORPH1: <__LA25Thunk_foo2>: -# ORPH1-NEXT: 20088: lui $25, 2 -# ORPH1-NEXT: 2008c: j 131232 -# ORPH1-NEXT: 20090: addiu $25, $25, 160 -# ORPH1-NEXT: 20094: nop +# ORPH1-NEXT: 20090: lui $25, 2 +# ORPH1-NEXT: j 131232 +# ORPH1-NEXT: addiu $25, $25, 160 +# ORPH1-NEXT: nop # ORPH1: : # ORPH1-NEXT: 200a0: nop # Test script with orphans added to new OutputSection, the .text.1 and # .text.2 sections will form a new OutputSection .text -# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } }" > %t3.script +# RUN: echo "SECTIONS { .out 0x20000 : { *(.text) } .text : {*(.text*)} }" > %t3.script # RUN: ld.lld --script %t3.script %t-npic.o %t-pic.o %t-sto-pic.o -o %t3.exe # RUN: llvm-objdump -d --no-show-raw-insn %t3.exe | FileCheck --check-prefix=ORPH2 %s diff --git a/lld/test/ELF/shuffle-sections-init-fini.s b/lld/test/ELF/shuffle-sections-init-fini.s index 31d87bb32444..d98ca8d359de 100644 --- a/lld/test/ELF/shuffle-sections-init-fini.s +++ b/lld/test/ELF/shuffle-sections-init-fini.s @@ -30,7 +30,9 @@ ## With a SECTIONS command, SHT_INIT_ARRAY prirotities are ignored. ## All .init_array* are shuffled together. -# RUN: echo 'SECTIONS {}' > %t.script +# RUN: echo 'SECTIONS { \ +# RUN: .init_array : { *(.init_array*) } \ +# RUN: .fini_array : { *(.fini_array*) }}' > %t.script # RUN: ld.lld -T %t.script %t.o -o %t2 # RUN: llvm-readelf -x .init -x .fini -x .init_array -x .fini_array %t2 | \ # RUN: FileCheck --check-prefixes=CHECK2,ORDERED2 %s diff --git a/lld/test/ELF/text-section-prefix.s b/lld/test/ELF/text-section-prefix.s index e39536da387d..022b4167037d 100644 --- a/lld/test/ELF/text-section-prefix.s +++ b/lld/test/ELF/text-section-prefix.s @@ -1,39 +1,53 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld -z keep-text-section-prefix %t -o %t2 -# RUN: llvm-readelf -l %t2 | FileCheck %s -# RUN: ld.lld %t -o %t3 -# RUN: llvm-readelf -l %t3 | FileCheck --check-prefix=CHECKNO %s -# RUN: ld.lld -z nokeep-text-section-prefix %t -o %t4 -# RUN: llvm-readelf -l %t4 | FileCheck --check-prefix=CHECKNO %s - -# CHECK: .text -# CHECK: .text.hot -# CHECK: .text.startup -# CHECK: .text.exit -# CHECK: .text.unlikely -# CHECKNO: .text -# CHECKNO-NOT: .text.hot +## -z keep-text-section-prefix separates text sections with prefix .text.hot, +## .text.unlikely, .text.startup, or .text.exit, in the absence of a SECTIONS command. +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: ld.lld %t.o -o %t1 +# RUN: llvm-readelf -S %t1 | FileCheck --check-prefix=NOKEEP %s +# RUN: ld.lld -z nokeep-text-section-prefix %t.o -o %t2 +# RUN: cmp %t1 %t2 + +# RUN: ld.lld -z keep-text-section-prefix %t.o -o %t.keep +# RUN: llvm-readelf -S %t.keep | FileCheck --check-prefix=KEEP %s + +# KEEP: [ 1] .text +# KEEP-NEXT: [ 2] .text.hot +# KEEP-NEXT: [ 3] .text.startup +# KEEP-NEXT: [ 4] .text.exit +# KEEP-NEXT: [ 5] .text.unlikely + +# NOKEEP: [ 1] .text +# NOKEEP-NOT: .text + +## With a SECTIONS command, orphan sections are created verbatim. +## No grouping is performed for them. +# RUN: echo 'SECTIONS {}' > %t.lds +# RUN: ld.lld -T %t.lds -z keep-text-section-prefix %t.o -o %t.script +# RUN: llvm-readelf -S %t.script | FileCheck --check-prefix=SCRIPT %s + +# SCRIPT: .text +# SCRIPT-NEXT: .text.f +# SCRIPT-NEXT: .text.hot.f_hot +# SCRIPT-NEXT: .text.startup.f_startup +# SCRIPT-NEXT: .text.exit.f_exit +# SCRIPT-NEXT: .text.unlikely.f_unlikely + +.globl _start _start: ret .section .text.f,"ax" -f: nop .section .text.hot.f_hot,"ax" -f_hot: nop .section .text.startup.f_startup,"ax" -f_startup: nop .section .text.exit.f_exit,"ax" -f_exit: nop .section .text.unlikely.f_unlikely,"ax" -f_unlikely: nop diff --git a/lld/tools/lld/CMakeLists.txt b/lld/tools/lld/CMakeLists.txt index a15e296e31df..a37c2c702bd5 100644 --- a/lld/tools/lld/CMakeLists.txt +++ b/lld/tools/lld/CMakeLists.txt @@ -4,7 +4,11 @@ set(LLVM_LINK_COMPONENTS add_lld_tool(lld lld.cpp + + ENABLE_PLUGINS + SUPPORT_PLUGINS ) +export_executable_symbols_for_plugins(lld) target_link_libraries(lld PRIVATE diff --git a/lld/tools/lld/lld.cpp b/lld/tools/lld/lld.cpp index 72ff758164d8..646fc3d6468e 100644 --- a/lld/tools/lld/lld.cpp +++ b/lld/tools/lld/lld.cpp @@ -36,6 +36,7 @@ #include "llvm/Support/Host.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PluginLoader.h" #include using namespace lld; diff --git a/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/lldb/include/lldb/DataFormatters/FormattersHelpers.h index 93642e57fde0..a5b0da57e5d8 100644 --- a/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -56,6 +56,8 @@ size_t ExtractIndexFromString(const char *item_name); lldb::addr_t GetArrayAddressOrPointerValue(ValueObject &valobj); +lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair); + time_t GetOSXEpoch(); struct InferiorSizedWord { diff --git a/lldb/include/lldb/Expression/ExpressionVariable.h b/lldb/include/lldb/Expression/ExpressionVariable.h index c523176e003f..60062d212bad 100644 --- a/lldb/include/lldb/Expression/ExpressionVariable.h +++ b/lldb/include/lldb/Expression/ExpressionVariable.h @@ -221,11 +221,7 @@ class PersistentExpressionState : public ExpressionVariableList { uint32_t addr_byte_size) = 0; /// Return a new persistent variable name with the specified prefix. - ConstString GetNextPersistentVariableName(Target &target, - llvm::StringRef prefix); - - virtual llvm::StringRef - GetPersistentVariablePrefix(bool is_error = false) const = 0; + virtual ConstString GetNextPersistentVariableName(bool is_error = false) = 0; virtual void RemovePersistentVariable(lldb::ExpressionVariableSP variable) = 0; @@ -237,6 +233,10 @@ class PersistentExpressionState : public ExpressionVariableList { void RegisterExecutionUnit(lldb::IRExecutionUnitSP &execution_unit_sp); +protected: + virtual llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const = 0; + private: LLVMCastKind m_kind; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 77cda4998192..cc74fe0f3d74 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1100,11 +1100,6 @@ class Target : public std::enable_shared_from_this, lldb::ExpressionVariableSP GetPersistentVariable(ConstString name); - /// Return the next available number for numbered persistent variables. - unsigned GetNextPersistentVariableIndex() { - return m_next_persistent_variable_index++; - } - lldb::addr_t GetPersistentSymbol(ConstString name); /// This method will return the address of the starting function for diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index e1d0ca941108..4c9c44ea15f4 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -3270,9 +3270,7 @@ ValueObjectSP ValueObject::Persist() { if (!persistent_state) return nullptr; - auto prefix = persistent_state->GetPersistentVariablePrefix(); - ConstString name = - persistent_state->GetNextPersistentVariableName(*target_sp, prefix); + ConstString name = persistent_state->GetNextPersistentVariableName(); ValueObjectSP const_result_sp = ValueObjectConstResult::Create(target_sp.get(), GetValue(), name); diff --git a/lldb/source/DataFormatters/FormattersHelpers.cpp b/lldb/source/DataFormatters/FormattersHelpers.cpp index 96e93808c18e..7944ff06eee5 100644 --- a/lldb/source/DataFormatters/FormattersHelpers.cpp +++ b/lldb/source/DataFormatters/FormattersHelpers.cpp @@ -142,3 +142,14 @@ lldb_private::formatters::GetArrayAddressOrPointerValue(ValueObject &valobj) { return data_addr; } + +lldb::ValueObjectSP +lldb_private::formatters::GetValueOfLibCXXCompressedPair(ValueObject &pair) { + ValueObjectSP value = + pair.GetChildMemberWithName(ConstString("__value_"), true); + if (!value) { + // pre-r300140 member name + value = pair.GetChildMemberWithName(ConstString("__first_"), true); + } + return value; +} diff --git a/lldb/source/Expression/ExpressionVariable.cpp b/lldb/source/Expression/ExpressionVariable.cpp index 7c27c0f249ec..d95f0745cf4b 100644 --- a/lldb/source/Expression/ExpressionVariable.cpp +++ b/lldb/source/Expression/ExpressionVariable.cpp @@ -76,13 +76,3 @@ void PersistentExpressionState::RegisterExecutionUnit( } } } - -ConstString PersistentExpressionState::GetNextPersistentVariableName( - Target &target, llvm::StringRef Prefix) { - llvm::SmallString<64> name; - { - llvm::raw_svector_ostream os(name); - os << Prefix << target.GetNextPersistentVariableIndex(); - } - return ConstString(name); -} diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 33c061effca4..8e96891257e4 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -881,11 +881,9 @@ class EntityResultVariable : public Materializer::Entity { return; } - ConstString name = - m_delegate - ? m_delegate->GetName() - : persistent_state->GetNextPersistentVariableName( - *target_sp, persistent_state->GetPersistentVariablePrefix()); + ConstString name = m_delegate + ? m_delegate->GetName() + : persistent_state->GetNextPersistentVariableName(); lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 3cbedf80755a..42afac9edb0d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -108,3 +108,14 @@ ClangPersistentVariables::GetClangASTImporter() { } return m_ast_importer_sp; } + +ConstString +ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index 12268b6549aa..f6298911dd6c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -51,9 +51,7 @@ class ClangPersistentVariables : public PersistentExpressionState { void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; - llvm::StringRef GetPersistentVariablePrefix(bool is_error) const override { - return "$"; - } + virtual ConstString GetNextPersistentVariableName(bool is_error = false); /// Returns the next file name that should be used for user expressions. std::string GetNextExprFileName() { @@ -80,6 +78,12 @@ class ClangPersistentVariables : public PersistentExpressionState { return m_hand_loaded_clang_modules; } +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$"; + } + private: /// The counter used by GetNextExprFileName. uint32_t m_next_user_file_id = 0; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index 6d781934c174..b246fc374d1c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -924,9 +924,7 @@ void ClangUserExpression::ClangUserExpressionHelper::CommitPersistentDecls() { } ConstString ClangUserExpression::ResultDelegate::GetName() { - auto prefix = m_persistent_state->GetPersistentVariablePrefix(); - return m_persistent_state->GetNextPersistentVariableName(*m_target_sp, - prefix); + return m_persistent_state->GetNextPersistentVariableName(false); } void ClangUserExpression::ResultDelegate::DidDematerialize( diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 97084da5fffa..ecb577e0c531 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -611,6 +611,15 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "shared_ptr synthetic children", ConstString("^(std::__[[:alnum:]]+::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); + + ConstString libcxx_std_unique_ptr_regex( + "^std::__[[:alnum:]]+::unique_ptr<.+>(( )?&)?$"); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator, + "unique_ptr synthetic children", libcxx_std_unique_ptr_regex, + stl_synth_flags, true); + AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, @@ -715,6 +724,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { "libc++ std::weak_ptr summary provider", ConstString("^std::__[[:alnum:]]+::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true); + AddCXXSummary(cpp_category_sp, + lldb_private::formatters::LibcxxUniquePointerSummaryProvider, + "libc++ std::unique_ptr summary provider", + libcxx_std_unique_ptr_regex, stl_summary_flags, true); AddCXXSynthetic( cpp_category_sp, diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 7152ff407f29..84dd09a47d8a 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -144,6 +144,43 @@ bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider( return true; } +bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider( + ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { + ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue()); + if (!valobj_sp) + return false; + + ValueObjectSP ptr_sp( + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + if (!ptr_sp) + return false; + + if (ptr_sp->GetValueAsUnsigned(0) == 0) { + stream.Printf("nullptr"); + return true; + } else { + bool print_pointee = false; + Status error; + ValueObjectSP pointee_sp = ptr_sp->Dereference(error); + if (pointee_sp && error.Success()) { + if (pointee_sp->DumpPrintableRepresentation( + stream, ValueObject::eValueObjectRepresentationStyleSummary, + lldb::eFormatInvalid, + ValueObject::PrintableRepresentationSpecialCases::eDisable, + false)) + print_pointee = true; + } + if (!print_pointee) + stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0)); + } + + return true; +} + /* (lldb) fr var ibeg --raw --ptr-depth 1 (std::__1::__map_iteratorGetChildMemberWithName(ConstString("__ptr_"), true)); + if (!ptr_sp) + return false; + + m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + + return false; +} + +bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (name == "__value_") + return 0; + return UINT32_MAX; +} + bool lldb_private::formatters::LibcxxContainerSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { if (valobj.IsPointerType()) { diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index a92e8be9abe9..ea5a7c178178 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -43,6 +43,10 @@ bool LibcxxSmartPointerSummaryProvider( const TypeSummaryOptions &options); // libc++ std::shared_ptr<> and std::weak_ptr<> +// libc++ std::unique_ptr<> +bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + bool LibcxxFunctionSummaryProvider( ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options); // libc++ std::function<> @@ -107,6 +111,26 @@ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { lldb::ByteOrder m_byte_order; }; +class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + + ~LibcxxUniquePtrSyntheticFrontEnd() override; + +private: + lldb::ValueObjectSP m_compressed_pair_sp; +}; + SyntheticChildrenFrontEnd * LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); @@ -115,6 +139,10 @@ SyntheticChildrenFrontEnd * LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 4c5940a45766..0d5ae16a0b29 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -290,15 +290,6 @@ ValueObjectSP ForwardListFrontEnd::GetChildAtIndex(size_t idx) { m_element_type); } -static ValueObjectSP GetValueOfCompressedPair(ValueObject &pair) { - ValueObjectSP value = pair.GetChildMemberWithName(ConstString("__value_"), true); - if (! value) { - // pre-r300140 member name - value = pair.GetChildMemberWithName(ConstString("__first_"), true); - } - return value; -} - bool ForwardListFrontEnd::Update() { AbstractListFrontEnd::Update(); @@ -311,7 +302,7 @@ bool ForwardListFrontEnd::Update() { m_backend.GetChildMemberWithName(ConstString("__before_begin_"), true)); if (!impl_sp) return false; - impl_sp = GetValueOfCompressedPair(*impl_sp); + impl_sp = GetValueOfLibCXXCompressedPair(*impl_sp); if (!impl_sp) return false; m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get(); @@ -332,7 +323,7 @@ size_t ListFrontEnd::CalculateNumChildren() { ValueObjectSP size_alloc( m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true)); if (size_alloc) { - ValueObjectSP value = GetValueOfCompressedPair(*size_alloc); + ValueObjectSP value = GetValueOfLibCXXCompressedPair(*size_alloc); if (value) { m_count = value->GetValueAsUnsigned(UINT32_MAX); } diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 46dd3774e5a9..350043f8d4e9 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -58,6 +58,17 @@ PlatformDarwin::PlatformDarwin(bool is_host) /// inherited from by the plug-in instance. PlatformDarwin::~PlatformDarwin() {} +lldb_private::Status +PlatformDarwin::PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, uint32_t uid, + uint32_t gid) { + // Unconditionally unlink the destination. If it is an executable, + // simply opening it and truncating its contents would invalidate + // its cached code signature. + Unlink(destination); + return PlatformPOSIX::PutFile(source, destination, uid, gid); +} + FileSpecList PlatformDarwin::LocateExecutableScriptingResources( Target *target, Module &module, Stream *feedback_stream) { FileSpecList file_list; diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 6d51edbc9294..f6729c508f00 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -25,6 +25,11 @@ class PlatformDarwin : public PlatformPOSIX { ~PlatformDarwin() override; + lldb_private::Status PutFile(const lldb_private::FileSpec &source, + const lldb_private::FileSpec &destination, + uint32_t uid = UINT32_MAX, + uint32_t gid = UINT32_MAX) override; + // lldb_private::Platform functions lldb_private::Status ResolveSymbolFile(lldb_private::Target &target, diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index cb7eca280a39..4320eb93adfc 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -97,10 +97,8 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, if (!persistent_expression_state) return {}; - auto prefix = persistent_expression_state->GetPersistentVariablePrefix(); ConstString persistent_variable_name = - persistent_expression_state->GetNextPersistentVariableName(target, - prefix); + persistent_expression_state->GetNextPersistentVariableName(); lldb::ValueObjectSP const_valobj_sp; diff --git a/lldb/test/API/commands/expression/result_numbering/Makefile b/lldb/test/API/commands/expression/result_numbering/Makefile new file mode 100644 index 000000000000..695335e068c0 --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -std=c99 + +include Makefile.rules diff --git a/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py b/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py new file mode 100644 index 000000000000..cd6b9c43775c --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/TestResultNumbering.py @@ -0,0 +1,48 @@ +""" +Make sure running internal expressions doesn't +influence the result variable numbering. +""" + + + +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + + +class TestExpressionResultNumbering(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + NO_DEBUG_INFO_TESTCASE = True + + def test_sample_rename_this(self): + self.build() + self.main_source_file = lldb.SBFileSpec("main.c") + self.do_numbering_test() + + def do_numbering_test(self): + (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, + "Set a breakpoint here", self.main_source_file) + + bkpt = target.BreakpointCreateBySourceRegex("Add conditions to this breakpoint", + self.main_source_file) + self.assertEqual(bkpt.GetNumLocations(), 1, "Set the breakpoint") + + bkpt.SetCondition("call_me(value) < 6") + + # Get the number of the last expression: + result = thread.frames[0].EvaluateExpression("call_me(200)") + self.assertTrue(result.GetError().Success(), "Our expression succeeded") + name = result.GetName() + ordinal = int(name[1:]) + + process.Continue() + + # The condition evaluation had to run a 4 expressions, but we haven't + # run any user expressions. + result = thread.frames[0].EvaluateExpression("call_me(200)") + self.assertTrue(result.GetError().Success(), "Our expression succeeded the second time") + after_name = result.GetName() + after_ordinal = int(after_name[1:]) + self.assertEqual(ordinal + 1, after_ordinal) diff --git a/lldb/test/API/commands/expression/result_numbering/main.c b/lldb/test/API/commands/expression/result_numbering/main.c new file mode 100644 index 000000000000..0f5853c99fb1 --- /dev/null +++ b/lldb/test/API/commands/expression/result_numbering/main.c @@ -0,0 +1,18 @@ +#include + +int +call_me(int input) +{ + return input; +} + +int +main() +{ + int value = call_me(0); // Set a breakpoint here + while (value < 10) + { + printf("Add conditions to this breakpoint: %d.\n", value++); + } + return 0; +} diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index 29360856a735..c0cdc085f129 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -286,6 +286,7 @@ def do_test_run_args_and_env_vars(self, use_launchsimple): "Environment variable 'MY_ENV_VAR' successfully passed."]) @skipIfRemote # it doesn't make sense to send host env to remote target + @skipIf(oslist=["windows"]) def test_pass_host_env_vars(self): """Test that the host env vars are passed to the launched process.""" self.build() diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile new file mode 100644 index 000000000000..7e57f13aea55 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/Makefile @@ -0,0 +1,6 @@ +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 + +CXXFLAGS_EXTRAS := -std=c++14 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py new file mode 100644 index 000000000000..b91e494258bf --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py @@ -0,0 +1,47 @@ +""" +Test lldb data formatter for libc++ std::unique_ptr. +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class LibcxUniquePtrDataFormatterTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @add_test_categories(["libc++"]) + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + + (self.target, self.process, _, bkpt) = lldbutil.run_to_source_breakpoint(self, '// break here', + lldb.SBFileSpec("main.cpp", False)) + + self.expect("frame variable up_empty", + substrs=['(std::unique_ptr >) up_empty = nullptr {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int", + substrs=['(std::unique_ptr >) up_int = 10 {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref", + substrs=['(std::unique_ptr > &) up_int_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_int_ref_ref", + substrs=['(std::unique_ptr > &&) up_int_ref_ref = 10: {', + '__value_ = ', + '}']) + + self.expect("frame variable up_str", + substrs=['up_str = "hello" {', + '__value_ = ', + '}']) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp new file mode 100644 index 000000000000..4ccffe2a006d --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp @@ -0,0 +1,13 @@ +#include +#include +#include + +int main() { + std::unique_ptr up_empty; + std::unique_ptr up_int = std::make_unique(10); + std::unique_ptr up_str = std::make_unique("hello"); + std::unique_ptr &up_int_ref = up_int; + std::unique_ptr &&up_int_ref_ref = std::make_unique(10); + + return 0; // break here +} diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test b/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test index 7db8bc4b36cf..d133c8d3b9f9 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestDataFormatter.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that data formatters continue to work when replaying a reproducer. diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test b/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test index e2bcb2d96570..f400cef07a24 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestExpressionEvaluation.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # XFAIL: system-netbsd # Flaky diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test b/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test index db319093f174..ec8b36ea9576 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestImageList.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that image list works when replaying. We arbitrarily assume # there's at least two entries and compare that they're identical. diff --git a/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test b/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test index 1dec9a077c7b..ba9164f4b43a 100644 --- a/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test +++ b/lldb/test/Shell/Reproducer/Functionalities/TestStepping.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests that stepping continues to work when replaying a reproducer. diff --git a/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test b/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test index a8e7bdec250e..ef06bce8983f 100644 --- a/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test +++ b/lldb/test/Shell/Reproducer/TestCaptureEnvOverride.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests the LLDB_CAPTURE_REPRODUCER override. # RUN: %lldb -b -o 'reproducer status' --capture --capture-path %t.repro /bin/ls | FileCheck %s --check-prefix CAPTURE diff --git a/lldb/test/Shell/Reproducer/TestCrash.test b/lldb/test/Shell/Reproducer/TestCrash.test index cb0c09aad141..1389a9b76ad3 100644 --- a/lldb/test/Shell/Reproducer/TestCrash.test +++ b/lldb/test/Shell/Reproducer/TestCrash.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests that a reproducer is generated when LLDB crashes. # Start clean. diff --git a/lldb/test/Shell/Reproducer/TestDiscard.test b/lldb/test/Shell/Reproducer/TestDiscard.test index db9614aabb84..829aabbe2b03 100644 --- a/lldb/test/Shell/Reproducer/TestDiscard.test +++ b/lldb/test/Shell/Reproducer/TestDiscard.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This ensures that the reproducer properly cleans up after itself. # Build the inferior. diff --git a/lldb/test/Shell/Reproducer/TestDump.test b/lldb/test/Shell/Reproducer/TestDump.test index c193b806b547..8300a97004bb 100644 --- a/lldb/test/Shell/Reproducer/TestDump.test +++ b/lldb/test/Shell/Reproducer/TestDump.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests the reproducer dump functionality. # Generate a reproducer. diff --git a/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test b/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test index 609c83929292..683a7e2f5529 100644 --- a/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test +++ b/lldb/test/Shell/Reproducer/TestGDBRemoteRepro.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests the replaying of GDB remote packets. # diff --git a/lldb/test/Shell/Reproducer/TestMultipleTargets.test b/lldb/test/Shell/Reproducer/TestMultipleTargets.test index ce1a5ecdd4c8..7859480e2d04 100644 --- a/lldb/test/Shell/Reproducer/TestMultipleTargets.test +++ b/lldb/test/Shell/Reproducer/TestMultipleTargets.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # This tests the replaying with multiple targets. diff --git a/lldb/test/Shell/Reproducer/TestRelativePath.test b/lldb/test/Shell/Reproducer/TestRelativePath.test index 2ee4bf0c9649..fa7518784550 100644 --- a/lldb/test/Shell/Reproducer/TestRelativePath.test +++ b/lldb/test/Shell/Reproducer/TestRelativePath.test @@ -1,4 +1,3 @@ -# UNSUPPORTED: system-windows # This tests relative capture paths. # RUN: mkdir -p %t diff --git a/lldb/test/Shell/Reproducer/TestReuseDirectory.test b/lldb/test/Shell/Reproducer/TestReuseDirectory.test index 31b71a0f2601..a3fecced2504 100644 --- a/lldb/test/Shell/Reproducer/TestReuseDirectory.test +++ b/lldb/test/Shell/Reproducer/TestReuseDirectory.test @@ -1,4 +1,4 @@ -# UNSUPPORTED: system-windows, system-freebsd +# UNSUPPORTED: system-freebsd # Test that we can capture twice to the same directory without breaking the # reproducer functionality. diff --git a/lldb/test/Shell/Reproducer/TestSynchronous.test b/lldb/test/Shell/Reproducer/TestSynchronous.test index c62cbe81aff3..f32ce8c57224 100644 --- a/lldb/test/Shell/Reproducer/TestSynchronous.test +++ b/lldb/test/Shell/Reproducer/TestSynchronous.test @@ -1,5 +1,4 @@ # REQUIRES: python -# UNSUPPORTED: system-windows # Ensure that replay happens in synchronous mode. # RUN: rm -rf %t.repro diff --git a/lldb/test/Shell/Reproducer/TestWorkingDir.test b/lldb/test/Shell/Reproducer/TestWorkingDir.test index 707916bae560..1d4c7694211a 100644 --- a/lldb/test/Shell/Reproducer/TestWorkingDir.test +++ b/lldb/test/Shell/Reproducer/TestWorkingDir.test @@ -1,5 +1,3 @@ -# XFAIL: system-windows - # This tests that the reproducer can deal with relative files. We create a # binary in a subdirectory and pass its relative path to LLDB. The subdirectory # is removed before replay so that it only exists in the reproducer's VFS. diff --git a/lldb/test/Shell/Reproducer/lit.local.cfg b/lldb/test/Shell/Reproducer/lit.local.cfg index 7f4022768c87..30f97f28279d 100644 --- a/lldb/test/Shell/Reproducer/lit.local.cfg +++ b/lldb/test/Shell/Reproducer/lit.local.cfg @@ -6,5 +6,8 @@ if 'LLVM_DISABLE_CRASH_REPORT' in config.environment: if 'LLDB_CAPTURE_REPRODUCER' in config.environment: del config.environment['LLDB_CAPTURE_REPRODUCER'] +if 'system-windows' in config.available_features: + config.unsupported = True + if 'lldb-repro' in config.available_features: config.unsupported = True diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index 7b95d8be1b60..8cd71eef2332 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1029,6 +1029,13 @@ function(export_executable_symbols target) endif() endfunction() +# Export symbols if LLVM plugins are enabled. +function(export_executable_symbols_for_plugins target) + if(LLVM_ENABLE_PLUGINS) + export_executable_symbols(${target}) + endif() +endfunction() + if(NOT LLVM_TOOLCHAIN_TOOLS) set (LLVM_TOOLCHAIN_TOOLS llvm-ar diff --git a/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt b/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt index 5bf96425d60e..0b1cdffb3805 100644 --- a/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt +++ b/llvm/examples/OrcV2Examples/LLJITWithGDBRegistrationListener/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS Core + ExecutionEngine IRReader JITLink OrcJIT diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h b/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h index 906e8a9ac312..976d42d58846 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h @@ -50,6 +50,9 @@ class GISelKnownBits : public GISelChangeObserver { // KnownBitsAPI KnownBits getKnownBits(Register R); + KnownBits getKnownBits(Register R, const APInt &DemandedElts, + unsigned Depth = 0); + // Calls getKnownBits for first operand def of MI. KnownBits getKnownBits(MachineInstr &MI); APInt getKnownZeroes(Register R); diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 0552420c3c33..fefa8daa60a1 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -3332,6 +3332,16 @@ class TargetLowering : public TargetLoweringBase { const SelectionDAG &DAG, unsigned Depth = 0) const; + /// This method can be implemented by targets that want to expose additional + /// information about sign bits to GlobalISel combiners. The DemandedElts + /// argument allows us to only collect the minimum sign bits that are shared + /// by the requested vector elements. + virtual unsigned computeNumSignBitsForTargetInstr(GISelKnownBits &Analysis, + Register R, + const APInt &DemandedElts, + const MachineRegisterInfo &MRI, + unsigned Depth = 0) const; + /// Attempt to simplify any target nodes based on the demanded vector /// elements, returning true on success. Otherwise, analyze the expression and /// return a mask of KnownUndef and KnownZero elements for the expression diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h index 960c557f55d4..0a9d9c277d99 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h @@ -16,6 +16,7 @@ #define LLVM_OPENMP_CONTEXT_H #include "llvm/ADT/APSInt.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Triple.h" @@ -43,6 +44,7 @@ enum class TraitSelector { /// IDs for all OpenMP context trait properties (host/gpu/bsc/llvm/...) enum class TraitProperty { #define OMP_TRAIT_PROPERTY(Enum, ...) Enum, +#define OMP_LAST_TRAIT_PROPERTY(Enum) Last = Enum #include "llvm/Frontend/OpenMP/OMPKinds.def" }; @@ -122,12 +124,12 @@ struct VariantMatchInfo { void addTrait(TraitSet Set, TraitProperty Property, APInt *Score = nullptr) { if (Score) ScoreMap[Property] = *Score; - RequiredTraits.insert(Property); + RequiredTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } - SmallSet RequiredTraits; + BitVector RequiredTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ConstructTraits; SmallDenseMap ScoreMap; }; @@ -142,12 +144,12 @@ struct OMPContext { addTrait(getOpenMPContextTraitSetForProperty(Property), Property); } void addTrait(TraitSet Set, TraitProperty Property) { - ActiveTraits.insert(Property); + ActiveTraits.set(unsigned(Property)); if (Set == TraitSet::construct) ConstructTraits.push_back(Property); } - SmallSet ActiveTraits; + BitVector ActiveTraits = BitVector(unsigned(TraitProperty::Last) + 1); SmallVector ConstructTraits; }; diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def index d37c3911edf2..5d26f07a7f5a 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -209,8 +209,8 @@ __OMP_RTL(omp_get_thread_limit, false, Int32, ) __OMP_RTL(omp_get_supported_active_levels, false, Int32, ) __OMP_RTL(omp_get_max_active_levels, false, Int32, ) __OMP_RTL(omp_get_level, false, Int32, ) -__OMP_RTL(omp_get_ancestor_thread_num, false, Int32, ) -__OMP_RTL(omp_get_team_size, false, Int32, ) +__OMP_RTL(omp_get_ancestor_thread_num, false, Int32, Int32) +__OMP_RTL(omp_get_team_size, false, Int32, Int32) __OMP_RTL(omp_get_active_level, false, Int32, ) __OMP_RTL(omp_in_final, false, Int32, ) __OMP_RTL(omp_get_proc_bind, false, Int32, ) @@ -219,7 +219,7 @@ __OMP_RTL(omp_get_num_procs, false, Int32, ) __OMP_RTL(omp_get_place_proc_ids, false, Void, Int32, Int32Ptr) __OMP_RTL(omp_get_place_num, false, Int32, ) __OMP_RTL(omp_get_partition_num_places, false, Int32, ) -__OMP_RTL(omp_get_partition_place_nums, false, Int32, ) +__OMP_RTL(omp_get_partition_place_nums, false, Void, Int32Ptr) __OMP_RTL(omp_set_num_threads, false, Void, Int32) __OMP_RTL(omp_set_dynamic, false, Void, Int32) @@ -427,6 +427,9 @@ __OMP_PROC_BIND_KIND(unknown, 7) #ifndef OMP_TRAIT_PROPERTY #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) #endif +#ifndef OMP_LAST_TRAIT_PROPERTY +#define OMP_LAST_TRAIT_PROPERTY(Enum) +#endif #define __OMP_TRAIT_SET(Name) OMP_TRAIT_SET(Name, #Name) #define __OMP_TRAIT_SELECTOR(TraitSet, Name, RequiresProperty) \ @@ -534,10 +537,14 @@ __OMP_REQUIRES_TRAIT(reverse_offload) __OMP_REQUIRES_TRAIT(dynamic_allocators) __OMP_REQUIRES_TRAIT(atomic_default_mem_order) +OMP_LAST_TRAIT_PROPERTY( + implementation_atomic_default_mem_order_atomic_default_mem_order) + #undef __OMP_TRAIT_SELECTOR_AND_PROPERTY #undef OMP_TRAIT_SELECTOR #undef __OMP_TRAIT_SELECTOR #undef OMP_TRAIT_PROPERTY +#undef OMP_LAST_TRAIT_PROPERTY #undef __OMP_TRAIT_PROPERTY #undef __OMP_REQUIRES_TRAIT #undef OMP_REQUIRES_TRAIT diff --git a/llvm/include/llvm/IR/CallSite.h b/llvm/include/llvm/IR/CallSite.h index 0e957c4797e8..6a82e73537cf 100644 --- a/llvm/include/llvm/IR/CallSite.h +++ b/llvm/include/llvm/IR/CallSite.h @@ -146,6 +146,13 @@ class CallSiteBase { return static_cast(0); } + /// Return if this call is to an intrinsic. + bool isIntrinsic() const { + if (auto *F = getCalledFunction()) + return F->isIntrinsic(); + return false; + } + /// Determine whether the passed iterator points to the callee operand's Use. bool isCallee(Value::const_user_iterator UI) const { return isCallee(&UI.getUse()); diff --git a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td index 3f962cc667c5..c01db52b1622 100644 --- a/llvm/include/llvm/IR/IntrinsicsAMDGPU.td +++ b/llvm/include/llvm/IR/IntrinsicsAMDGPU.td @@ -1371,8 +1371,8 @@ def int_amdgcn_writelane : [IntrNoMem, IntrConvergent] >; -def int_amdgcn_alignbit : - GCCBuiltin<"__builtin_amdgcn_alignbit">, Intrinsic<[llvm_i32_ty], +// FIXME: Deprecated. This is equivalent to llvm.fshr +def int_amdgcn_alignbit : Intrinsic<[llvm_i32_ty], [llvm_i32_ty, llvm_i32_ty, llvm_i32_ty], [IntrNoMem, IntrSpeculatable] >; diff --git a/llvm/include/llvm/Support/LockFileManager.h b/llvm/include/llvm/Support/LockFileManager.h index 2efeca3b6200..ab66621e6756 100644 --- a/llvm/include/llvm/Support/LockFileManager.h +++ b/llvm/include/llvm/Support/LockFileManager.h @@ -78,8 +78,8 @@ class LockFileManager { /// For a shared lock, wait until the owner releases the lock. /// Total timeout for the file to appear is ~1.5 minutes. - /// \param MaxSeconds the maximum wait time per iteration in seconds. - WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 40); + /// \param MaxSeconds the maximum total wait time in seconds. + WaitForUnlockResult waitForUnlock(const unsigned MaxSeconds = 90); /// Remove the lock file. This may delete a different lock file than /// the one previously read if there is a race. diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h index 1df8ce9f17ff..a229f55e1a84 100644 --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -29,7 +29,7 @@ // automatically capture a potential dependence from Q to P. This dependence // will cause P to be reevaluated whenever Q changes in the future. // -// The Attributor will only reevaluated abstract attributes that might have +// The Attributor will only reevaluate abstract attributes that might have // changed since the last iteration. That means that the Attribute will not // revisit all instructions/blocks/functions in the module but only query // an update from a subset of the abstract attributes. @@ -152,8 +152,8 @@ struct IRPosition { /// The positions we distinguish in the IR. /// - /// The values are chosen such that the KindOrArgNo member has a value >= 1 - /// if it is an argument or call site argument while a value < 1 indicates the + /// The values are chosen such that the KindOrArgNo member has a value >= 0 + /// if it is an argument or call site argument while a value < 0 indicates the /// respective kind of that value. enum Kind : int { IRP_INVALID = -6, ///< An invalid position. @@ -273,18 +273,11 @@ struct IRPosition { /// Return the associated function, if any. Function *getAssociatedFunction() const { - if (auto *CB = dyn_cast(AnchorVal)) - return CB->getCalledFunction(); assert(KindOrArgNo != IRP_INVALID && "Invalid position does not have an anchor scope!"); - Value &V = getAnchorValue(); - if (isa(V)) - return &cast(V); - if (isa(V)) - return cast(V).getParent(); - if (isa(V)) - return cast(V).getFunction(); - return nullptr; + if (auto *CB = dyn_cast(AnchorVal)) + return CB->getCalledFunction(); + return getAnchorScope(); } /// Return the associated argument, if any. @@ -474,7 +467,10 @@ struct IRPosition { /// The value this position is anchored at. Value *AnchorVal; - /// The argument number, if non-negative, or the position "kind". + /// If AnchorVal is Argument or CallBase then this number should be + /// non-negative and it denotes the argument or call site argument index + /// respectively. Otherwise, it denotes the kind of this IRPosition according + /// to Kind above. int KindOrArgNo; }; @@ -2288,7 +2284,8 @@ struct DerefState : AbstractState { /// Add accessed bytes to the map. void addAccessedBytes(int64_t Offset, uint64_t Size) { - AccessedBytesMap[Offset] = std::max(AccessedBytesMap[Offset], Size); + uint64_t &AccessedBytes = AccessedBytesMap[Offset]; + AccessedBytes = std::max(AccessedBytes, Size); // Known bytes might increase. computeKnownDerefBytesFromAccessedMap(); diff --git a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp index 8e369fe9e31d..213af320531c 100644 --- a/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp +++ b/llvm/lib/CodeGen/GlobalISel/GISelKnownBits.cpp @@ -65,12 +65,18 @@ KnownBits GISelKnownBits::getKnownBits(MachineInstr &MI) { } KnownBits GISelKnownBits::getKnownBits(Register R) { - KnownBits Known; - LLT Ty = MRI.getType(R); + const LLT Ty = MRI.getType(R); APInt DemandedElts = Ty.isVector() ? APInt::getAllOnesValue(Ty.getNumElements()) : APInt(1, 1); + return getKnownBits(R, DemandedElts); +} + +KnownBits GISelKnownBits::getKnownBits(Register R, const APInt &DemandedElts, + unsigned Depth) { // For now, we only maintain the cache during one request. assert(ComputeKnownBitsCache.empty() && "Cache should have been cleared"); + + KnownBits Known; computeKnownBitsImpl(R, Known, DemandedElts); ComputeKnownBitsCache.clear(); return Known; @@ -428,6 +434,7 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, return 1; // No demanded elts, better to assume we don't know anything. LLT DstTy = MRI.getType(R); + const unsigned TyBits = DstTy.getScalarSizeInBits(); // Handle the case where this is called on a register that does not have a // type constraint. This is unlikely to occur except by looking through copies @@ -436,6 +443,7 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, if (!DstTy.isValid()) return 1; + unsigned FirstAnswer = 1; switch (Opcode) { case TargetOpcode::COPY: { MachineOperand &Src = MI.getOperand(1); @@ -465,13 +473,34 @@ unsigned GISelKnownBits::computeNumSignBits(Register R, return NumSrcSignBits - (NumSrcBits - DstTyBits); break; } - default: + case TargetOpcode::G_INTRINSIC: + case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: + default: { + unsigned NumBits = + TL.computeNumSignBitsForTargetInstr(*this, R, DemandedElts, MRI, Depth); + if (NumBits > 1) + FirstAnswer = std::max(FirstAnswer, NumBits); break; } + } + + // Finally, if we can prove that the top bits of the result are 0's or 1's, + // use this information. + KnownBits Known = getKnownBits(R, DemandedElts, Depth); + APInt Mask; + if (Known.isNonNegative()) { // sign bit is 0 + Mask = Known.Zero; + } else if (Known.isNegative()) { // sign bit is 1; + Mask = Known.One; + } else { + // Nothing known. + return FirstAnswer; + } - // TODO: Handle target instructions - // TODO: Fall back to known bits - return 1; + // Okay, we know that the sign bit in Mask is set. Use CLO to determine + // the number of identical bits in the top of the input value. + Mask <<= Mask.getBitWidth() - TyBits; + return std::max(FirstAnswer, Mask.countLeadingOnes()); } unsigned GISelKnownBits::computeNumSignBits(Register R, unsigned Depth) { diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 70d8656d2875..3f0c6443211e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -2783,6 +2783,12 @@ unsigned TargetLowering::ComputeNumSignBitsForTargetNode(SDValue Op, return 1; } +unsigned TargetLowering::computeNumSignBitsForTargetInstr( + GISelKnownBits &Analysis, Register R, const APInt &DemandedElts, + const MachineRegisterInfo &MRI, unsigned Depth) const { + return 1; +} + bool TargetLowering::SimplifyDemandedVectorEltsForTargetNode( SDValue Op, const APInt &DemandedElts, APInt &KnownUndef, APInt &KnownZero, TargetLoweringOpt &TLO, unsigned Depth) const { diff --git a/llvm/lib/Frontend/OpenMP/OMPContext.cpp b/llvm/lib/Frontend/OpenMP/OMPContext.cpp index 62e5d1d8c466..748caa645a37 100644 --- a/llvm/lib/Frontend/OpenMP/OMPContext.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPContext.cpp @@ -26,8 +26,9 @@ using namespace omp; OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { // Add the appropriate device kind trait based on the triple and the // IsDeviceCompilation flag. - ActiveTraits.insert(IsDeviceCompilation ? TraitProperty::device_kind_nohost - : TraitProperty::device_kind_host); + ActiveTraits.set(unsigned(IsDeviceCompilation + ? TraitProperty::device_kind_nohost + : TraitProperty::device_kind_host)); switch (TargetTriple.getArch()) { case Triple::arm: case Triple::armeb: @@ -43,12 +44,12 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { case Triple::ppc64le: case Triple::x86: case Triple::x86_64: - ActiveTraits.insert(TraitProperty::device_kind_cpu); + ActiveTraits.set(unsigned(TraitProperty::device_kind_cpu)); break; case Triple::amdgcn: case Triple::nvptx: case Triple::nvptx64: - ActiveTraits.insert(TraitProperty::device_kind_gpu); + ActiveTraits.set(unsigned(TraitProperty::device_kind_gpu)); break; default: break; @@ -58,7 +59,7 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { #define OMP_TRAIT_PROPERTY(Enum, TraitSetEnum, TraitSelectorEnum, Str) \ if (TraitSelector::TraitSelectorEnum == TraitSelector::device_arch) \ if (TargetTriple.getArch() == TargetTriple.getArchTypeForLLVMName(Str)) \ - ActiveTraits.insert(TraitProperty::Enum); + ActiveTraits.set(unsigned(TraitProperty::Enum)); #include "llvm/Frontend/OpenMP/OMPKinds.def" // TODO: What exactly do we want to see as device ISA trait? @@ -67,20 +68,22 @@ OMPContext::OMPContext(bool IsDeviceCompilation, Triple TargetTriple) { // LLVM is the "OpenMP vendor" but we could also interpret vendor as the // target vendor. - ActiveTraits.insert(TraitProperty::implementation_vendor_llvm); + ActiveTraits.set(unsigned(TraitProperty::implementation_vendor_llvm)); // The user condition true is accepted but not false. - ActiveTraits.insert(TraitProperty::user_condition_true); + ActiveTraits.set(unsigned(TraitProperty::user_condition_true)); // This is for sure some device. - ActiveTraits.insert(TraitProperty::device_kind_any); + ActiveTraits.set(unsigned(TraitProperty::device_kind_any)); LLVM_DEBUG({ dbgs() << "[" << DEBUG_TYPE << "] New OpenMP context with the following properties:\n"; - for (auto &Property : ActiveTraits) + for (const auto &SetBitsIt : ActiveTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); dbgs() << "\t " << getOpenMPContextTraitPropertyFullName(Property) << "\n"; + } }); } @@ -122,17 +125,24 @@ static bool isStrictSubset(const VariantMatchInfo &VMI0, // If all required traits are a strict subset and the ordered vectors storing // the construct traits, we say it is a strict subset. Note that the latter // relation is not required to be strict. - return set_is_strict_subset(VMI0.RequiredTraits, VMI1.RequiredTraits) && - isSubset(VMI0.ConstructTraits, VMI1.ConstructTraits); + if (VMI0.RequiredTraits.count() >= VMI1.RequiredTraits.count()) + return false; + for (const auto &SetBitsIt : VMI0.RequiredTraits.set_bits()) + if (!VMI1.RequiredTraits.test(SetBitsIt)) + return false; + if (!isSubset(VMI0.ConstructTraits, VMI1.ConstructTraits)) + return false; + return true; } static int isVariantApplicableInContextHelper( const VariantMatchInfo &VMI, const OMPContext &Ctx, SmallVectorImpl *ConstructMatches) { - for (TraitProperty Property : VMI.RequiredTraits) { + for (const auto &SetBitsIt : VMI.RequiredTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); - bool IsActiveTrait = Ctx.ActiveTraits.count(Property); + bool IsActiveTrait = Ctx.ActiveTraits.test(unsigned(Property)); if (!IsActiveTrait) { LLVM_DEBUG(dbgs() << "[" << DEBUG_TYPE << "] Property " << getOpenMPContextTraitPropertyName(Property) @@ -181,7 +191,8 @@ static APInt getVariantMatchScore(const VariantMatchInfo &VMI, APInt Score(64, 1); unsigned NoConstructTraits = VMI.ConstructTraits.size(); - for (TraitProperty Property : VMI.RequiredTraits) { + for (const auto &SetBitsIt : VMI.RequiredTraits.set_bits()) { + TraitProperty Property = TraitProperty(SetBitsIt); // If there is a user score attached, use it. if (VMI.ScoreMap.count(Property)) { const APInt &UserScore = VMI.ScoreMap.lookup(Property); diff --git a/llvm/lib/Support/LockFileManager.cpp b/llvm/lib/Support/LockFileManager.cpp index a4793aa7c04f..88489a658953 100644 --- a/llvm/lib/Support/LockFileManager.cpp +++ b/llvm/lib/Support/LockFileManager.cpp @@ -17,12 +17,16 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include +#include #include #include +#include #include #include #include +#include #include + #ifdef _WIN32 #include #endif @@ -295,23 +299,29 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) { if (getState() != LFS_Shared) return Res_Success; -#ifdef _WIN32 - unsigned long Interval = 1; -#else - struct timespec Interval; - Interval.tv_sec = 0; - Interval.tv_nsec = 1000000; -#endif + // Since we don't yet have an event-based method to wait for the lock file, + // implement randomized exponential backoff, similar to Ethernet collision + // algorithm. This improves performance on machines with high core counts + // when the file lock is heavily contended by multiple clang processes + const unsigned long MinWaitDurationMS = 10; + const unsigned long MaxWaitMultiplier = 50; // 500ms max wait + unsigned long WaitMultiplier = 1; + unsigned long ElapsedTimeSeconds = 0; + + std::random_device Device; + std::default_random_engine Engine(Device()); + + auto StartTime = std::chrono::steady_clock::now(); + do { + // FIXME: implement event-based waiting + // Sleep for the designated interval, to allow the owning process time to // finish up and remove the lock file. - // FIXME: Should we hook in to system APIs to get a notification when the - // lock file is deleted? -#ifdef _WIN32 - Sleep(Interval); -#else - nanosleep(&Interval, nullptr); -#endif + std::uniform_int_distribution Distribution(1, + WaitMultiplier); + unsigned long WaitDurationMS = MinWaitDurationMS * Distribution(Engine); + std::this_thread::sleep_for(std::chrono::milliseconds(WaitDurationMS)); if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) == errc::no_such_file_or_directory) { @@ -325,24 +335,16 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) { if (!processStillExecuting((*Owner).first, (*Owner).second)) return Res_OwnerDied; - // Exponentially increase the time we wait for the lock to be removed. -#ifdef _WIN32 - Interval *= 2; -#else - Interval.tv_sec *= 2; - Interval.tv_nsec *= 2; - if (Interval.tv_nsec >= 1000000000) { - ++Interval.tv_sec; - Interval.tv_nsec -= 1000000000; + WaitMultiplier *= 2; + if (WaitMultiplier > MaxWaitMultiplier) { + WaitMultiplier = MaxWaitMultiplier; } -#endif - } while ( -#ifdef _WIN32 - Interval < MaxSeconds * 1000 -#else - Interval.tv_sec < (time_t)MaxSeconds -#endif - ); + + ElapsedTimeSeconds = std::chrono::duration_cast( + std::chrono::steady_clock::now() - StartTime) + .count(); + + } while (ElapsedTimeSeconds < MaxSeconds); // Give up. return Res_Timeout; diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index ee199aa1d4b1..0eadefb689fd 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -75,8 +75,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16, SmallString Path8Str; Path8.toVector(Path8Str); - std::error_code EC = UTF8ToUTF16(Path8Str, Path16); - if (EC) + if (std::error_code EC = UTF8ToUTF16(Path8Str, Path16)) return EC; const bool IsAbsolute = llvm::sys::path::is_absolute(Path8); @@ -97,7 +96,7 @@ std::error_code widenPath(const Twine &Path8, SmallVectorImpl &Path16, return std::error_code(); if (!IsAbsolute) { - if (EC = llvm::sys::fs::make_absolute(Path8Str)) + if (std::error_code EC = llvm::sys::fs::make_absolute(Path8Str)) return EC; } diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp index bee0605bd556..bdf5c3b03663 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.cpp @@ -4587,6 +4587,29 @@ unsigned AMDGPUTargetLowering::ComputeNumSignBitsForTargetNode( } } +unsigned AMDGPUTargetLowering::computeNumSignBitsForTargetInstr( + GISelKnownBits &Analysis, Register R, + const APInt &DemandedElts, const MachineRegisterInfo &MRI, + unsigned Depth) const { + const MachineInstr *MI = MRI.getVRegDef(R); + if (!MI) + return 1; + + // TODO: Check range metadata on MMO. + switch (MI->getOpcode()) { + case AMDGPU::G_AMDGPU_BUFFER_LOAD_SBYTE: + return 25; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_SSHORT: + return 17; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_UBYTE: + return 24; + case AMDGPU::G_AMDGPU_BUFFER_LOAD_USHORT: + return 16; + default: + return 1; + } +} + bool AMDGPUTargetLowering::isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h index 54747b57f6f4..7d0b17f7e816 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h +++ b/llvm/lib/Target/AMDGPU/AMDGPUISelLowering.h @@ -269,6 +269,12 @@ class AMDGPUTargetLowering : public TargetLowering { const SelectionDAG &DAG, unsigned Depth = 0) const override; + unsigned computeNumSignBitsForTargetInstr(GISelKnownBits &Analysis, + Register R, + const APInt &DemandedElts, + const MachineRegisterInfo &MRI, + unsigned Depth = 0) const override; + bool isKnownNeverNaNForTargetNode(SDValue Op, const SelectionDAG &DAG, bool SNaN = false, diff --git a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp index caa3a4aa31f4..318e536da6aa 100644 --- a/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp +++ b/llvm/lib/Target/AMDGPU/AMDGPUTargetTransformInfo.cpp @@ -476,11 +476,24 @@ int GCNTTIImpl::getArithmeticInstrCost(unsigned Opcode, Type *Ty, Opd1PropInfo, Opd2PropInfo); } +// Return true if there's a potential benefit from using v2f16 instructions for +// an intrinsic, even if it requires nontrivial legalization. +static bool intrinsicHasPackedVectorBenefit(Intrinsic::ID ID) { + switch (ID) { + case Intrinsic::fma: // TODO: fmuladd + // There's a small benefit to using vector ops in the legalized code. + case Intrinsic::round: + return true; + default: + return false; + } +} + template int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, ArrayRef Args, FastMathFlags FMF, unsigned VF, const Instruction *I) { - if (ID != Intrinsic::fma) + if (!intrinsicHasPackedVectorBenefit(ID)) return BaseT::getIntrinsicInstrCost(ID, RetTy, Args, FMF, VF, I); EVT OrigTy = TLI->getValueType(DL, RetTy); @@ -502,8 +515,14 @@ int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, if (ST->has16BitInsts() && SLT == MVT::f16) NElts = (NElts + 1) / 2; - return LT.first * NElts * (ST->hasFastFMAF32() ? getHalfRateInstrCost() - : getQuarterRateInstrCost()); + // TODO: Get more refined intrinsic costs? + unsigned InstRate = getQuarterRateInstrCost(); + if (ID == Intrinsic::fma) { + InstRate = ST->hasFastFMAF32() ? getHalfRateInstrCost() + : getQuarterRateInstrCost(); + } + + return LT.first * NElts * InstRate; } int GCNTTIImpl::getIntrinsicInstrCost(Intrinsic::ID ID, Type *RetTy, diff --git a/llvm/lib/Target/PowerPC/PPC.td b/llvm/lib/Target/PowerPC/PPC.td index fc817631e0ac..888b228450b6 100644 --- a/llvm/lib/Target/PowerPC/PPC.td +++ b/llvm/lib/Target/PowerPC/PPC.td @@ -463,7 +463,7 @@ def : ProcessorModel<"g5", G5Model, def : ProcessorModel<"e500", PPCE500Model, [DirectiveE500, FeatureICBT, FeatureBookE, - FeatureISEL, FeatureMFTB, FeatureSPE]>; + FeatureISEL, FeatureMFTB, FeatureMSYNC, FeatureSPE]>; def : ProcessorModel<"e500mc", PPCE500mcModel, [DirectiveE500mc, FeatureSTFIWX, FeatureICBT, FeatureBookE, diff --git a/llvm/lib/Target/PowerPC/PPCInstrVSX.td b/llvm/lib/Target/PowerPC/PPCInstrVSX.td index b12096dacdd3..73529533c26b 100644 --- a/llvm/lib/Target/PowerPC/PPCInstrVSX.td +++ b/llvm/lib/Target/PowerPC/PPCInstrVSX.td @@ -1341,6 +1341,21 @@ def DWToSPExtractConv { dag BVS = (v4f32 (build_vector El0SS1, El1SS1, El0SS2, El1SS2)); } +def WToDPExtractConv { + dag El0S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 0)))); + dag El1S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 1)))); + dag El2S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 2)))); + dag El3S = (f64 (PPCfcfid (PPCmtvsra (extractelt v4i32:$A, 3)))); + dag El0U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 0)))); + dag El1U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 1)))); + dag El2U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 2)))); + dag El3U = (f64 (PPCfcfidu (PPCmtvsrz (extractelt v4i32:$A, 3)))); + dag BV02S = (v2f64 (build_vector El0S, El2S)); + dag BV13S = (v2f64 (build_vector El1S, El3S)); + dag BV02U = (v2f64 (build_vector El0U, El2U)); + dag BV13U = (v2f64 (build_vector El1U, El3U)); +} + // The following VSX instructions were introduced in Power ISA 2.07 /* FIXME: if the operands are v2i64, these patterns will not match. we should define new patterns or otherwise match the same patterns @@ -4171,6 +4186,41 @@ let AddedComplexity = 400 in { def : Pat<(v4i32 (build_vector ExtDbl.A0U, ExtDbl.A1U, ExtDbl.B0U, ExtDbl.B1U)), (v4i32 (VMRGEW MrgWords.CVA0B0U, MrgWords.CVA1B1U))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 1))))), + (v2f64 (XVCVSPDP (XXMRGHW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 0))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGHW $A, $A)), + (XVCVSPDP (XXMRGHW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XVCVSPDP $A))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXSLDWI $A, $A, 3)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 2))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXMRGLW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGLW $A, $A)), + (XVCVSPDP (XXMRGLW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$B, 0))))), + (v2f64 (XVCVSPDP (XXPERMDI $A, $B, 0)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$B, 3))))), + (v2f64 (XVCVSPDP (XXSLDWI (XXPERMDI $A, $B, 3), + (XXPERMDI $A, $B, 3), 1)))>; + def : Pat; + def : Pat; + def : Pat; + def : Pat; } let Predicates = [IsLittleEndian, HasP8Vector] in { @@ -4249,6 +4299,41 @@ let AddedComplexity = 400 in { def : Pat<(v4i32 (build_vector ExtDbl.A0U, ExtDbl.A1U, ExtDbl.B0U, ExtDbl.B1U)), (v4i32 (VMRGEW MrgWords.CVB1A1U, MrgWords.CVB0A0U))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 1))))), + (v2f64 (XVCVSPDP (XXMRGLW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 0))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGLW $A, $A)), + (XVCVSPDP (XXMRGLW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XVCVSPDP (XXSLDWI $A, $A, 1)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 1))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP $A))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 2))), + (f64 (fpextend (extractelt v4f32:$A, 3))))), + (v2f64 (XVCVSPDP (XXMRGHW $A, $A)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$A, 2))))), + (v2f64 (XXPERMDI (XVCVSPDP (XXMRGHW $A, $A)), + (XVCVSPDP (XXMRGHW $A, $A)), 2))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 0))), + (f64 (fpextend (extractelt v4f32:$B, 0))))), + (v2f64 (XVCVSPDP (XXSLDWI (XXPERMDI $B, $A, 3), + (XXPERMDI $B, $A, 3), 1)))>; + def : Pat<(v2f64 (build_vector (f64 (fpextend (extractelt v4f32:$A, 3))), + (f64 (fpextend (extractelt v4f32:$B, 3))))), + (v2f64 (XVCVSPDP (XXPERMDI $B, $A, 0)))>; + def : Pat; + def : Pat; + def : Pat; + def : Pat; } let Predicates = [HasDirectMove] in { diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index 2111f9ffac42..dff83243e11c 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -558,7 +558,7 @@ ChangeStatus AbstractAttribute::update(Attributor &A) { ChangeStatus IRAttributeManifest::manifestAttrs(Attributor &A, const IRPosition &IRP, const ArrayRef &DeducedAttrs) { - Function *ScopeFn = IRP.getAssociatedFunction(); + Function *ScopeFn = IRP.getAnchorScope(); IRPosition::Kind PK = IRP.getPositionKind(); // In the following some generic code that will manifest attributes in @@ -627,8 +627,7 @@ SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { return; case IRPosition::IRP_ARGUMENT: case IRPosition::IRP_RETURNED: - IRPositions.emplace_back( - IRPosition::function(*IRP.getAssociatedFunction())); + IRPositions.emplace_back(IRPosition::function(*IRP.getAnchorScope())); return; case IRPosition::IRP_CALL_SITE: assert(ICS && "Expected call site!"); @@ -2528,7 +2527,7 @@ struct AAWillReturnImpl : public AAWillReturn { void initialize(Attributor &A) override { AAWillReturn::initialize(A); - Function *F = getAssociatedFunction(); + Function *F = getAnchorScope(); if (!F || !A.isFunctionIPOAmendable(*F) || mayContainUnboundedCycle(*F, A)) indicatePessimisticFixpoint(); } @@ -3113,7 +3112,7 @@ struct AAIsDeadArgument : public AAIsDeadFloating { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - if (!A.isFunctionIPOAmendable(*getAssociatedFunction())) + if (!A.isFunctionIPOAmendable(*getAnchorScope())) indicatePessimisticFixpoint(); } @@ -3273,7 +3272,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - const Function *F = getAssociatedFunction(); + const Function *F = getAnchorScope(); if (F && !F->isDeclaration()) { ToBeExploredFrom.insert(&F->getEntryBlock().front()); assumeLive(A, F->getEntryBlock()); @@ -3283,7 +3282,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AbstractAttribute::getAsStr(). const std::string getAsStr() const override { return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" + - std::to_string(getAssociatedFunction()->size()) + "][#TBEP " + + std::to_string(getAnchorScope()->size()) + "][#TBEP " + std::to_string(ToBeExploredFrom.size()) + "][#KDE " + std::to_string(KnownDeadEnds.size()) + "]"; } @@ -3294,7 +3293,7 @@ struct AAIsDeadFunction : public AAIsDead { "Attempted to manifest an invalid state!"); ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - Function &F = *getAssociatedFunction(); + Function &F = *getAnchorScope(); if (AssumedLiveBlocks.empty()) { A.deleteAfterManifest(F); @@ -3346,7 +3345,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AAIsDead::isAssumedDead(BasicBlock *). bool isAssumedDead(const BasicBlock *BB) const override { - assert(BB->getParent() == getAssociatedFunction() && + assert(BB->getParent() == getAnchorScope() && "BB must be in the same anchor scope function."); if (!getAssumed()) @@ -3361,7 +3360,7 @@ struct AAIsDeadFunction : public AAIsDead { /// See AAIsDead::isAssumed(Instruction *I). bool isAssumedDead(const Instruction *I) const override { - assert(I->getParent()->getParent() == getAssociatedFunction() && + assert(I->getParent()->getParent() == getAnchorScope() && "Instruction must be in the same anchor scope function."); if (!getAssumed()) @@ -3515,7 +3514,7 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { ChangeStatus Change = ChangeStatus::UNCHANGED; LLVM_DEBUG(dbgs() << "[AAIsDead] Live [" << AssumedLiveBlocks.size() << "/" - << getAssociatedFunction()->size() << "] BBs and " + << getAnchorScope()->size() << "] BBs and " << ToBeExploredFrom.size() << " exploration points and " << KnownDeadEnds.size() << " known dead ends\n"); @@ -3595,7 +3594,7 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { // discovered any non-trivial dead end and (2) not ruled unreachable code // dead. if (ToBeExploredFrom.empty() && - getAssociatedFunction()->size() == AssumedLiveBlocks.size() && + getAnchorScope()->size() == AssumedLiveBlocks.size() && llvm::all_of(KnownDeadEnds, [](const Instruction *DeadEndI) { return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0; })) @@ -3935,7 +3934,7 @@ struct AAAlignImpl : AAAlign { takeKnownMaximum(Attr.getValueAsInt()); if (getIRPosition().isFnInterfaceKind() && - (!getAssociatedFunction() || + (!getAnchorScope() || !A.isFunctionIPOAmendable(*getAssociatedFunction()))) indicatePessimisticFixpoint(); } @@ -4736,7 +4735,7 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl { void initialize(Attributor &A) override { AAValueSimplifyImpl::initialize(A); - if (!getAssociatedFunction() || getAssociatedFunction()->isDeclaration()) + if (!getAnchorScope() || getAnchorScope()->isDeclaration()) indicatePessimisticFixpoint(); if (hasAttr({Attribute::InAlloca, Attribute::StructRet, Attribute::Nest}, /* IgnoreSubsumingPositions */ true)) @@ -4980,7 +4979,7 @@ struct AAHeapToStackImpl : public AAHeapToStack { "Attempted to manifest an invalid state!"); ChangeStatus HasChanged = ChangeStatus::UNCHANGED; - Function *F = getAssociatedFunction(); + Function *F = getAnchorScope(); const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); for (Instruction *MallocCall : MallocCalls) { @@ -5057,7 +5056,7 @@ struct AAHeapToStackImpl : public AAHeapToStack { }; ChangeStatus AAHeapToStackImpl::updateImpl(Attributor &A) { - const Function *F = getAssociatedFunction(); + const Function *F = getAnchorScope(); const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F); MustBeExecutedContextExplorer &Explorer = @@ -7655,7 +7654,7 @@ ChangeStatus Attributor::run() { unsigned IterationCounter = 1; - SmallVector ChangedAAs; + SmallVector ChangedAAs; SetVector Worklist, InvalidAAs; Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); @@ -8306,7 +8305,7 @@ void Attributor::initializeInformationCache(Function &F) { switch (I.getOpcode()) { default: assert((!ImmutableCallSite(&I)) && (!isa(&I)) && - "New call site/base instruction type needs to be known int the " + "New call site/base instruction type needs to be known in the " "Attributor."); break; case Instruction::Load: @@ -8635,6 +8634,10 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, // while we identify default attribute opportunities. Attributor A(Functions, InfoCache, CGUpdater, DepRecInterval); + // Note: _Don't_ combine/fuse this loop with the one below because + // when A.identifyDefaultAbstractAttributes() is called for one + // function, it assumes that the information cach has been + // initialized for _all_ functions. for (Function *F : Functions) A.initializeInformationCache(*F); @@ -8661,9 +8664,9 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, A.identifyDefaultAbstractAttributes(*F); } - Module &M = *Functions.front()->getParent(); ChangeStatus Changed = A.run(); - assert(!verifyModule(M, &errs()) && "Module verification failed!"); + assert(!verifyModule(*Functions.front()->getParent(), &errs()) && + "Module verification failed!"); LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() << " functions, result: " << Changed << ".\n"); return Changed == ChangeStatus::CHANGED; diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp index a766513ded03..ca52a618be4c 100644 --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -119,7 +119,7 @@ struct OpenMPOpt { } private: - /// Try to delete parallel regions if possible + /// Try to delete parallel regions if possible. bool deleteParallelRegions() { const unsigned CallbackCalleeOperand = 2; @@ -385,6 +385,32 @@ struct OpenMPOpt { return nullptr; } + /// Returns true if the function declaration \p F matches the runtime + /// function types, that is, return type \p RTFRetType, and argument types + /// \p RTFArgTypes. + static bool declMatchesRTFTypes(Function *F, Type *RTFRetType, + SmallVector &RTFArgTypes) { + // TODO: We should output information to the user (under debug output + // and via remarks). + + if (!F) + return false; + if (F->getReturnType() != RTFRetType) + return false; + if (F->arg_size() != RTFArgTypes.size()) + return false; + + auto RTFTyIt = RTFArgTypes.begin(); + for (Argument &Arg : F->args()) { + if (Arg.getType() != *RTFTyIt) + return false; + + ++RTFTyIt; + } + + return true; + } + /// Helper to initialize all runtime function information for those defined in /// OpenMPKinds.def. void initializeRuntimeFunctions() { @@ -415,26 +441,29 @@ struct OpenMPOpt { #define OMP_RTL(_Enum, _Name, _IsVarArg, _ReturnType, ...) \ { \ - auto &RFI = RFIs[_Enum]; \ - RFI.Kind = _Enum; \ - RFI.Name = _Name; \ - RFI.IsVarArg = _IsVarArg; \ - RFI.ReturnType = _ReturnType; \ - RFI.ArgumentTypes = SmallVector({__VA_ARGS__}); \ - RFI.Declaration = M.getFunction(_Name); \ - unsigned NumUses = CollectUses(RFI); \ - (void)NumUses; \ - LLVM_DEBUG({ \ - dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \ - << " found\n"; \ - if (RFI.Declaration) \ - dbgs() << TAG << "-> got " << NumUses << " uses in " \ - << RFI.UsesMap.size() << " different functions.\n"; \ - }); \ + SmallVector ArgsTypes({__VA_ARGS__}); \ + Function *F = M.getFunction(_Name); \ + if (declMatchesRTFTypes(F, _ReturnType , ArgsTypes)) { \ + auto &RFI = RFIs[_Enum]; \ + RFI.Kind = _Enum; \ + RFI.Name = _Name; \ + RFI.IsVarArg = _IsVarArg; \ + RFI.ReturnType = _ReturnType; \ + RFI.ArgumentTypes = std::move(ArgsTypes); \ + RFI.Declaration = F; \ + unsigned NumUses = CollectUses(RFI); \ + (void)NumUses; \ + LLVM_DEBUG({ \ + dbgs() << TAG << RFI.Name << (RFI.Declaration ? "" : " not") \ + << " found\n"; \ + if (RFI.Declaration) \ + dbgs() << TAG << "-> got " << NumUses << " uses in " \ + << RFI.UsesMap.size() << " different functions.\n"; \ + }); \ + } \ } #include "llvm/Frontend/OpenMP/OMPKinds.def" - // TODO: We should validate the declaration agains the types we expect. // TODO: We should attach the attributes defined in OMPKinds.def. } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index a234779ba24f..b28da9464933 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1343,8 +1343,7 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombiner &IC) { } // ctpop(~x & (x - 1)) -> cttz(x, false) - if (Op0->hasOneUse() && - match(Op0, + if (match(Op0, m_c_And(m_Not(m_Value(X)), m_Add(m_Deferred(X), m_AllOnes())))) { Function *F = Intrinsic::getDeclaration(II.getModule(), Intrinsic::cttz, Ty); diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp index 5bfece010bec..0fc07fb9778d 100644 --- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp +++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -491,7 +491,7 @@ void ConstantHoistingPass::collectConstantCandidates( // take constant variables is lower than `TargetTransformInfo::TCC_Basic`. // So it's safe for us to collect constant candidates from all // IntrinsicInsts. - if (canReplaceOperandWithVariable(Inst, Idx) || isa(Inst)) { + if (canReplaceOperandWithVariable(Inst, Idx)) { collectConstantCandidates(ConstCandMap, Inst, Idx); } } // end of for all operands diff --git a/llvm/lib/Transforms/Scalar/GVNSink.cpp b/llvm/lib/Transforms/Scalar/GVNSink.cpp index 6d0a4975e266..6b9a88d04eda 100644 --- a/llvm/lib/Transforms/Scalar/GVNSink.cpp +++ b/llvm/lib/Transforms/Scalar/GVNSink.cpp @@ -475,6 +475,7 @@ class ValueTable { case Instruction::PtrToInt: case Instruction::IntToPtr: case Instruction::BitCast: + case Instruction::AddrSpaceCast: case Instruction::Select: case Instruction::ExtractElement: case Instruction::InsertElement: diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 1267226dfeb2..d5d9dff75ef0 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -2935,21 +2935,39 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { default: return true; case Instruction::Call: - case Instruction::Invoke: + case Instruction::Invoke: { + ImmutableCallSite CS(I); + // Can't handle inline asm. Skip it. - if (isa(ImmutableCallSite(I).getCalledValue())) - return false; - // Many arithmetic intrinsics have no issue taking a - // variable, however it's hard to distingish these from - // specials such as @llvm.frameaddress that require a constant. - if (isa(I)) + if (CS.isInlineAsm()) return false; // Constant bundle operands may need to retain their constant-ness for // correctness. - if (ImmutableCallSite(I).isBundleOperand(OpIdx)) + if (CS.isBundleOperand(OpIdx)) return false; - return true; + + if (OpIdx < CS.getNumArgOperands()) { + // Some variadic intrinsics require constants in the variadic arguments, + // which currently aren't markable as immarg. + if (CS.isIntrinsic() && OpIdx >= CS.getFunctionType()->getNumParams()) { + // This is known to be OK for stackmap. + return CS.getIntrinsicID() == Intrinsic::experimental_stackmap; + } + + // gcroot is a special case, since it requires a constant argument which + // isn't also required to be a simple ConstantInt. + if (CS.getIntrinsicID() == Intrinsic::gcroot) + return false; + + // Some intrinsic operands are required to be immediates. + return !CS.paramHasAttr(OpIdx, Attribute::ImmArg); + } + + // It is never allowed to replace the call argument to an intrinsic, but it + // may be possible for a call. + return !CS.isIntrinsic(); + } case Instruction::ShuffleVector: // Shufflevector masks are constant. return OpIdx != 2; diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 36358ef34fd0..9a39df4c35f8 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -1445,6 +1445,13 @@ static bool isLifeTimeMarker(const Instruction *I) { return false; } +// TODO: Refine this. This should avoid cases like turning constant memcpy sizes +// into variables. +static bool replacingOperandWithVariableIsCheap(const Instruction *I, + int OpIdx) { + return !isa(I); +} + // All instructions in Insts belong to different blocks that all unconditionally // branch to a common successor. Analyze each instruction and return true if it // would be possible to sink them into their successor, creating one common @@ -1522,7 +1529,8 @@ static bool canSinkInstructions( return false; for (unsigned OI = 0, OE = I0->getNumOperands(); OI != OE; ++OI) { - if (I0->getOperand(OI)->getType()->isTokenTy()) + Value *Op = I0->getOperand(OI); + if (Op->getType()->isTokenTy()) // Don't touch any operand of token type. return false; @@ -1531,7 +1539,8 @@ static bool canSinkInstructions( return I->getOperand(OI) == I0->getOperand(OI); }; if (!all_of(Insts, SameAsI0)) { - if (!canReplaceOperandWithVariable(I0, OI)) + if ((isa(Op) && !replacingOperandWithVariableIsCheap(I0, OI)) || + !canReplaceOperandWithVariable(I0, OI)) // We can't create a PHI from this GEP. return false; // Don't create indirect calls! The called value is the final operand. diff --git a/llvm/test/CodeGen/PowerPC/atomics-fences.ll b/llvm/test/CodeGen/PowerPC/atomics-fences.ll index 3fea72150000..8fe366307fd1 100644 --- a/llvm/test/CodeGen/PowerPC/atomics-fences.ll +++ b/llvm/test/CodeGen/PowerPC/atomics-fences.ll @@ -1,6 +1,7 @@ ; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc64-unknown-linux-gnu -verify-machineinstrs | FileCheck %s ; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -mcpu=440 | FileCheck %s --check-prefix=PPC440 +; RUN: llc < %s -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 | FileCheck %s --check-prefix=PPC440 ; Fences define void @fence_acquire() { diff --git a/llvm/test/CodeGen/PowerPC/build-vector-tests.ll b/llvm/test/CodeGen/PowerPC/build-vector-tests.ll index 4e096b1c5c03..469cef01094b 100644 --- a/llvm/test/CodeGen/PowerPC/build-vector-tests.ll +++ b/llvm/test/CodeGen/PowerPC/build-vector-tests.ll @@ -6123,3 +6123,412 @@ entry: %splat.splat = shufflevector <2 x i64> %splat.splatinsert, <2 x i64> undef, <2 x i32> zeroinitializer ret <2 x i64> %splat.splat } + +; Some additional patterns that come up in real code. +define dso_local <2 x double> @sint_to_fp_widen02(<4 x i32> %a) { +; P9BE-LABEL: sint_to_fp_widen02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvsxwdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: sint_to_fp_widen02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvsxwdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: sint_to_fp_widen02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvsxwdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: sint_to_fp_widen02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvsxwdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 0 + %conv = sitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 2 + %conv2 = sitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @sint_to_fp_widen13(<4 x i32> %a) { +; P9BE-LABEL: sint_to_fp_widen13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvsxwdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: sint_to_fp_widen13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvsxwdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: sint_to_fp_widen13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvsxwdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: sint_to_fp_widen13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvsxwdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 1 + %conv = sitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 3 + %conv2 = sitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @uint_to_fp_widen02(<4 x i32> %a) { +; P9BE-LABEL: uint_to_fp_widen02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvuxwdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: uint_to_fp_widen02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvuxwdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: uint_to_fp_widen02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvuxwdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: uint_to_fp_widen02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvuxwdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 0 + %conv = uitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 2 + %conv2 = uitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @uint_to_fp_widen13(<4 x i32> %a) { +; P9BE-LABEL: uint_to_fp_widen13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvuxwdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: uint_to_fp_widen13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvuxwdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: uint_to_fp_widen13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvuxwdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: uint_to_fp_widen13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvuxwdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x i32> %a, i32 1 + %conv = uitofp i32 %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x i32> %a, i32 3 + %conv2 = uitofp i32 %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend01(<4 x float> %a) { +; P9BE-LABEL: fp_extend01: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend01: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrglw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend01: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend01: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrglw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 1 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend10(<4 x float> %a) { +; P9BE-LABEL: fp_extend10: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp vs0, vs0 +; P9BE-NEXT: xxswapd v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend10: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrglw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp vs0, vs0 +; P9LE-NEXT: xxswapd v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend10: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp vs0, vs0 +; P8BE-NEXT: xxswapd v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend10: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrglw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp vs0, vs0 +; P8LE-NEXT: xxswapd v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 1 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 0 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend02(<4 x float> %a) { +; P9BE-LABEL: fp_extend02: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xvcvspdp v2, v2 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend02: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend02: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xvcvspdp v2, v2 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend02: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxsldwi vs0, v2, v2, 1 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 2 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend13(<4 x float> %a) { +; P9BE-LABEL: fp_extend13: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend13: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xvcvspdp v2, v2 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend13: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxsldwi vs0, v2, v2, 3 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend13: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xvcvspdp v2, v2 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 1 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend23(<4 x float> %a) { +; P9BE-LABEL: fp_extend23: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrglw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend23: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend23: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrglw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend23: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 2 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend32(<4 x float> %a) { +; P9BE-LABEL: fp_extend32: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrglw vs0, v2, v2 +; P9BE-NEXT: xvcvspdp vs0, vs0 +; P9BE-NEXT: xxswapd v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend32: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghw vs0, v2, v2 +; P9LE-NEXT: xvcvspdp vs0, vs0 +; P9LE-NEXT: xxswapd v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend32: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrglw vs0, v2, v2 +; P8BE-NEXT: xvcvspdp vs0, vs0 +; P8BE-NEXT: xxswapd v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend32: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghw vs0, v2, v2 +; P8LE-NEXT: xvcvspdp vs0, vs0 +; P8LE-NEXT: xxswapd v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 3 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %a, i32 2 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend_two00(<4 x float> %a, <4 x float> %b) { +; P9BE-LABEL: fp_extend_two00: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrghd vs0, v2, v3 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend_two00: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrgld vs0, v3, v2 +; P9LE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend_two00: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrghd vs0, v2, v3 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend_two00: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrgld vs0, v3, v2 +; P8LE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 0 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %b, i32 0 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} + +define dso_local <2 x double> @fp_extend_two33(<4 x float> %a, <4 x float> %b) { +; P9BE-LABEL: fp_extend_two33: +; P9BE: # %bb.0: # %entry +; P9BE-NEXT: xxmrgld vs0, v2, v3 +; P9BE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P9BE-NEXT: xvcvspdp v2, vs0 +; P9BE-NEXT: blr +; +; P9LE-LABEL: fp_extend_two33: +; P9LE: # %bb.0: # %entry +; P9LE-NEXT: xxmrghd vs0, v3, v2 +; P9LE-NEXT: xvcvspdp v2, vs0 +; P9LE-NEXT: blr +; +; P8BE-LABEL: fp_extend_two33: +; P8BE: # %bb.0: # %entry +; P8BE-NEXT: xxmrgld vs0, v2, v3 +; P8BE-NEXT: xxsldwi vs0, vs0, vs0, 1 +; P8BE-NEXT: xvcvspdp v2, vs0 +; P8BE-NEXT: blr +; +; P8LE-LABEL: fp_extend_two33: +; P8LE: # %bb.0: # %entry +; P8LE-NEXT: xxmrghd vs0, v3, v2 +; P8LE-NEXT: xvcvspdp v2, vs0 +; P8LE-NEXT: blr +entry: + %vecext = extractelement <4 x float> %a, i32 3 + %conv = fpext float %vecext to double + %vecinit = insertelement <2 x double> undef, double %conv, i32 0 + %vecext1 = extractelement <4 x float> %b, i32 3 + %conv2 = fpext float %vecext1 to double + %vecinit3 = insertelement <2 x double> %vecinit, double %conv2, i32 1 + ret <2 x double> %vecinit3 +} diff --git a/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll b/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll index f7727d6f4ea1..1dc40edf7146 100644 --- a/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll +++ b/llvm/test/CodeGen/PowerPC/reduce_scalarization02.ll @@ -47,33 +47,23 @@ define dso_local void @test2(<16 x float>* nocapture readonly %a, <2 x double>* ; CHECK-LABEL: test2: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: lxv vs0, 0(r3) -; CHECK-NEXT: xxsldwi vs1, vs0, vs0, 1 -; CHECK-NEXT: xscvspdpn f2, vs0 -; CHECK-NEXT: xxsldwi vs3, vs0, vs0, 3 -; CHECK-NEXT: xxswapd vs0, vs0 -; CHECK-NEXT: xscvspdpn f1, vs1 -; CHECK-NEXT: xscvspdpn f3, vs3 -; CHECK-NEXT: xscvspdpn f0, vs0 -; CHECK-NEXT: xxmrghd vs0, vs0, vs3 -; CHECK-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-NEXT: stxv vs0, 0(r4) -; CHECK-NEXT: stxv vs1, 0(r5) +; CHECK-NEXT: xxmrglw vs1, vs0, vs0 +; CHECK-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-NEXT: xvcvspdp vs1, vs1 +; CHECK-NEXT: xvcvspdp vs0, vs0 +; CHECK-NEXT: stxv vs1, 0(r4) +; CHECK-NEXT: stxv vs0, 0(r5) ; CHECK-NEXT: blr ; ; CHECK-BE-LABEL: test2: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: lxv vs0, 0(r3) -; CHECK-BE-NEXT: xxswapd vs1, vs0 -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs3, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: stxv vs0, 0(r4) -; CHECK-BE-NEXT: stxv vs1, 0(r5) +; CHECK-BE-NEXT: xxmrghw vs1, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: stxv vs1, 0(r4) +; CHECK-BE-NEXT: stxv vs0, 0(r5) ; CHECK-BE-NEXT: blr entry: %0 = load <16 x float>, <16 x float>* %a, align 16 diff --git a/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll b/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll index cf4a6d636207..d355dcd08b0f 100644 --- a/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll +++ b/llvm/test/CodeGen/PowerPC/vec_conv_fp32_to_i64_elts.ll @@ -14,10 +14,8 @@ define <2 x i64> @test2elt(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P8: # %bb.0: # %entry ; CHECK-P8-NEXT: mtvsrd f0, r3 ; CHECK-P8-NEXT: xxswapd v2, vs0 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: blr ; @@ -25,20 +23,16 @@ define <2 x i64> @test2elt(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P9: # %bb.0: # %entry ; CHECK-P9-NEXT: mtvsrd f0, r3 ; CHECK-P9-NEXT: xxswapd v2, vs0 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test2elt: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: mtvsrd f0, r3 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-BE-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-BE-NEXT: blr entry: @@ -50,16 +44,11 @@ entry: define void @test4elt(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> %a) local_unnamed_addr #1 { ; CHECK-P8-LABEL: test4elt: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 ; CHECK-P8-NEXT: li r4, 16 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 ; CHECK-P8-NEXT: xxswapd vs1, v2 @@ -70,36 +59,26 @@ define void @test4elt(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> ; ; CHECK-P9-LABEL: test4elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P9-NEXT: xxswapd vs1, v2 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxsldwi vs2, v2, v2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, v2 -; CHECK-P9-NEXT: xxmrghd vs1, vs1, vs2 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 ; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test4elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 1 -; CHECK-BE-NEXT: xscvspdpn f0, v2 -; CHECK-BE-NEXT: xxswapd vs2, v2 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs1 -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 +; CHECK-BE-NEXT: xxmrghw vs0, v2, v2 +; CHECK-BE-NEXT: xxmrglw vs1, v2, v2 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs2, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: blr entry: %0 = fptoui <4 x float> %a to <4 x i64> @@ -115,31 +94,21 @@ define void @test8elt(<8 x i64>* noalias nocapture sret %agg.result, <8 x float> ; CHECK-P8-NEXT: li r6, 32 ; CHECK-P8-NEXT: lvx v2, r4, r5 ; CHECK-P8-NEXT: li r4, 48 -; CHECK-P8-NEXT: xxsldwi vs5, v3, v3, 3 -; CHECK-P8-NEXT: xxswapd vs6, v3 -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xxsldwi vs7, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xscvspdpn f6, vs6 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 -; CHECK-P8-NEXT: xxmrghd vs2, vs6, vs5 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs3, v3, v3 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 -; CHECK-P8-NEXT: xxmrghd vs3, vs4, vs7 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs3 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs1, v2 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v5 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r6 @@ -149,65 +118,45 @@ define void @test8elt(<8 x i64>* noalias nocapture sret %agg.result, <8 x float> ; ; CHECK-P9-LABEL: test8elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: lxv vs2, 16(r4) -; CHECK-P9-NEXT: xxmrghd vs0, vs3, vs0 +; CHECK-P9-NEXT: lxv vs0, 16(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs3, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xxsldwi vs3, vs2, vs2, 3 -; CHECK-P9-NEXT: xxswapd vs4, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: xxmrghd vs3, vs4, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-P9-NEXT: xxmrghd vs2, vs4, vs2 -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 48(r3) ; CHECK-P9-NEXT: stxv vs3, 32(r3) -; CHECK-P9-NEXT: stxv vs2, 48(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test8elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs1, 0(r4) -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 1 -; CHECK-BE-NEXT: xscvspdpn f2, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 ; CHECK-BE-NEXT: lxv vs0, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs3 -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 3 -; CHECK-BE-NEXT: xxswapd vs1, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs4 -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs4 +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs3, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: stxv vs3, 32(r3) ; CHECK-BE-NEXT: stxv vs0, 48(r3) +; CHECK-BE-NEXT: stxv vs3, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: @@ -220,70 +169,50 @@ entry: define void @test16elt(<16 x i64>* noalias nocapture sret %agg.result, <16 x float>* nocapture readonly) local_unnamed_addr #2 { ; CHECK-P8-LABEL: test16elt: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r7, 48 +; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r6, 32 -; CHECK-P8-NEXT: lvx v4, 0, r4 ; CHECK-P8-NEXT: li r8, 64 -; CHECK-P8-NEXT: lvx v5, r4, r5 -; CHECK-P8-NEXT: lvx v3, r4, r7 -; CHECK-P8-NEXT: lvx v2, r4, r6 +; CHECK-P8-NEXT: lvx v4, r4, r7 +; CHECK-P8-NEXT: lvx v2, r4, r5 +; CHECK-P8-NEXT: lvx v3, r4, r6 +; CHECK-P8-NEXT: xxmrghw vs3, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs5, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: lvx v2, 0, r4 ; CHECK-P8-NEXT: li r4, 112 -; CHECK-P8-NEXT: xxsldwi vs13, v4, v4, 3 -; CHECK-P8-NEXT: xscvspdpn f6, v4 -; CHECK-P8-NEXT: xxsldwi vs1, v5, v5, 3 -; CHECK-P8-NEXT: xxswapd vs3, v5 -; CHECK-P8-NEXT: xxsldwi vs9, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xxsldwi vs5, v5, v5, 1 -; CHECK-P8-NEXT: xxsldwi vs10, v3, v3, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxswapd vs11, v3 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxsldwi vs7, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f9, vs9 -; CHECK-P8-NEXT: xxswapd vs8, v2 -; CHECK-P8-NEXT: xscvspdpn f0, v5 -; CHECK-P8-NEXT: xxsldwi vs12, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xxswapd v2, v4 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xxsldwi v3, v4, v4, 1 -; CHECK-P8-NEXT: xscvspdpn f10, vs10 -; CHECK-P8-NEXT: xscvspdpn f11, vs11 -; CHECK-P8-NEXT: xxmrghd vs1, vs3, vs1 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs4, vs4, vs9 -; CHECK-P8-NEXT: xscvspdpn f8, vs8 -; CHECK-P8-NEXT: xscvspdpn f12, vs12 -; CHECK-P8-NEXT: xscvspdpn f13, vs13 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-P8-NEXT: xscvspdpn f3, v2 -; CHECK-P8-NEXT: xscvspdpn f9, v3 -; CHECK-P8-NEXT: xxmrghd vs5, vs11, vs10 -; CHECK-P8-NEXT: xvcvdpuxds v3, vs4 -; CHECK-P8-NEXT: xvcvdpuxds v2, vs1 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs12 -; CHECK-P8-NEXT: xxmrghd vs2, vs8, vs7 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs0 -; CHECK-P8-NEXT: xxmrghd vs0, vs3, vs13 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs4, v3, v3 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xxmrglw vs6, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs7, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs5, vs5 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs4, vs4 +; CHECK-P8-NEXT: xvcvspdp vs6, vs6 +; CHECK-P8-NEXT: xvcvspdp vs7, vs7 +; CHECK-P8-NEXT: xvcvdpuxds v3, vs3 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs5 -; CHECK-P8-NEXT: xxmrghd vs3, vs6, vs9 -; CHECK-P8-NEXT: xvcvdpuxds v0, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v0, vs4 ; CHECK-P8-NEXT: xvcvdpuxds v1, vs2 -; CHECK-P8-NEXT: xvcvdpuxds v6, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v6, vs6 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xvcvdpuxds v7, vs3 -; CHECK-P8-NEXT: xxswapd vs4, v2 -; CHECK-P8-NEXT: xxswapd vs3, v4 +; CHECK-P8-NEXT: xvcvdpuxds v7, vs7 ; CHECK-P8-NEXT: xxswapd vs1, v5 +; CHECK-P8-NEXT: xxswapd vs4, v2 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: li r4, 96 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v0 -; CHECK-P8-NEXT: xxswapd vs0, v1 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r4 -; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: li r4, 80 +; CHECK-P8-NEXT: xxswapd vs0, v1 +; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: xxswapd vs1, v7 ; CHECK-P8-NEXT: stxvd2x vs2, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r8 @@ -295,122 +224,82 @@ define void @test16elt(<16 x i64>* noalias nocapture sret %agg.result, <16 x flo ; ; CHECK-P9-LABEL: test16elt: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs4, 16(r4) -; CHECK-P9-NEXT: xxsldwi vs5, vs4, vs4, 3 -; CHECK-P9-NEXT: xxswapd vs6, vs4 -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs5, vs6, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs4 -; CHECK-P9-NEXT: xxsldwi vs4, vs4, vs4, 1 -; CHECK-P9-NEXT: lxv vs3, 32(r4) -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxswapd vs7, vs3 -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs0, vs2, vs0 -; CHECK-P9-NEXT: xxmrghd vs4, vs6, vs4 -; CHECK-P9-NEXT: xxsldwi vs6, vs3, vs3, 3 +; CHECK-P9-NEXT: lxv vs0, 48(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: lxv vs3, 16(r4) +; CHECK-P9-NEXT: lxv vs5, 32(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs4, vs3, vs3 +; CHECK-P9-NEXT: xxmrghw vs3, vs3, vs3 +; CHECK-P9-NEXT: xxmrglw vs6, vs5, vs5 +; CHECK-P9-NEXT: xxmrghw vs5, vs5, vs5 +; CHECK-P9-NEXT: xxmrglw vs7, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs4, vs4 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs6, vs6 +; CHECK-P9-NEXT: xvcvspdp vs5, vs5 +; CHECK-P9-NEXT: xvcvspdp vs7, vs7 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs6, vs7, vs6 -; CHECK-P9-NEXT: xscvspdpn f7, vs3 -; CHECK-P9-NEXT: xxsldwi vs3, vs3, vs3, 1 -; CHECK-P9-NEXT: lxv vs2, 48(r4) -; CHECK-P9-NEXT: xxswapd vs8, vs2 -; CHECK-P9-NEXT: xscvspdpn f8, vs8 ; CHECK-P9-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xxmrghd vs3, vs7, vs3 -; CHECK-P9-NEXT: xxsldwi vs7, vs2, vs2, 3 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 -; CHECK-P9-NEXT: stxv vs6, 64(r3) -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xxmrghd vs7, vs8, vs7 -; CHECK-P9-NEXT: xscvspdpn f8, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs2, vs8, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-P9-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-P9-NEXT: stxv vs3, 80(r3) -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 112(r3) ; CHECK-P9-NEXT: stxv vs7, 96(r3) -; CHECK-P9-NEXT: stxv vs2, 112(r3) -; CHECK-P9-NEXT: stxv vs4, 48(r3) -; CHECK-P9-NEXT: stxv vs5, 32(r3) -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs5, 80(r3) +; CHECK-P9-NEXT: stxv vs6, 64(r3) +; CHECK-P9-NEXT: stxv vs3, 48(r3) +; CHECK-P9-NEXT: stxv vs4, 32(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test16elt: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs0, 0(r4) -; CHECK-BE-NEXT: lxv vs4, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs5, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f5, vs5 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 1 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-BE-NEXT: xscvspdpn f5, vs4 -; CHECK-BE-NEXT: lxv vs3, 32(r4) -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 1 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xxmrghd vs5, vs5, vs6 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 3 -; CHECK-BE-NEXT: xxswapd vs4, vs4 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: lxv vs2, 48(r4) -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 1 +; CHECK-BE-NEXT: lxv vs0, 48(r4) +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: lxv vs3, 16(r4) +; CHECK-BE-NEXT: lxv vs5, 32(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs4, vs3, vs3 +; CHECK-BE-NEXT: xxmrglw vs3, vs3, vs3 +; CHECK-BE-NEXT: xxmrghw vs6, vs5, vs5 +; CHECK-BE-NEXT: xxmrglw vs5, vs5, vs5 +; CHECK-BE-NEXT: xxmrghw vs7, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs4, vs4 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs6, vs6 +; CHECK-BE-NEXT: xvcvspdp vs5, vs5 +; CHECK-BE-NEXT: xvcvspdp vs7, vs7 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xxmrghd vs4, vs4, vs6 -; CHECK-BE-NEXT: xscvspdpn f6, vs3 -; CHECK-BE-NEXT: stxv vs0, 16(r3) -; CHECK-BE-NEXT: xxmrghd vs6, vs6, vs7 -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 3 -; CHECK-BE-NEXT: xxswapd vs3, vs3 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs7 -; CHECK-BE-NEXT: xscvspdpn f7, vs2 -; CHECK-BE-NEXT: xxmrghd vs7, vs7, vs8 -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 3 -; CHECK-BE-NEXT: xxswapd vs2, vs2 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs8 -; CHECK-BE-NEXT: stxv vs5, 32(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-BE-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-BE-NEXT: stxv vs3, 80(r3) +; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-BE-NEXT: stxv vs0, 112(r3) ; CHECK-BE-NEXT: stxv vs7, 96(r3) -; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 -; CHECK-BE-NEXT: stxv vs2, 112(r3) +; CHECK-BE-NEXT: stxv vs5, 80(r3) ; CHECK-BE-NEXT: stxv vs6, 64(r3) -; CHECK-BE-NEXT: stxv vs4, 48(r3) -; CHECK-BE-NEXT: stxv vs1, 0(r3) +; CHECK-BE-NEXT: stxv vs3, 48(r3) +; CHECK-BE-NEXT: stxv vs4, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: %a = load <16 x float>, <16 x float>* %0, align 64 @@ -424,10 +313,8 @@ define <2 x i64> @test2elt_signed(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P8: # %bb.0: # %entry ; CHECK-P8-NEXT: mtvsrd f0, r3 ; CHECK-P8-NEXT: xxswapd v2, vs0 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: blr ; @@ -435,20 +322,16 @@ define <2 x i64> @test2elt_signed(i64 %a.coerce) local_unnamed_addr #0 { ; CHECK-P9: # %bb.0: # %entry ; CHECK-P9-NEXT: mtvsrd f0, r3 ; CHECK-P9-NEXT: xxswapd v2, vs0 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs0, vs0, vs1 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test2elt_signed: ; CHECK-BE: # %bb.0: # %entry ; CHECK-BE-NEXT: mtvsrd f0, r3 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-BE-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-BE-NEXT: blr entry: @@ -460,16 +343,11 @@ entry: define void @test4elt_signed(<4 x i64>* noalias nocapture sret %agg.result, <4 x float> %a) local_unnamed_addr #1 { ; CHECK-P8-LABEL: test4elt_signed: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 ; CHECK-P8-NEXT: li r4, 16 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 ; CHECK-P8-NEXT: xxswapd vs1, v2 @@ -480,36 +358,26 @@ define void @test4elt_signed(<4 x i64>* noalias nocapture sret %agg.result, <4 x ; ; CHECK-P9-LABEL: test4elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P9-NEXT: xxswapd vs1, v2 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxsldwi vs2, v2, v2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, v2 -; CHECK-P9-NEXT: xxmrghd vs1, vs1, vs2 +; CHECK-P9-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P9-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 ; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs0, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test4elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 1 -; CHECK-BE-NEXT: xscvspdpn f0, v2 -; CHECK-BE-NEXT: xxswapd vs2, v2 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs1 -; CHECK-BE-NEXT: xxsldwi vs1, v2, v2, 3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 +; CHECK-BE-NEXT: xxmrghw vs0, v2, v2 +; CHECK-BE-NEXT: xxmrglw vs1, v2, v2 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xxmrghd vs1, vs2, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs0, 0(r3) ; CHECK-BE-NEXT: blr entry: %0 = fptoui <4 x float> %a to <4 x i64> @@ -525,31 +393,21 @@ define void @test8elt_signed(<8 x i64>* noalias nocapture sret %agg.result, <8 x ; CHECK-P8-NEXT: li r6, 32 ; CHECK-P8-NEXT: lvx v2, r4, r5 ; CHECK-P8-NEXT: li r4, 48 -; CHECK-P8-NEXT: xxsldwi vs5, v3, v3, 3 -; CHECK-P8-NEXT: xxswapd vs6, v3 -; CHECK-P8-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-P8-NEXT: xxswapd vs1, v2 -; CHECK-P8-NEXT: xxsldwi vs3, v2, v2, 1 -; CHECK-P8-NEXT: xxsldwi vs7, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xscvspdpn f0, vs0 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xscvspdpn f6, vs6 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs0, vs1, vs0 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs3 -; CHECK-P8-NEXT: xxmrghd vs2, vs6, vs5 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs3, v3, v3 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 -; CHECK-P8-NEXT: xxmrghd vs3, vs4, vs7 ; CHECK-P8-NEXT: xvcvdpuxds v3, vs1 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs2 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs3 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs1, v2 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v5 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r6 @@ -559,65 +417,45 @@ define void @test8elt_signed(<8 x i64>* noalias nocapture sret %agg.result, <8 x ; ; CHECK-P9-LABEL: test8elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: lxv vs2, 16(r4) -; CHECK-P9-NEXT: xxmrghd vs0, vs3, vs0 +; CHECK-P9-NEXT: lxv vs0, 16(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs3, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xxsldwi vs3, vs2, vs2, 3 -; CHECK-P9-NEXT: xxswapd vs4, vs2 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: xxmrghd vs3, vs4, vs3 -; CHECK-P9-NEXT: xscvspdpn f4, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-P9-NEXT: xxmrghd vs2, vs4, vs2 -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 48(r3) ; CHECK-P9-NEXT: stxv vs3, 32(r3) -; CHECK-P9-NEXT: stxv vs2, 48(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test8elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs1, 0(r4) -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 1 -; CHECK-BE-NEXT: xscvspdpn f2, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 ; CHECK-BE-NEXT: lxv vs0, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs3 -; CHECK-BE-NEXT: xxsldwi vs3, vs1, vs1, 3 -; CHECK-BE-NEXT: xxswapd vs1, vs1 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xscvspdpn f1, vs1 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs3 -; CHECK-BE-NEXT: xscvspdpn f3, vs0 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs4 -; CHECK-BE-NEXT: xxsldwi vs4, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs4 +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs3, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 ; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 -; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: stxv vs3, 32(r3) ; CHECK-BE-NEXT: stxv vs0, 48(r3) +; CHECK-BE-NEXT: stxv vs3, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) ; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: @@ -630,70 +468,50 @@ entry: define void @test16elt_signed(<16 x i64>* noalias nocapture sret %agg.result, <16 x float>* nocapture readonly) local_unnamed_addr #2 { ; CHECK-P8-LABEL: test16elt_signed: ; CHECK-P8: # %bb.0: # %entry -; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r7, 48 +; CHECK-P8-NEXT: li r5, 16 ; CHECK-P8-NEXT: li r6, 32 -; CHECK-P8-NEXT: lvx v4, 0, r4 ; CHECK-P8-NEXT: li r8, 64 -; CHECK-P8-NEXT: lvx v5, r4, r5 -; CHECK-P8-NEXT: lvx v3, r4, r7 -; CHECK-P8-NEXT: lvx v2, r4, r6 +; CHECK-P8-NEXT: lvx v4, r4, r7 +; CHECK-P8-NEXT: lvx v2, r4, r5 +; CHECK-P8-NEXT: lvx v3, r4, r6 +; CHECK-P8-NEXT: xxmrghw vs3, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs5, v4, v4 +; CHECK-P8-NEXT: xxmrglw vs0, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs1, v2, v2 +; CHECK-P8-NEXT: lvx v2, 0, r4 ; CHECK-P8-NEXT: li r4, 112 -; CHECK-P8-NEXT: xxsldwi vs13, v4, v4, 3 -; CHECK-P8-NEXT: xscvspdpn f6, v4 -; CHECK-P8-NEXT: xxsldwi vs1, v5, v5, 3 -; CHECK-P8-NEXT: xxswapd vs3, v5 -; CHECK-P8-NEXT: xxsldwi vs9, v3, v3, 1 -; CHECK-P8-NEXT: xscvspdpn f4, v3 -; CHECK-P8-NEXT: xxsldwi vs5, v5, v5, 1 -; CHECK-P8-NEXT: xxsldwi vs10, v3, v3, 3 -; CHECK-P8-NEXT: xscvspdpn f1, vs1 -; CHECK-P8-NEXT: xxswapd vs11, v3 -; CHECK-P8-NEXT: xscvspdpn f3, vs3 -; CHECK-P8-NEXT: xxsldwi vs7, v2, v2, 3 -; CHECK-P8-NEXT: xscvspdpn f9, vs9 -; CHECK-P8-NEXT: xxswapd vs8, v2 -; CHECK-P8-NEXT: xscvspdpn f0, v5 -; CHECK-P8-NEXT: xxsldwi vs12, v2, v2, 1 -; CHECK-P8-NEXT: xscvspdpn f2, v2 -; CHECK-P8-NEXT: xxswapd v2, v4 -; CHECK-P8-NEXT: xscvspdpn f5, vs5 -; CHECK-P8-NEXT: xxsldwi v3, v4, v4, 1 -; CHECK-P8-NEXT: xscvspdpn f10, vs10 -; CHECK-P8-NEXT: xscvspdpn f11, vs11 -; CHECK-P8-NEXT: xxmrghd vs1, vs3, vs1 -; CHECK-P8-NEXT: xscvspdpn f7, vs7 -; CHECK-P8-NEXT: xxmrghd vs4, vs4, vs9 -; CHECK-P8-NEXT: xscvspdpn f8, vs8 -; CHECK-P8-NEXT: xscvspdpn f12, vs12 -; CHECK-P8-NEXT: xscvspdpn f13, vs13 -; CHECK-P8-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-P8-NEXT: xscvspdpn f3, v2 -; CHECK-P8-NEXT: xscvspdpn f9, v3 -; CHECK-P8-NEXT: xxmrghd vs5, vs11, vs10 -; CHECK-P8-NEXT: xvcvdpuxds v3, vs4 -; CHECK-P8-NEXT: xvcvdpuxds v2, vs1 -; CHECK-P8-NEXT: xxmrghd vs1, vs2, vs12 -; CHECK-P8-NEXT: xxmrghd vs2, vs8, vs7 -; CHECK-P8-NEXT: xvcvdpuxds v4, vs0 -; CHECK-P8-NEXT: xxmrghd vs0, vs3, vs13 +; CHECK-P8-NEXT: xxmrglw vs2, v3, v3 +; CHECK-P8-NEXT: xxmrghw vs4, v3, v3 +; CHECK-P8-NEXT: xvcvspdp vs3, vs3 +; CHECK-P8-NEXT: xxmrglw vs6, v2, v2 +; CHECK-P8-NEXT: xxmrghw vs7, v2, v2 +; CHECK-P8-NEXT: xvcvspdp vs5, vs5 +; CHECK-P8-NEXT: xvcvspdp vs0, vs0 +; CHECK-P8-NEXT: xvcvspdp vs1, vs1 +; CHECK-P8-NEXT: xvcvspdp vs2, vs2 +; CHECK-P8-NEXT: xvcvspdp vs4, vs4 +; CHECK-P8-NEXT: xvcvspdp vs6, vs6 +; CHECK-P8-NEXT: xvcvspdp vs7, vs7 +; CHECK-P8-NEXT: xvcvdpuxds v3, vs3 ; CHECK-P8-NEXT: xvcvdpuxds v5, vs5 -; CHECK-P8-NEXT: xxmrghd vs3, vs6, vs9 -; CHECK-P8-NEXT: xvcvdpuxds v0, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v2, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v4, vs1 +; CHECK-P8-NEXT: xvcvdpuxds v0, vs4 ; CHECK-P8-NEXT: xvcvdpuxds v1, vs2 -; CHECK-P8-NEXT: xvcvdpuxds v6, vs0 +; CHECK-P8-NEXT: xvcvdpuxds v6, vs6 ; CHECK-P8-NEXT: xxswapd vs0, v3 -; CHECK-P8-NEXT: xvcvdpuxds v7, vs3 -; CHECK-P8-NEXT: xxswapd vs4, v2 -; CHECK-P8-NEXT: xxswapd vs3, v4 +; CHECK-P8-NEXT: xvcvdpuxds v7, vs7 ; CHECK-P8-NEXT: xxswapd vs1, v5 +; CHECK-P8-NEXT: xxswapd vs4, v2 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r4 ; CHECK-P8-NEXT: li r4, 96 +; CHECK-P8-NEXT: xxswapd vs3, v4 ; CHECK-P8-NEXT: xxswapd vs2, v0 -; CHECK-P8-NEXT: xxswapd vs0, v1 ; CHECK-P8-NEXT: stxvd2x vs1, r3, r4 -; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: li r4, 80 +; CHECK-P8-NEXT: xxswapd vs0, v1 +; CHECK-P8-NEXT: xxswapd vs5, v6 ; CHECK-P8-NEXT: xxswapd vs1, v7 ; CHECK-P8-NEXT: stxvd2x vs2, r3, r4 ; CHECK-P8-NEXT: stxvd2x vs0, r3, r8 @@ -705,122 +523,82 @@ define void @test16elt_signed(<16 x i64>* noalias nocapture sret %agg.result, <1 ; ; CHECK-P9-LABEL: test16elt_signed: ; CHECK-P9: # %bb.0: # %entry -; CHECK-P9-NEXT: lxv vs4, 16(r4) -; CHECK-P9-NEXT: xxsldwi vs5, vs4, vs4, 3 -; CHECK-P9-NEXT: xxswapd vs6, vs4 -; CHECK-P9-NEXT: lxv vs0, 0(r4) -; CHECK-P9-NEXT: xxsldwi vs1, vs0, vs0, 3 -; CHECK-P9-NEXT: xxswapd vs2, vs0 -; CHECK-P9-NEXT: xscvspdpn f5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs5, vs6, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs4 -; CHECK-P9-NEXT: xxsldwi vs4, vs4, vs4, 1 -; CHECK-P9-NEXT: lxv vs3, 32(r4) -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxswapd vs7, vs3 -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xscvspdpn f4, vs4 -; CHECK-P9-NEXT: xscvspdpn f1, vs1 -; CHECK-P9-NEXT: xxmrghd vs1, vs2, vs1 -; CHECK-P9-NEXT: xscvspdpn f2, vs0 -; CHECK-P9-NEXT: xxsldwi vs0, vs0, vs0, 1 -; CHECK-P9-NEXT: xscvspdpn f0, vs0 -; CHECK-P9-NEXT: xxmrghd vs0, vs2, vs0 -; CHECK-P9-NEXT: xxmrghd vs4, vs6, vs4 -; CHECK-P9-NEXT: xxsldwi vs6, vs3, vs3, 3 +; CHECK-P9-NEXT: lxv vs0, 48(r4) +; CHECK-P9-NEXT: lxv vs1, 0(r4) +; CHECK-P9-NEXT: lxv vs3, 16(r4) +; CHECK-P9-NEXT: lxv vs5, 32(r4) +; CHECK-P9-NEXT: xxmrglw vs2, vs1, vs1 +; CHECK-P9-NEXT: xxmrghw vs1, vs1, vs1 +; CHECK-P9-NEXT: xxmrglw vs4, vs3, vs3 +; CHECK-P9-NEXT: xxmrghw vs3, vs3, vs3 +; CHECK-P9-NEXT: xxmrglw vs6, vs5, vs5 +; CHECK-P9-NEXT: xxmrghw vs5, vs5, vs5 +; CHECK-P9-NEXT: xxmrglw vs7, vs0, vs0 +; CHECK-P9-NEXT: xxmrghw vs0, vs0, vs0 +; CHECK-P9-NEXT: xvcvspdp vs2, vs2 +; CHECK-P9-NEXT: xvcvspdp vs1, vs1 +; CHECK-P9-NEXT: xvcvspdp vs4, vs4 +; CHECK-P9-NEXT: xvcvspdp vs3, vs3 +; CHECK-P9-NEXT: xvcvspdp vs6, vs6 +; CHECK-P9-NEXT: xvcvspdp vs5, vs5 +; CHECK-P9-NEXT: xvcvspdp vs7, vs7 +; CHECK-P9-NEXT: xvcvspdp vs0, vs0 +; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-P9-NEXT: xscvspdpn f6, vs6 -; CHECK-P9-NEXT: xxmrghd vs6, vs7, vs6 -; CHECK-P9-NEXT: xscvspdpn f7, vs3 -; CHECK-P9-NEXT: xxsldwi vs3, vs3, vs3, 1 -; CHECK-P9-NEXT: lxv vs2, 48(r4) -; CHECK-P9-NEXT: xxswapd vs8, vs2 -; CHECK-P9-NEXT: xscvspdpn f8, vs8 ; CHECK-P9-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-P9-NEXT: xscvspdpn f3, vs3 -; CHECK-P9-NEXT: xxmrghd vs3, vs7, vs3 -; CHECK-P9-NEXT: xxsldwi vs7, vs2, vs2, 3 -; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 -; CHECK-P9-NEXT: stxv vs6, 64(r3) -; CHECK-P9-NEXT: xscvspdpn f7, vs7 -; CHECK-P9-NEXT: xxmrghd vs7, vs8, vs7 -; CHECK-P9-NEXT: xscvspdpn f8, vs2 -; CHECK-P9-NEXT: xxsldwi vs2, vs2, vs2, 1 -; CHECK-P9-NEXT: xscvspdpn f2, vs2 -; CHECK-P9-NEXT: xxmrghd vs2, vs8, vs2 ; CHECK-P9-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-P9-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-P9-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-P9-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-P9-NEXT: stxv vs3, 80(r3) -; CHECK-P9-NEXT: xvcvdpuxds vs2, vs2 +; CHECK-P9-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-P9-NEXT: stxv vs0, 112(r3) ; CHECK-P9-NEXT: stxv vs7, 96(r3) -; CHECK-P9-NEXT: stxv vs2, 112(r3) -; CHECK-P9-NEXT: stxv vs4, 48(r3) -; CHECK-P9-NEXT: stxv vs5, 32(r3) -; CHECK-P9-NEXT: stxv vs0, 16(r3) -; CHECK-P9-NEXT: stxv vs1, 0(r3) +; CHECK-P9-NEXT: stxv vs5, 80(r3) +; CHECK-P9-NEXT: stxv vs6, 64(r3) +; CHECK-P9-NEXT: stxv vs3, 48(r3) +; CHECK-P9-NEXT: stxv vs4, 32(r3) +; CHECK-P9-NEXT: stxv vs1, 16(r3) +; CHECK-P9-NEXT: stxv vs2, 0(r3) ; CHECK-P9-NEXT: blr ; ; CHECK-BE-LABEL: test16elt_signed: ; CHECK-BE: # %bb.0: # %entry -; CHECK-BE-NEXT: lxv vs0, 0(r4) -; CHECK-BE-NEXT: lxv vs4, 16(r4) -; CHECK-BE-NEXT: xxsldwi vs2, vs0, vs0, 1 -; CHECK-BE-NEXT: xscvspdpn f1, vs0 -; CHECK-BE-NEXT: xxsldwi vs5, vs0, vs0, 3 -; CHECK-BE-NEXT: xxswapd vs0, vs0 -; CHECK-BE-NEXT: xscvspdpn f5, vs5 -; CHECK-BE-NEXT: xscvspdpn f0, vs0 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 1 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xxmrghd vs0, vs0, vs5 -; CHECK-BE-NEXT: xscvspdpn f5, vs4 -; CHECK-BE-NEXT: lxv vs3, 32(r4) -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 1 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xxmrghd vs5, vs5, vs6 -; CHECK-BE-NEXT: xxsldwi vs6, vs4, vs4, 3 -; CHECK-BE-NEXT: xxswapd vs4, vs4 -; CHECK-BE-NEXT: xscvspdpn f6, vs6 -; CHECK-BE-NEXT: xscvspdpn f4, vs4 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs1, vs1, vs2 -; CHECK-BE-NEXT: lxv vs2, 48(r4) -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 1 +; CHECK-BE-NEXT: lxv vs0, 48(r4) +; CHECK-BE-NEXT: lxv vs1, 0(r4) +; CHECK-BE-NEXT: lxv vs3, 16(r4) +; CHECK-BE-NEXT: lxv vs5, 32(r4) +; CHECK-BE-NEXT: xxmrghw vs2, vs1, vs1 +; CHECK-BE-NEXT: xxmrglw vs1, vs1, vs1 +; CHECK-BE-NEXT: xxmrghw vs4, vs3, vs3 +; CHECK-BE-NEXT: xxmrglw vs3, vs3, vs3 +; CHECK-BE-NEXT: xxmrghw vs6, vs5, vs5 +; CHECK-BE-NEXT: xxmrglw vs5, vs5, vs5 +; CHECK-BE-NEXT: xxmrghw vs7, vs0, vs0 +; CHECK-BE-NEXT: xxmrglw vs0, vs0, vs0 +; CHECK-BE-NEXT: xvcvspdp vs2, vs2 +; CHECK-BE-NEXT: xvcvspdp vs1, vs1 +; CHECK-BE-NEXT: xvcvspdp vs4, vs4 +; CHECK-BE-NEXT: xvcvspdp vs3, vs3 +; CHECK-BE-NEXT: xvcvspdp vs6, vs6 +; CHECK-BE-NEXT: xvcvspdp vs5, vs5 +; CHECK-BE-NEXT: xvcvspdp vs7, vs7 +; CHECK-BE-NEXT: xvcvspdp vs0, vs0 +; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 ; CHECK-BE-NEXT: xvcvdpuxds vs1, vs1 -; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 -; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xxmrghd vs4, vs4, vs6 -; CHECK-BE-NEXT: xscvspdpn f6, vs3 -; CHECK-BE-NEXT: stxv vs0, 16(r3) -; CHECK-BE-NEXT: xxmrghd vs6, vs6, vs7 -; CHECK-BE-NEXT: xxsldwi vs7, vs3, vs3, 3 -; CHECK-BE-NEXT: xxswapd vs3, vs3 -; CHECK-BE-NEXT: xscvspdpn f7, vs7 -; CHECK-BE-NEXT: xscvspdpn f3, vs3 -; CHECK-BE-NEXT: xxmrghd vs3, vs3, vs7 -; CHECK-BE-NEXT: xscvspdpn f7, vs2 -; CHECK-BE-NEXT: xxmrghd vs7, vs7, vs8 -; CHECK-BE-NEXT: xxsldwi vs8, vs2, vs2, 3 -; CHECK-BE-NEXT: xxswapd vs2, vs2 -; CHECK-BE-NEXT: xscvspdpn f8, vs8 -; CHECK-BE-NEXT: xscvspdpn f2, vs2 -; CHECK-BE-NEXT: xxmrghd vs2, vs2, vs8 -; CHECK-BE-NEXT: stxv vs5, 32(r3) ; CHECK-BE-NEXT: xvcvdpuxds vs4, vs4 -; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 ; CHECK-BE-NEXT: xvcvdpuxds vs3, vs3 +; CHECK-BE-NEXT: xvcvdpuxds vs6, vs6 +; CHECK-BE-NEXT: xvcvdpuxds vs5, vs5 ; CHECK-BE-NEXT: xvcvdpuxds vs7, vs7 -; CHECK-BE-NEXT: stxv vs3, 80(r3) +; CHECK-BE-NEXT: xvcvdpuxds vs0, vs0 +; CHECK-BE-NEXT: stxv vs0, 112(r3) ; CHECK-BE-NEXT: stxv vs7, 96(r3) -; CHECK-BE-NEXT: xvcvdpuxds vs2, vs2 -; CHECK-BE-NEXT: stxv vs2, 112(r3) +; CHECK-BE-NEXT: stxv vs5, 80(r3) ; CHECK-BE-NEXT: stxv vs6, 64(r3) -; CHECK-BE-NEXT: stxv vs4, 48(r3) -; CHECK-BE-NEXT: stxv vs1, 0(r3) +; CHECK-BE-NEXT: stxv vs3, 48(r3) +; CHECK-BE-NEXT: stxv vs4, 32(r3) +; CHECK-BE-NEXT: stxv vs1, 16(r3) +; CHECK-BE-NEXT: stxv vs2, 0(r3) ; CHECK-BE-NEXT: blr entry: %a = load <16 x float>, <16 x float>* %0, align 64 diff --git a/llvm/test/CodeGen/PowerPC/vsx.ll b/llvm/test/CodeGen/PowerPC/vsx.ll index 9923cb02cc8d..7cf43a92a5dc 100644 --- a/llvm/test/CodeGen/PowerPC/vsx.ll +++ b/llvm/test/CodeGen/PowerPC/vsx.ll @@ -1554,11 +1554,8 @@ define <2 x i64> @test46(<2 x float> %a) { ; ; CHECK-LE-LABEL: test46: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-LE-NEXT: xxswapd vs1, v2 -; CHECK-LE-NEXT: xscvspdpn f0, vs0 -; CHECK-LE-NEXT: xscvspdpn f1, vs1 -; CHECK-LE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-LE-NEXT: xxmrglw vs0, v2, v2 +; CHECK-LE-NEXT: xvcvspdp vs0, vs0 ; CHECK-LE-NEXT: xvcvdpuxds v2, vs0 ; CHECK-LE-NEXT: blr %v = fptoui <2 x float> %a to <2 x i64> @@ -1625,11 +1622,8 @@ define <2 x i64> @test47(<2 x float> %a) { ; ; CHECK-LE-LABEL: test47: ; CHECK-LE: # %bb.0: -; CHECK-LE-NEXT: xxsldwi vs0, v2, v2, 3 -; CHECK-LE-NEXT: xxswapd vs1, v2 -; CHECK-LE-NEXT: xscvspdpn f0, vs0 -; CHECK-LE-NEXT: xscvspdpn f1, vs1 -; CHECK-LE-NEXT: xxmrghd vs0, vs1, vs0 +; CHECK-LE-NEXT: xxmrglw vs0, v2, v2 +; CHECK-LE-NEXT: xvcvspdp vs0, vs0 ; CHECK-LE-NEXT: xvcvdpsxds v2, vs0 ; CHECK-LE-NEXT: blr %v = fptosi <2 x float> %a to <2 x i64> diff --git a/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll b/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll new file mode 100644 index 000000000000..d8c8c48f3ba8 --- /dev/null +++ b/llvm/test/CodeGen/Thumb2/mve-vmovnstore.ll @@ -0,0 +1,541 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s + +define arm_aapcs_vfpcc void @vmovn32_trunc1(<4 x i32> %src1, <4 x i32> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn32_trunc1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s2 +; CHECK-NEXT: vmov.f32 s9, s6 +; CHECK-NEXT: vmov.f32 s10, s3 +; CHECK-NEXT: vmov.f32 s11, s7 +; CHECK-NEXT: vstrh.32 q2, [r0, #8] +; CHECK-NEXT: vmov.f32 s8, s0 +; CHECK-NEXT: vmov.f32 s9, s4 +; CHECK-NEXT: vmov.f32 s10, s1 +; CHECK-NEXT: vmov.f32 s11, s5 +; CHECK-NEXT: vstrh.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <4 x i32> %src1, <4 x i32> %src2, <8 x i32> + %out = trunc <8 x i32> %strided.vec to <8 x i16> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_trunc2(<4 x i32> %src1, <4 x i32> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn32_trunc2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s6 +; CHECK-NEXT: vmov.f32 s9, s2 +; CHECK-NEXT: vmov.f32 s10, s7 +; CHECK-NEXT: vmov.f32 s11, s3 +; CHECK-NEXT: vstrh.32 q2, [r0, #8] +; CHECK-NEXT: vmov.f32 s8, s4 +; CHECK-NEXT: vmov.f32 s9, s0 +; CHECK-NEXT: vmov.f32 s10, s5 +; CHECK-NEXT: vmov.f32 s11, s1 +; CHECK-NEXT: vstrh.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <4 x i32> %src1, <4 x i32> %src2, <8 x i32> + %out = trunc <8 x i32> %strided.vec to <8 x i16> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_trunc1(<8 x i16> %src1, <8 x i16> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn16_trunc1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vstrb.16 q2, [r0, #8] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrb.16 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <8 x i16> %src1, <8 x i16> %src2, <16 x i32> + %out = trunc <16 x i16> %strided.vec to <16 x i8> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_trunc2(<8 x i16> %src1, <8 x i16> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn16_trunc2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vstrb.16 q2, [r0, #8] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrb.16 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %strided.vec = shufflevector <8 x i16> %src1, <8 x i16> %src2, <16 x i32> + %out = trunc <16 x i16> %strided.vec to <16 x i8> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + + +define arm_aapcs_vfpcc void @vmovn64_t1(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s2, s4 +; CHECK-NEXT: vmov.f32 s3, s5 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_t2(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s6, s0 +; CHECK-NEXT: vmov.f32 s7, s1 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b1(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s2, s6 +; CHECK-NEXT: vmov.f32 s3, s7 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b2(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s6 +; CHECK-NEXT: vmov.f32 s9, s7 +; CHECK-NEXT: vmov.f32 s10, s0 +; CHECK-NEXT: vmov.f32 s11, s1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b3(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s2 +; CHECK-NEXT: vmov.f32 s9, s3 +; CHECK-NEXT: vmov.f32 s10, s4 +; CHECK-NEXT: vmov.f32 s11, s5 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn64_b4(<2 x i64> %src1, <2 x i64> %src2, <2 x i64> *%dest) { +; CHECK-LABEL: vmovn64_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s6, s2 +; CHECK-NEXT: vmov.f32 s7, s3 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <2 x i64> %src1, <2 x i64> %src2, <2 x i32> + store <2 x i64> %out, <2 x i64> *%dest, align 8 + ret void +} + + + +define arm_aapcs_vfpcc void @vmovn32_t1(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s1, s4 +; CHECK-NEXT: vmov.f32 s3, s6 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_t2(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s5, s0 +; CHECK-NEXT: vmov.f32 s7, s2 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b1(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s1, s5 +; CHECK-NEXT: vmov.f32 s3, s7 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b2(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s5 +; CHECK-NEXT: vmov.f32 s9, s0 +; CHECK-NEXT: vmov.f32 s10, s7 +; CHECK-NEXT: vmov.f32 s11, s2 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b3(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s8, s1 +; CHECK-NEXT: vmov.f32 s9, s4 +; CHECK-NEXT: vmov.f32 s10, s3 +; CHECK-NEXT: vmov.f32 s11, s6 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn32_b4(<4 x i32> %src1, <4 x i32> %src2, <4 x i32> *%dest) { +; CHECK-LABEL: vmovn32_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.f32 s5, s1 +; CHECK-NEXT: vmov.f32 s7, s3 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <4 x i32> %src1, <4 x i32> %src2, <4 x i32> + store <4 x i32> %out, <4 x i32> *%dest, align 8 + ret void +} + + + + +define arm_aapcs_vfpcc void @vmovn16_t1(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i32 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_t2(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i32 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b1(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i32 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b2(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q1[1] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q0[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q1[3] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q0[2] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q1[5] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q0[4] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q1[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q0[6] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b3(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u16 r1, q0[1] +; CHECK-NEXT: vmov.16 q2[0], r1 +; CHECK-NEXT: vmov.u16 r1, q1[0] +; CHECK-NEXT: vmov.16 q2[1], r1 +; CHECK-NEXT: vmov.u16 r1, q0[3] +; CHECK-NEXT: vmov.16 q2[2], r1 +; CHECK-NEXT: vmov.u16 r1, q1[2] +; CHECK-NEXT: vmov.16 q2[3], r1 +; CHECK-NEXT: vmov.u16 r1, q0[5] +; CHECK-NEXT: vmov.16 q2[4], r1 +; CHECK-NEXT: vmov.u16 r1, q1[4] +; CHECK-NEXT: vmov.16 q2[5], r1 +; CHECK-NEXT: vmov.u16 r1, q0[7] +; CHECK-NEXT: vmov.16 q2[6], r1 +; CHECK-NEXT: vmov.u16 r1, q1[6] +; CHECK-NEXT: vmov.16 q2[7], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn16_b4(<8 x i16> %src1, <8 x i16> %src2, <8 x i16> *%dest) { +; CHECK-LABEL: vmovn16_b4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i32 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <8 x i16> %src1, <8 x i16> %src2, <8 x i32> + store <8 x i16> %out, <8 x i16> *%dest, align 8 + ret void +} + + +define arm_aapcs_vfpcc void @vmovn8_b1(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_b1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i16 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_b2(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_b2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnt.i16 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t1(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t1: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i16 q1, q0 +; CHECK-NEXT: vstrw.32 q1, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t2(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t2: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u8 r1, q1[1] +; CHECK-NEXT: vmov.8 q2[0], r1 +; CHECK-NEXT: vmov.u8 r1, q0[0] +; CHECK-NEXT: vmov.8 q2[1], r1 +; CHECK-NEXT: vmov.u8 r1, q1[3] +; CHECK-NEXT: vmov.8 q2[2], r1 +; CHECK-NEXT: vmov.u8 r1, q0[2] +; CHECK-NEXT: vmov.8 q2[3], r1 +; CHECK-NEXT: vmov.u8 r1, q1[5] +; CHECK-NEXT: vmov.8 q2[4], r1 +; CHECK-NEXT: vmov.u8 r1, q0[4] +; CHECK-NEXT: vmov.8 q2[5], r1 +; CHECK-NEXT: vmov.u8 r1, q1[7] +; CHECK-NEXT: vmov.8 q2[6], r1 +; CHECK-NEXT: vmov.u8 r1, q0[6] +; CHECK-NEXT: vmov.8 q2[7], r1 +; CHECK-NEXT: vmov.u8 r1, q1[9] +; CHECK-NEXT: vmov.8 q2[8], r1 +; CHECK-NEXT: vmov.u8 r1, q0[8] +; CHECK-NEXT: vmov.8 q2[9], r1 +; CHECK-NEXT: vmov.u8 r1, q1[11] +; CHECK-NEXT: vmov.8 q2[10], r1 +; CHECK-NEXT: vmov.u8 r1, q0[10] +; CHECK-NEXT: vmov.8 q2[11], r1 +; CHECK-NEXT: vmov.u8 r1, q1[13] +; CHECK-NEXT: vmov.8 q2[12], r1 +; CHECK-NEXT: vmov.u8 r1, q0[12] +; CHECK-NEXT: vmov.8 q2[13], r1 +; CHECK-NEXT: vmov.u8 r1, q1[15] +; CHECK-NEXT: vmov.8 q2[14], r1 +; CHECK-NEXT: vmov.u8 r1, q0[14] +; CHECK-NEXT: vmov.8 q2[15], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t3(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t3: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov.u8 r1, q0[1] +; CHECK-NEXT: vmov.8 q2[0], r1 +; CHECK-NEXT: vmov.u8 r1, q1[0] +; CHECK-NEXT: vmov.8 q2[1], r1 +; CHECK-NEXT: vmov.u8 r1, q0[3] +; CHECK-NEXT: vmov.8 q2[2], r1 +; CHECK-NEXT: vmov.u8 r1, q1[2] +; CHECK-NEXT: vmov.8 q2[3], r1 +; CHECK-NEXT: vmov.u8 r1, q0[5] +; CHECK-NEXT: vmov.8 q2[4], r1 +; CHECK-NEXT: vmov.u8 r1, q1[4] +; CHECK-NEXT: vmov.8 q2[5], r1 +; CHECK-NEXT: vmov.u8 r1, q0[7] +; CHECK-NEXT: vmov.8 q2[6], r1 +; CHECK-NEXT: vmov.u8 r1, q1[6] +; CHECK-NEXT: vmov.8 q2[7], r1 +; CHECK-NEXT: vmov.u8 r1, q0[9] +; CHECK-NEXT: vmov.8 q2[8], r1 +; CHECK-NEXT: vmov.u8 r1, q1[8] +; CHECK-NEXT: vmov.8 q2[9], r1 +; CHECK-NEXT: vmov.u8 r1, q0[11] +; CHECK-NEXT: vmov.8 q2[10], r1 +; CHECK-NEXT: vmov.u8 r1, q1[10] +; CHECK-NEXT: vmov.8 q2[11], r1 +; CHECK-NEXT: vmov.u8 r1, q0[13] +; CHECK-NEXT: vmov.8 q2[12], r1 +; CHECK-NEXT: vmov.u8 r1, q1[12] +; CHECK-NEXT: vmov.8 q2[13], r1 +; CHECK-NEXT: vmov.u8 r1, q0[15] +; CHECK-NEXT: vmov.8 q2[14], r1 +; CHECK-NEXT: vmov.u8 r1, q1[14] +; CHECK-NEXT: vmov.8 q2[15], r1 +; CHECK-NEXT: vstrw.32 q2, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} + +define arm_aapcs_vfpcc void @vmovn8_t4(<16 x i8> %src1, <16 x i8> %src2, <16 x i8> *%dest) { +; CHECK-LABEL: vmovn8_t4: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmovnb.i16 q0, q1 +; CHECK-NEXT: vstrw.32 q0, [r0] +; CHECK-NEXT: bx lr +entry: + %out = shufflevector <16 x i8> %src1, <16 x i8> %src2, <16 x i32> + store <16 x i8> %out, <16 x i8> *%dest, align 8 + ret void +} diff --git a/llvm/test/CodeGen/Thumb2/mve-vmull.ll b/llvm/test/CodeGen/Thumb2/mve-vmull.ll index b7b28068f528..c1e720fa3ab6 100644 --- a/llvm/test/CodeGen/Thumb2/mve-vmull.ll +++ b/llvm/test/CodeGen/Thumb2/mve-vmull.ll @@ -1,6 +1,105 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple=thumbv8.1m.main-arm-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK +define arm_aapcs_vfpcc <2 x i64> @sext_02(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: sext_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov r0, s4 +; CHECK-NEXT: vmov r1, s0 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[0], r0 +; CHECK-NEXT: vmov r0, s6 +; CHECK-NEXT: vmov.32 q2[1], r1 +; CHECK-NEXT: vmov r1, s2 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[2], r0 +; CHECK-NEXT: vmov.32 q2[3], r1 +; CHECK-NEXT: vmov q0, q2 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = sext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = sext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @sext_13(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: sext_13: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vrev64.32 q2, q1 +; CHECK-NEXT: vrev64.32 q1, q0 +; CHECK-NEXT: vmov r0, s8 +; CHECK-NEXT: vmov r1, s4 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[0], r0 +; CHECK-NEXT: vmov r0, s10 +; CHECK-NEXT: vmov.32 q0[1], r1 +; CHECK-NEXT: vmov r1, s6 +; CHECK-NEXT: smull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[2], r0 +; CHECK-NEXT: vmov.32 q0[3], r1 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = sext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = sext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @zext_02(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: zext_02: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vmov r0, s4 +; CHECK-NEXT: vmov r1, s0 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[0], r0 +; CHECK-NEXT: vmov r0, s6 +; CHECK-NEXT: vmov.32 q2[1], r1 +; CHECK-NEXT: vmov r1, s2 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q2[2], r0 +; CHECK-NEXT: vmov.32 q2[3], r1 +; CHECK-NEXT: vmov q0, q2 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = zext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = zext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + +define arm_aapcs_vfpcc <2 x i64> @zext_13(<4 x i32> %src1, <4 x i32> %src2) { +; CHECK-LABEL: zext_13: +; CHECK: @ %bb.0: @ %entry +; CHECK-NEXT: vrev64.32 q2, q1 +; CHECK-NEXT: vrev64.32 q1, q0 +; CHECK-NEXT: vmov r0, s8 +; CHECK-NEXT: vmov r1, s4 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[0], r0 +; CHECK-NEXT: vmov r0, s10 +; CHECK-NEXT: vmov.32 q0[1], r1 +; CHECK-NEXT: vmov r1, s6 +; CHECK-NEXT: umull r0, r1, r1, r0 +; CHECK-NEXT: vmov.32 q0[2], r0 +; CHECK-NEXT: vmov.32 q0[3], r1 +; CHECK-NEXT: bx lr +entry: + %shuf1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <2 x i32> + %out1 = zext <2 x i32> %shuf1 to <2 x i64> + %shuf2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <2 x i32> + %out2 = zext <2 x i32> %shuf2 to <2 x i64> + %out = mul <2 x i64> %out1, %out2 + ret <2 x i64> %out +} + + define arm_aapcs_vfpcc <4 x i32> @sext_0246(<8 x i16> %src1, <8 x i16> %src2) { ; CHECK-LABEL: sext_0246: ; CHECK: @ %bb.0: @ %entry diff --git a/llvm/test/Transforms/GVNSink/indirect-call.ll b/llvm/test/Transforms/GVNSink/indirect-call.ll index da98ed0819a6..57b7297c84bd 100644 --- a/llvm/test/Transforms/GVNSink/indirect-call.ll +++ b/llvm/test/Transforms/GVNSink/indirect-call.ll @@ -68,3 +68,27 @@ if.end: %tobool4 = icmp ne i8 %obeys.0, 0 ret i1 %tobool4 } + +; Make sure no indirect call is introduced from direct calls +declare i8 @ext2(i1) +define zeroext i1 @test4(i1 zeroext %flag, i32 %blksA, i32 %blksB, i32 %nblks) { +entry: + %cmp = icmp uge i32 %blksA, %nblks + br i1 %flag, label %if.then, label %if.else + +; CHECK-LABEL: test4 +; CHECK: call i8 @ext( +; CHECK: call i8 @ext2( +if.then: + %frombool1 = call i8 @ext(i1 %cmp) + br label %if.end + +if.else: + %frombool3 = call i8 @ext2(i1 %cmp) + br label %if.end + +if.end: + %obeys.0 = phi i8 [ %frombool1, %if.then ], [ %frombool3, %if.else ] + %tobool4 = icmp ne i8 %obeys.0, 0 + ret i1 %tobool4 +} diff --git a/llvm/test/Transforms/GVNSink/sink-common-code.ll b/llvm/test/Transforms/GVNSink/sink-common-code.ll index 02b1eb7fe259..160bbd370ff5 100644 --- a/llvm/test/Transforms/GVNSink/sink-common-code.ll +++ b/llvm/test/Transforms/GVNSink/sink-common-code.ll @@ -692,6 +692,73 @@ if.end: ; CHECK-NOT: exact ; CHECK: } + +; CHECK-LABEL: @common_bitcast( +; CHECK: %. = select i1 %flag, float 2.000000e+00, float 1.000000e+00 +; CHECK: %a = bitcast i32* %x to float* +; CHECK: store float %., float* %a +define i32 @common_bitcast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = bitcast i32* %x to float* + store float 2.0, float* %a + br label %if.end + +if.else: + %b = bitcast i32* %x to float* + store float 1.0, float* %b + br label %if.end + +if.end: + ret i32 1 +} + +; CHECK-LABEL: @common_addrspacecast( +; CHECK: %. = select i1 %flag, i32 9, i32 10 +; CHECK: %a = addrspacecast i32* %x to i32 addrspace(1)* +; CHECK: store i32 %., i32 addrspace(1)* %a +define i32 @common_addrspacecast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = addrspacecast i32* %x to i32 addrspace(1)* + store i32 9, i32 addrspace(1)* %a + br label %if.end + +if.else: + %b = addrspacecast i32* %x to i32 addrspace(1)* + store i32 10, i32 addrspace(1)* %b + br label %if.end + +if.end: + ret i32 1 +} + +; Don't merge different address spaces +; CHECK-LABEL: @no_common_addrspacecast( +; CHECK: addrspacecast i32* %x to i32 addrspace(1)* +; CHECK: addrspacecast i32* %x to i32 addrspace(3)* +define i32 @no_common_addrspacecast(i1 zeroext %flag, i32* %x) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %a = addrspacecast i32* %x to i32 addrspace(1)* + store i32 9, i32 addrspace(1)* %a + br label %if.end + +if.else: + %b = addrspacecast i32* %x to i32 addrspace(3)* + store i32 10, i32 addrspace(3)* %b + br label %if.end + +if.end: + ret i32 1 +} + ; CHECK: !0 = !{!1, !1, i64 0} ; CHECK: !1 = !{!"float", !2} ; CHECK: !2 = !{!"an example type tree"} diff --git a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll index f1fe9384e3fe..6ac3cfe36bbc 100644 --- a/llvm/test/Transforms/InstCombine/ctpop-cttz.ll +++ b/llvm/test/Transforms/InstCombine/ctpop-cttz.ll @@ -78,7 +78,7 @@ define i32 @ctpop2_multiuse(i32 %0) { ; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP0:%.*]], -1 ; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP0]], -1 ; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP3]], [[TMP2]] -; CHECK-NEXT: [[TMP5:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[TMP4]]), !range !0 +; CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.cttz.i32(i32 [[TMP0]], i1 false), !range !0 ; CHECK-NEXT: [[TMP6:%.*]] = add i32 [[TMP5]], [[TMP4]] ; CHECK-NEXT: ret i32 [[TMP6]] ; diff --git a/llvm/test/Transforms/OpenMP/rtf_type_checking.ll b/llvm/test/Transforms/OpenMP/rtf_type_checking.ll new file mode 100644 index 000000000000..57c09bcc7e06 --- /dev/null +++ b/llvm/test/Transforms/OpenMP/rtf_type_checking.ll @@ -0,0 +1,63 @@ +; RUN: opt -S -openmpopt -stats < %s 2>&1 | FileCheck %s +; REQUIRES: asserts + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +%struct.ident_t = type { i32, i32, i32, i32, i8* } + +@.str = private unnamed_addr constant [23 x i8] c";unknown;unknown;0;0;;\00", align 1 +@0 = private unnamed_addr global %struct.ident_t { i32 0, i32 2, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 +@1 = private unnamed_addr global %struct.ident_t { i32 0, i32 322, i32 0, i32 0, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str, i32 0, i32 0) }, align 8 + +define i32 @main() { +entry: + + call void (%struct.ident_t*, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)) + ret i32 0 +} + +; Only the last runtime call will be matched due that the rest of the "runtime function" calls +; have some type mismatch compared to the real runtime function. See the check at bottom. +define internal void @.omp_outlined.(i32* noalias %.global_tid., i32* noalias %.bound_tid.) { +entry: + + call void @__kmpc_master(%struct.ident_t* nonnull @0) + call void @__kmpc_end_master(%struct.ident_t* nonnull @0, i32 0, i32 0) + call void @__kmpc_barrier(%struct.ident_t* nonnull @1, float 0.0) + call void @omp_get_thread_num() + call void @__kmpc_flush(%struct.ident_t* nonnull @0) + ret void +} +; Fewer arguments than expected in variadic function. +declare !callback !2 void @__kmpc_fork_call(%struct.ident_t*, void (i32*, i32*, ...)*, ...) + +; Fewer number of arguments in non variadic function. +declare void @__kmpc_master(%struct.ident_t*) + +; Bigger number of arguments in non variadic function. +declare void @__kmpc_end_master(%struct.ident_t*, i32, i32) + +; Different argument type than the expected. +declare void @__kmpc_barrier(%struct.ident_t*, float) + +; Proper use of runtime function. +declare void @__kmpc_flush(%struct.ident_t*) + +; Different return type. +declare void @omp_get_thread_num() + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang"} +!2 = !{!3} +!3 = !{i64 2, i64 -1, i64 -1, i1 true} +; ===-------------------------------------------------------------------------=== +; ... Statistics Collected ... +; ===-------------------------------------------------------------------------=== +; +; CHECK: 1 cgscc-passmgr - Maximum CGSCCPassMgr iterations on one SCC +; CHECK: 2 openmp-opt{{.*}}Number of OpenMP runtime functions identified +; +; There are two matches since the pass is run once per function. \ No newline at end of file diff --git a/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll b/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll new file mode 100644 index 000000000000..84d25fe79a27 --- /dev/null +++ b/llvm/test/Transforms/SLPVectorizer/AMDGPU/round.ll @@ -0,0 +1,38 @@ +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=hawaii -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX7 %s +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=fiji -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX8 %s +; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -mcpu=gfx900 -slp-vectorizer %s | FileCheck -check-prefixes=GCN,GFX8 %s + +; GCN-LABEL: @round_v2f16( +; GFX7: call half @llvm.round.f16( +; GFX7: call half @llvm.round.f16( + +; GFX8: call <2 x half> @llvm.round.v2f16( +define <2 x half> @round_v2f16(<2 x half> %arg) { +bb: + %tmp = extractelement <2 x half> %arg, i64 0 + %tmp1 = tail call half @llvm.round.half(half %tmp) + %tmp2 = insertelement <2 x half> undef, half %tmp1, i64 0 + %tmp3 = extractelement <2 x half> %arg, i64 1 + %tmp4 = tail call half @llvm.round.half(half %tmp3) + %tmp5 = insertelement <2 x half> %tmp2, half %tmp4, i64 1 + ret <2 x half> %tmp5 +} + +; TODO: Should probably not really be vectorizing this +; GCN-LABEL: @round_v2f32( +; GCN: call <2 x float> @llvm.round.v2f32 +define <2 x float> @round_v2f32(<2 x float> %arg) { +bb: + %tmp = extractelement <2 x float> %arg, i64 0 + %tmp1 = tail call float @llvm.round.f32(float %tmp) + %tmp2 = insertelement <2 x float> undef, float %tmp1, i64 0 + %tmp3 = extractelement <2 x float> %arg, i64 1 + %tmp4 = tail call float @llvm.round.f32(float %tmp3) + %tmp5 = insertelement <2 x float> %tmp2, float %tmp4, i64 1 + ret <2 x float> %tmp5 +} + +declare half @llvm.round.half(half) #0 +declare float @llvm.round.f32(float) #0 + +attributes #0 = { nounwind readnone speculatable willreturn } diff --git a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll index 8254a49e28fd..00329ae5d640 100644 --- a/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll +++ b/llvm/test/Transforms/SimplifyCFG/sink-common-code.ll @@ -291,12 +291,12 @@ entry: if.then: %dummy = add i32 %w, 5 - %sv1 = call i32 @llvm.ctlz.i32(i32 %x) + %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 false) br label %if.end if.else: %dummy1 = add i32 %w, 6 - %sv2 = call i32 @llvm.cttz.i32(i32 %x) + %sv2 = call i32 @llvm.cttz.i32(i32 %x, i1 false) br label %if.end if.end: @@ -304,8 +304,8 @@ if.end: ret i32 1 } -declare i32 @llvm.ctlz.i32(i32 %x) readnone -declare i32 @llvm.cttz.i32(i32 %x) readnone +declare i32 @llvm.ctlz.i32(i32 %x, i1 immarg) readnone +declare i32 @llvm.cttz.i32(i32 %x, i1 immarg) readnone ; CHECK-LABEL: test12 ; CHECK: call i32 @llvm.ctlz @@ -769,6 +769,120 @@ if.end: ; CHECK-NOT: exact ; CHECK: } + +; FIXME: Should turn into select +; CHECK-LABEL: @allow_intrinsic_remove_constant( +; CHECK: %sv1 = call float @llvm.fma.f32(float %dummy, float 2.000000e+00, float 1.000000e+00) +; CHECK: %sv2 = call float @llvm.fma.f32(float 2.000000e+00, float %dummy1, float 1.000000e+00) +define float @allow_intrinsic_remove_constant(i1 zeroext %flag, float %w, float %x, float %y) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %dummy = fadd float %w, 4.0 + %sv1 = call float @llvm.fma.f32(float %dummy, float 2.0, float 1.0) + br label %if.end + +if.else: + %dummy1 = fadd float %w, 8.0 + %sv2 = call float @llvm.fma.f32(float 2.0, float %dummy1, float 1.0) + br label %if.end + +if.end: + %p = phi float [ %sv1, %if.then ], [ %sv2, %if.else ] + ret float %p +} + +declare float @llvm.fma.f32(float, float, float) + +; CHECK-LABEL: @no_remove_constant_immarg( +; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 true) +; CHECK: call i32 @llvm.ctlz.i32(i32 %x, i1 false) +define i32 @no_remove_constant_immarg(i1 zeroext %flag, i32 %w, i32 %x, i32 %y) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + %dummy = add i32 %w, 5 + %sv1 = call i32 @llvm.ctlz.i32(i32 %x, i1 true) + br label %if.end + +if.else: + %dummy1 = add i32 %w, 6 + %sv2 = call i32 @llvm.ctlz.i32(i32 %x, i1 false) + br label %if.end + +if.end: + %p = phi i32 [ %sv1, %if.then ], [ %sv2, %if.else ] + ret i32 1 +} + +declare void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) + +; Make sure a memcpy size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memcpy_size( +; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) +; CHECK: call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) +define void @no_replace_memcpy_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memcpy.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + +declare void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* nocapture, i8 addrspace(1)* nocapture readonly, i64, i1) + +; Make sure a memmove size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memmove_size( +; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) +; CHECK: call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) +define void @no_replace_memmove_size(i1 zeroext %flag, i8 addrspace(1)* %dst, i8 addrspace(1)* %src) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memmove.p1i8.p1i8.i64(i8 addrspace(1)* %dst, i8 addrspace(1)* %src, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + +declare void @llvm.memset.p1i8.i64(i8 addrspace(1)* nocapture, i8, i64, i1) + +; Make sure a memset size isn't replaced with a variable +; CHECK-LABEL: @no_replace_memset_size( +; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 1024, i1 false) +; CHECK: call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 4096, i1 false) +define void @no_replace_memset_size(i1 zeroext %flag, i8 addrspace(1)* %dst) { +entry: + br i1 %flag, label %if.then, label %if.else + +if.then: + call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 1024, i1 false) + br label %if.end + +if.else: + call void @llvm.memset.p1i8.i64(i8 addrspace(1)* %dst, i8 0, i64 4096, i1 false) + br label %if.end + +if.end: + ret void +} + ; Check that simplifycfg doesn't sink and merge inline-asm instructions. define i32 @test_inline_asm1(i32 %c, i32 %r6) { @@ -913,7 +1027,6 @@ if.end: declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) - ; CHECK: ![[$TBAA]] = !{![[TYPE:[0-9]]], ![[TYPE]], i64 0} ; CHECK: ![[TYPE]] = !{!"float", ![[TEXT:[0-9]]]} ; CHECK: ![[TEXT]] = !{!"an example type tree"} diff --git a/llvm/test/tools/llvm-objcopy/tool-name.test b/llvm/test/tools/llvm-objcopy/tool-name.test new file mode 100644 index 000000000000..a273375f109e --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/tool-name.test @@ -0,0 +1,33 @@ +## Don't make symlinks on Windows. +# UNSUPPORTED: system-windows + +# RUN: rm -rf %t +# RUN: mkdir %t + +# RUN: ln -s llvm-objcopy %t/llvm-objcopy-11.exe +# RUN: ln -s llvm-objcopy %t/powerpc64-unknown-freebsd13-objcopy + +# RUN: llvm-objcopy --help | FileCheck --check-prefix=OBJCOPY %s +# RUN: %t/llvm-objcopy-11.exe --help | FileCheck --check-prefix=OBJCOPY %s +# RUN: %t/powerpc64-unknown-freebsd13-objcopy --help | FileCheck --check-prefix=OBJCOPY %s + +# OBJCOPY: OVERVIEW: llvm-objcopy tool + +# RUN: ln -s llvm-strip %t/strip.exe +# RUN: ln -s llvm-strip %t/gnu-llvm-strip-10 + +# RUN: llvm-strip --help | FileCheck --check-prefix=STRIP %s +# RUN: %t/strip.exe --help | FileCheck --check-prefix=STRIP %s +# RUN: %t/gnu-llvm-strip-10 --help | FileCheck --check-prefix=STRIP %s + +# STRIP: OVERVIEW: llvm-strip tool + +## This driver emulates install_name_tool on macOS. +# RUN: ln -s llvm-install-name-tool %t/llvm-install-name-tool-10 +# RUN: ln -s llvm-install-name-tool %t/install_name_tool.exe + +# RUN: llvm-install-name-tool --help | FileCheck --check-prefix=INSTALL %s +# RUN: %t/llvm-install-name-tool-10 --help | FileCheck --check-prefix=INSTALL %s +# RUN: %t/install_name_tool.exe --help | FileCheck --check-prefix=INSTALL %s + +# INSTALL: OVERVIEW: llvm-install-name-tool tool diff --git a/llvm/tools/bugpoint/CMakeLists.txt b/llvm/tools/bugpoint/CMakeLists.txt index 421889cfedb7..df10bfe4fcac 100644 --- a/llvm/tools/bugpoint/CMakeLists.txt +++ b/llvm/tools/bugpoint/CMakeLists.txt @@ -39,4 +39,4 @@ add_llvm_tool(bugpoint intrinsics_gen SUPPORT_PLUGINS ) -export_executable_symbols(bugpoint) +export_executable_symbols_for_plugins(bugpoint) diff --git a/llvm/tools/llc/CMakeLists.txt b/llvm/tools/llc/CMakeLists.txt index 479bc6b55b27..2eecfca2e075 100644 --- a/llvm/tools/llc/CMakeLists.txt +++ b/llvm/tools/llc/CMakeLists.txt @@ -27,4 +27,4 @@ add_llvm_tool(llc SUPPORT_PLUGINS ) -export_executable_symbols(llc) +export_executable_symbols_for_plugins(llc) diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp index 8e95ebb73331..69b23b6cf975 100644 --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -327,11 +327,25 @@ enum class ToolType { Objcopy, Strip, InstallNameTool }; int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - ToolType Tool = StringSwitch(sys::path::stem(ToolName)) - .EndsWith("strip", ToolType::Strip) - .EndsWith("install-name-tool", ToolType::InstallNameTool) - .EndsWith("install_name_tool", ToolType::InstallNameTool) - .Default(ToolType::Objcopy); + + StringRef Stem = sys::path::stem(ToolName); + auto Is = [=](StringRef Tool) { + // We need to recognize the following filenames: + // + // llvm-objcopy -> objcopy + // strip-10.exe -> strip + // powerpc64-unknown-freebsd13-objcopy -> objcopy + // llvm-install-name-tool -> install-name-tool + auto I = Stem.rfind_lower(Tool); + return I != StringRef::npos && + (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); + }; + ToolType Tool = ToolType::Objcopy; + if (Is("strip")) + Tool = ToolType::Strip; + else if (Is("install-name-tool") || Is("install_name_tool")) + Tool = ToolType::InstallNameTool; + // Expand response files. // TODO: Move these lines, which are copied from lib/Support/CommandLine.cpp, // into a separate function in the CommandLine library and call that function diff --git a/llvm/tools/llvm-stress/CMakeLists.txt b/llvm/tools/llvm-stress/CMakeLists.txt index 139ab9e0d8f9..e4d1ae65ee76 100644 --- a/llvm/tools/llvm-stress/CMakeLists.txt +++ b/llvm/tools/llvm-stress/CMakeLists.txt @@ -10,4 +10,3 @@ add_llvm_tool(llvm-stress DEPENDS intrinsics_gen ) -export_executable_symbols(llvm-stress) diff --git a/llvm/tools/opt/CMakeLists.txt b/llvm/tools/opt/CMakeLists.txt index ad9e20bd0b43..c3368d93174c 100644 --- a/llvm/tools/opt/CMakeLists.txt +++ b/llvm/tools/opt/CMakeLists.txt @@ -40,7 +40,7 @@ add_llvm_tool(opt intrinsics_gen SUPPORT_PLUGINS ) -export_executable_symbols(opt) +export_executable_symbols_for_plugins(opt) if(LLVM_BUILD_EXAMPLES) target_link_libraries(opt PRIVATE ExampleIRTransforms) diff --git a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp index 999220fd250d..1c86d5ff9943 100644 --- a/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/CSETest.cpp @@ -11,7 +11,7 @@ namespace { -TEST_F(GISelMITest, TestCSE) { +TEST_F(AArch64GISelMITest, TestCSE) { setUp(); if (!TM) return; @@ -79,7 +79,7 @@ TEST_F(GISelMITest, TestCSE) { EXPECT_EQ(&*Undef0, &*Undef1); } -TEST_F(GISelMITest, TestCSEConstantConfig) { +TEST_F(AArch64GISelMITest, TestCSEConstantConfig) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp index 2f99005105fd..127aaffc2878 100644 --- a/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/ConstantFoldingTest.cpp @@ -17,7 +17,7 @@ using namespace llvm; namespace { -TEST_F(GISelMITest, FoldWithBuilder) { +TEST_F(AArch64GISelMITest, FoldWithBuilder) { setUp(); if (!TM) return; @@ -68,7 +68,7 @@ TEST_F(GISelMITest, FoldWithBuilder) { EXPECT_EQ(-0x80, Cst); } -TEST_F(GISelMITest, FoldBinOp) { +TEST_F(AArch64GISelMITest, FoldBinOp) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp index 0558c4121fdd..ef50a0f281f0 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.cpp @@ -28,3 +28,79 @@ operator<<(std::ostream &OS, const MachineFunction &MF) { } } + +std::unique_ptr +AArch64GISelMITest::createTargetMachine() const { + Triple TargetTriple("aarch64--"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + static_cast(T->createTargetMachine( + "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive))); +} + +void AArch64GISelMITest::getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const { + (Twine(R"MIR( +--- +... +name: func +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.1: + liveins: $x0, $x1, $x2, $x4 + + %0(s64) = COPY $x0 + %1(s64) = COPY $x1 + %2(s64) = COPY $x2 +)MIR") + + Twine(MIRFunc) + Twine("...\n")) + .toNullTerminatedStringRef(S); +} + +std::unique_ptr +AMDGPUGISelMITest::createTargetMachine() const { + Triple TargetTriple("amdgcn-amd-amdhsa"); + std::string Error; + const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); + if (!T) + return nullptr; + + TargetOptions Options; + return std::unique_ptr( + static_cast(T->createTargetMachine( + "amdgcn-amd-amdhsa", "gfx900", "", Options, None, None, + CodeGenOpt::Aggressive))); +} + +void AMDGPUGISelMITest::getTargetTestModuleString( + SmallString<512> &S, StringRef MIRFunc) const { + (Twine(R"MIR( +--- +... +name: func +tracksRegLiveness: true +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.1: + liveins: $vgpr0, $vgpr1, $vgpr2 + + %0(s32) = COPY $vgpr0 + %1(s32) = COPY $vgpr1 + %2(s32) = COPY $vgpr2 +)MIR") + Twine(MIRFunc) + Twine("...\n")) + .toNullTerminatedStringRef(S); +} diff --git a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h index 4254f4f759e4..db3f2b9531c9 100644 --- a/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h +++ b/llvm/unittests/CodeGen/GlobalISel/GISelMITest.h @@ -53,21 +53,6 @@ std::ostream & operator<<(std::ostream &OS, const MachineFunction &MF); } -/// Create a TargetMachine. As we lack a dedicated always available target for -/// unittests, we go for "AArch64". -static std::unique_ptr createTargetMachine() { - Triple TargetTriple("aarch64--"); - std::string Error; - const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error); - if (!T) - return nullptr; - - TargetOptions Options; - return std::unique_ptr( - static_cast(T->createTargetMachine( - "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive))); -} - static std::unique_ptr parseMIR(LLVMContext &Context, std::unique_ptr &MIR, const TargetMachine &TM, @@ -90,34 +75,13 @@ static std::unique_ptr parseMIR(LLVMContext &Context, return M; } - static std::pair, std::unique_ptr> createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM, - StringRef MIRFunc) { - SmallString<512> S; - StringRef MIRString = (Twine(R"MIR( ---- -... -name: func -tracksRegLiveness: true -registers: - - { id: 0, class: _ } - - { id: 1, class: _ } - - { id: 2, class: _ } - - { id: 3, class: _ } -body: | - bb.1: - liveins: $x0, $x1, $x2, $x4 - - %0(s64) = COPY $x0 - %1(s64) = COPY $x1 - %2(s64) = COPY $x2 -)MIR") + Twine(MIRFunc) + Twine("...\n")) - .toNullTerminatedStringRef(S); + StringRef MIRString, const char *FuncName) { std::unique_ptr MIR; auto MMI = std::make_unique(&TM); std::unique_ptr M = - parseMIR(Context, MIR, TM, MIRString, "func", *MMI); + parseMIR(Context, MIR, TM, MIRString, FuncName, *MMI); return make_pair(std::move(M), std::move(MMI)); } @@ -140,11 +104,23 @@ static void collectCopies(SmallVectorImpl &Copies, class GISelMITest : public ::testing::Test { protected: GISelMITest() : ::testing::Test() {} + + /// Prepare a target specific LLVMTargetMachine. + virtual std::unique_ptr createTargetMachine() const = 0; + + /// Get the stub sample MIR test function. + virtual void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const = 0; + void setUp(StringRef ExtraAssembly = "") { TM = createTargetMachine(); if (!TM) return; - ModuleMMIPair = createDummyModule(Context, *TM, ExtraAssembly); + + SmallString<512> MIRString; + getTargetTestModuleString(MIRString, ExtraAssembly); + + ModuleMMIPair = createDummyModule(Context, *TM, MIRString, "func"); MF = getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get()); collectCopies(Copies, MF); EntryMBB = &*MF->begin(); @@ -152,6 +128,7 @@ class GISelMITest : public ::testing::Test { MRI = &MF->getRegInfo(); B.setInsertPt(*EntryMBB, EntryMBB->end()); } + LLVMContext Context; std::unique_ptr TM; MachineFunction *MF; @@ -163,6 +140,18 @@ class GISelMITest : public ::testing::Test { MachineRegisterInfo *MRI; }; +class AArch64GISelMITest : public GISelMITest { + std::unique_ptr createTargetMachine() const override; + void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const override; +}; + +class AMDGPUGISelMITest : public GISelMITest { + std::unique_ptr createTargetMachine() const override; + void getTargetTestModuleString(SmallString<512> &S, + StringRef MIRFunc) const override; +}; + #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \ class Name##Info : public LegalizerInfo { \ public: \ diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp index a5372511b051..fe0c14270ecf 100644 --- a/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/KnownBitsTest.cpp @@ -10,7 +10,7 @@ #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" -TEST_F(GISelMITest, TestKnownBitsCst) { +TEST_F(AArch64GISelMITest, TestKnownBitsCst) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 1\n" " %4:_(s8) = COPY %3\n"; setUp(MIRString); @@ -30,7 +30,7 @@ TEST_F(GISelMITest, TestKnownBitsCst) { EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsCstWithClass) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstWithClass) { StringRef MIRString = " %10:gpr32 = MOVi32imm 1\n" " %4:_(s32) = COPY %10\n"; setUp(MIRString); @@ -58,7 +58,7 @@ TEST_F(GISelMITest, TestKnownBitsCstWithClass) { // Check that we are able to track bits through PHIs // and get the intersections of everything we know on each operand. -TEST_F(GISelMITest, TestKnownBitsCstPHI) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHI) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 3\n" " %11:_(s1) = G_IMPLICIT_DEF\n" @@ -92,7 +92,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHI) { // Check that we report we know nothing when we hit a // non-generic register. // Note: this could be improved though! -TEST_F(GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { StringRef MIRString = " bb.10:\n" " %10:gpr32 = MOVi32imm 3\n" " %11:_(s1) = G_IMPLICIT_DEF\n" @@ -129,7 +129,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHIToNonGenericReg) { // here to cover the code that stops the analysis of PHIs // earlier. In that case, we would not even look at the // second incoming value. -TEST_F(GISelMITest, TestKnownBitsUnknownPHI) { +TEST_F(AArch64GISelMITest, TestKnownBitsUnknownPHI) { StringRef MIRString = " bb.10:\n" " %10:_(s64) = COPY %0\n" @@ -165,7 +165,7 @@ TEST_F(GISelMITest, TestKnownBitsUnknownPHI) { // For now, the analysis just stops and assumes it knows nothing, // eventually we could teach it how to properly track phis that // loop back. -TEST_F(GISelMITest, TestKnownBitsCstPHIWithLoop) { +TEST_F(AArch64GISelMITest, TestKnownBitsCstPHIWithLoop) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 3\n" @@ -210,7 +210,7 @@ TEST_F(GISelMITest, TestKnownBitsCstPHIWithLoop) { // on PHIs, but eventually we could teach it how to properly track // phis that loop back without relying on the luck effect of max // depth. -TEST_F(GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { +TEST_F(AArch64GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { StringRef MIRString = " bb.10:\n" " %10:_(s8) = G_CONSTANT i8 5\n" " %11:_(s8) = G_CONSTANT i8 1\n" @@ -243,7 +243,7 @@ TEST_F(GISelMITest, TestKnownBitsDecreasingCstPHIWithLoop) { EXPECT_EQ(Res.Zero.getZExtValue(), Res2.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsPtrToIntViceVersa) { +TEST_F(AArch64GISelMITest, TestKnownBitsPtrToIntViceVersa) { StringRef MIRString = " %3:_(s16) = G_CONSTANT i16 256\n" " %4:_(p0) = G_INTTOPTR %3\n" " %5:_(s32) = G_PTRTOINT %4\n" @@ -259,7 +259,7 @@ TEST_F(GISelMITest, TestKnownBitsPtrToIntViceVersa) { EXPECT_EQ(256u, Res.One.getZExtValue()); EXPECT_EQ(0xfffffeffu, Res.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBitsXOR) { +TEST_F(AArch64GISelMITest, TestKnownBitsXOR) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 4\n" " %4:_(s8) = G_CONSTANT i8 7\n" " %5:_(s8) = G_XOR %3, %4\n" @@ -276,7 +276,7 @@ TEST_F(GISelMITest, TestKnownBitsXOR) { EXPECT_EQ(252u, Res.Zero.getZExtValue()); } -TEST_F(GISelMITest, TestKnownBits) { +TEST_F(AArch64GISelMITest, TestKnownBits) { StringRef MIR = " %3:_(s32) = G_TRUNC %0\n" " %4:_(s32) = G_TRUNC %1\n" @@ -306,7 +306,7 @@ TEST_F(GISelMITest, TestKnownBits) { EXPECT_EQ(Known.Zero, Zeroes); } -TEST_F(GISelMITest, TestSignBitIsZero) { +TEST_F(AArch64GISelMITest, TestSignBitIsZero) { setUp(); if (!TM) return; @@ -321,7 +321,7 @@ TEST_F(GISelMITest, TestSignBitIsZero) { EXPECT_FALSE(KnownBits.signBitIsZero(SignBit.getReg(0))); } -TEST_F(GISelMITest, TestNumSignBitsConstant) { +TEST_F(AArch64GISelMITest, TestNumSignBitsConstant) { StringRef MIRString = " %3:_(s8) = G_CONSTANT i8 1\n" " %4:_(s8) = COPY %3\n" @@ -353,7 +353,7 @@ TEST_F(GISelMITest, TestNumSignBitsConstant) { EXPECT_EQ(3u, Info.computeNumSignBits(CopyRegNeg32)); } -TEST_F(GISelMITest, TestNumSignBitsSext) { +TEST_F(AArch64GISelMITest, TestNumSignBitsSext) { StringRef MIRString = " %3:_(p0) = G_IMPLICIT_DEF\n" " %4:_(s8) = G_LOAD %3 :: (load 1)\n" " %5:_(s32) = G_SEXT %4\n" @@ -373,7 +373,7 @@ TEST_F(GISelMITest, TestNumSignBitsSext) { EXPECT_EQ(32u, Info.computeNumSignBits(CopySextNeg1)); } -TEST_F(GISelMITest, TestNumSignBitsTrunc) { +TEST_F(AArch64GISelMITest, TestNumSignBitsTrunc) { StringRef MIRString = " %3:_(p0) = G_IMPLICIT_DEF\n" " %4:_(s32) = G_LOAD %3 :: (load 4)\n" " %5:_(s8) = G_TRUNC %4\n" @@ -398,3 +398,36 @@ TEST_F(GISelMITest, TestNumSignBitsTrunc) { EXPECT_EQ(8u, Info.computeNumSignBits(CopyTruncNeg1)); EXPECT_EQ(5u, Info.computeNumSignBits(CopyTrunc7)); } + +TEST_F(AMDGPUGISelMITest, TestNumSignBitsTrunc) { + StringRef MIRString = + " %3:_(<4 x s32>) = G_IMPLICIT_DEF\n" + " %4:_(s32) = G_IMPLICIT_DEF\n" + " %5:_(s32) = G_AMDGPU_BUFFER_LOAD_UBYTE %3, %4, %4, %4, 0, 0, 0 :: (load 1)\n" + " %6:_(s32) = COPY %5\n" + + " %7:_(s32) = G_AMDGPU_BUFFER_LOAD_SBYTE %3, %4, %4, %4, 0, 0, 0 :: (load 1)\n" + " %8:_(s32) = COPY %7\n" + + " %9:_(s32) = G_AMDGPU_BUFFER_LOAD_USHORT %3, %4, %4, %4, 0, 0, 0 :: (load 2)\n" + " %10:_(s32) = COPY %9\n" + + " %11:_(s32) = G_AMDGPU_BUFFER_LOAD_SSHORT %3, %4, %4, %4, 0, 0, 0 :: (load 2)\n" + " %12:_(s32) = COPY %11\n"; + + setUp(MIRString); + if (!TM) + return; + + Register CopyLoadUByte = Copies[Copies.size() - 4]; + Register CopyLoadSByte = Copies[Copies.size() - 3]; + Register CopyLoadUShort = Copies[Copies.size() - 2]; + Register CopyLoadSShort = Copies[Copies.size() - 1]; + + GISelKnownBits Info(*MF); + + EXPECT_EQ(24u, Info.computeNumSignBits(CopyLoadUByte)); + EXPECT_EQ(25u, Info.computeNumSignBits(CopyLoadSByte)); + EXPECT_EQ(16u, Info.computeNumSignBits(CopyLoadUShort)); + EXPECT_EQ(17u, Info.computeNumSignBits(CopyLoadSShort)); +} diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp index f47f9a364a73..3bc8f1f8f240 100644 --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerHelperTest.cpp @@ -25,7 +25,7 @@ class DummyGISelObserver : public GISelChangeObserver { // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom, // in which case it becomes CTTZ_ZERO_UNDEF with select. -TEST_F(GISelMITest, LowerBitCountingCTTZ0) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ0) { setUp(); if (!TM) return; @@ -57,7 +57,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ0) { } // CTTZ expansion in terms of CTLZ -TEST_F(GISelMITest, LowerBitCountingCTTZ1) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ1) { setUp(); if (!TM) return; @@ -91,7 +91,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ1) { } // CTLZ scalar narrowing -TEST_F(GISelMITest, NarrowScalarCTLZ) { +TEST_F(AArch64GISelMITest, NarrowScalarCTLZ) { setUp(); if (!TM) return; @@ -126,7 +126,7 @@ TEST_F(GISelMITest, NarrowScalarCTLZ) { } // CTTZ scalar narrowing -TEST_F(GISelMITest, NarrowScalarCTTZ) { +TEST_F(AArch64GISelMITest, NarrowScalarCTTZ) { setUp(); if (!TM) return; @@ -161,7 +161,7 @@ TEST_F(GISelMITest, NarrowScalarCTTZ) { } // CTTZ expansion in terms of CTPOP -TEST_F(GISelMITest, LowerBitCountingCTTZ2) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ2) { setUp(); if (!TM) return; @@ -192,7 +192,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ2) { } // CTPOP widening. -TEST_F(GISelMITest, WidenBitCountingCTPOP1) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP1) { if (!TM) return; @@ -224,7 +224,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP1) { } // Test a strange case where the result is wider than the source -TEST_F(GISelMITest, WidenBitCountingCTPOP2) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP2) { if (!TM) return; @@ -257,7 +257,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP2) { } // CTTZ_ZERO_UNDEF expansion in terms of CTTZ -TEST_F(GISelMITest, LowerBitCountingCTTZ3) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTTZ3) { setUp(); if (!TM) return; @@ -284,7 +284,7 @@ TEST_F(GISelMITest, LowerBitCountingCTTZ3) { } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF -TEST_F(GISelMITest, LowerBitCountingCTLZ0) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ0) { setUp(); if (!TM) return; @@ -315,7 +315,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZ0) { } // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall -TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZLibcall) { setUp(); if (!TM) return; @@ -346,7 +346,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) { } // CTLZ expansion -TEST_F(GISelMITest, LowerBitCountingCTLZ1) { +TEST_F(AArch64GISelMITest, LowerBitCountingCTLZ1) { setUp(); if (!TM) return; @@ -387,7 +387,7 @@ TEST_F(GISelMITest, LowerBitCountingCTLZ1) { } // CTLZ widening. -TEST_F(GISelMITest, WidenBitCountingCTLZ) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTLZ) { setUp(); if (!TM) return; @@ -422,7 +422,7 @@ TEST_F(GISelMITest, WidenBitCountingCTLZ) { } // CTLZ_ZERO_UNDEF widening. -TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTLZZeroUndef) { setUp(); if (!TM) return; @@ -458,7 +458,7 @@ TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) { } // CTPOP widening. -TEST_F(GISelMITest, WidenBitCountingCTPOP) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTPOP) { setUp(); if (!TM) return; @@ -491,7 +491,7 @@ TEST_F(GISelMITest, WidenBitCountingCTPOP) { } // CTTZ_ZERO_UNDEF widening. -TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { setUp(); if (!TM) return; @@ -525,7 +525,7 @@ TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) { } // CTTZ widening. -TEST_F(GISelMITest, WidenBitCountingCTTZ) { +TEST_F(AArch64GISelMITest, WidenBitCountingCTTZ) { setUp(); if (!TM) return; @@ -559,7 +559,7 @@ TEST_F(GISelMITest, WidenBitCountingCTTZ) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } // UADDO widening. -TEST_F(GISelMITest, WidenUADDO) { +TEST_F(AArch64GISelMITest, WidenUADDO) { setUp(); if (!TM) return; @@ -598,7 +598,7 @@ TEST_F(GISelMITest, WidenUADDO) { } // USUBO widening. -TEST_F(GISelMITest, WidenUSUBO) { +TEST_F(AArch64GISelMITest, WidenUSUBO) { setUp(); if (!TM) return; @@ -636,7 +636,7 @@ TEST_F(GISelMITest, WidenUSUBO) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, FewerElementsAnd) { +TEST_F(AArch64GISelMITest, FewerElementsAnd) { if (!TM) return; @@ -683,7 +683,7 @@ TEST_F(GISelMITest, FewerElementsAnd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, MoreElementsAnd) { +TEST_F(AArch64GISelMITest, MoreElementsAnd) { if (!TM) return; @@ -724,7 +724,7 @@ TEST_F(GISelMITest, MoreElementsAnd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, FewerElementsPhi) { +TEST_F(AArch64GISelMITest, FewerElementsPhi) { if (!TM) return; @@ -819,7 +819,7 @@ TEST_F(GISelMITest, FewerElementsPhi) { } // FNEG expansion in terms of FSUB -TEST_F(GISelMITest, LowerFNEG) { +TEST_F(AArch64GISelMITest, LowerFNEG) { if (!TM) return; @@ -864,7 +864,7 @@ TEST_F(GISelMITest, LowerFNEG) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerMinMax) { +TEST_F(AArch64GISelMITest, LowerMinMax) { if (!TM) return; @@ -942,7 +942,7 @@ TEST_F(GISelMITest, LowerMinMax) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenScalarBuildVector) { +TEST_F(AArch64GISelMITest, WidenScalarBuildVector) { if (!TM) return; @@ -988,7 +988,7 @@ TEST_F(GISelMITest, WidenScalarBuildVector) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerMergeValues) { +TEST_F(AArch64GISelMITest, LowerMergeValues) { if (!TM) return; @@ -1089,7 +1089,7 @@ TEST_F(GISelMITest, LowerMergeValues) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenScalarMergeValuesPointer) { +TEST_F(AArch64GISelMITest, WidenScalarMergeValuesPointer) { if (!TM) return; @@ -1126,7 +1126,7 @@ TEST_F(GISelMITest, WidenScalarMergeValuesPointer) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, WidenSEXTINREG) { +TEST_F(AArch64GISelMITest, WidenSEXTINREG) { if (!TM) return; @@ -1157,7 +1157,7 @@ TEST_F(GISelMITest, WidenSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, NarrowSEXTINREG) { +TEST_F(AArch64GISelMITest, NarrowSEXTINREG) { if (!TM) return; @@ -1188,7 +1188,7 @@ TEST_F(GISelMITest, NarrowSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, NarrowSEXTINREG2) { +TEST_F(AArch64GISelMITest, NarrowSEXTINREG2) { if (!TM) return; @@ -1220,7 +1220,7 @@ TEST_F(GISelMITest, NarrowSEXTINREG2) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, LowerSEXTINREG) { +TEST_F(AArch64GISelMITest, LowerSEXTINREG) { if (!TM) return; @@ -1250,7 +1250,7 @@ TEST_F(GISelMITest, LowerSEXTINREG) { ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr)); } -TEST_F(GISelMITest, LibcallFPExt) { +TEST_F(AArch64GISelMITest, LibcallFPExt) { setUp(); if (!TM) return; @@ -1289,7 +1289,7 @@ TEST_F(GISelMITest, LibcallFPExt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFPTrunc) { +TEST_F(AArch64GISelMITest, LibcallFPTrunc) { setUp(); if (!TM) return; @@ -1331,7 +1331,7 @@ TEST_F(GISelMITest, LibcallFPTrunc) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallSimple) { +TEST_F(AArch64GISelMITest, LibcallSimple) { setUp(); if (!TM) return; @@ -1354,7 +1354,7 @@ TEST_F(GISelMITest, LibcallSimple) { Helper.libcall(*MIBFADD)); } -TEST_F(GISelMITest, LibcallSRem) { +TEST_F(AArch64GISelMITest, LibcallSRem) { setUp(); if (!TM) return; @@ -1411,7 +1411,7 @@ TEST_F(GISelMITest, LibcallSRem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallURem) { +TEST_F(AArch64GISelMITest, LibcallURem) { setUp(); if (!TM) return; @@ -1468,7 +1468,7 @@ TEST_F(GISelMITest, LibcallURem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallCtlzZeroUndef) { +TEST_F(AArch64GISelMITest, LibcallCtlzZeroUndef) { setUp(); if (!TM) return; @@ -1521,7 +1521,7 @@ TEST_F(GISelMITest, LibcallCtlzZeroUndef) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFAdd) { +TEST_F(AArch64GISelMITest, LibcallFAdd) { setUp(); if (!TM) return; @@ -1573,7 +1573,7 @@ TEST_F(GISelMITest, LibcallFAdd) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFSub) { +TEST_F(AArch64GISelMITest, LibcallFSub) { setUp(); if (!TM) return; @@ -1625,7 +1625,7 @@ TEST_F(GISelMITest, LibcallFSub) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMul) { +TEST_F(AArch64GISelMITest, LibcallFMul) { setUp(); if (!TM) return; @@ -1677,7 +1677,7 @@ TEST_F(GISelMITest, LibcallFMul) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFDiv) { +TEST_F(AArch64GISelMITest, LibcallFDiv) { setUp(); if (!TM) return; @@ -1729,7 +1729,7 @@ TEST_F(GISelMITest, LibcallFDiv) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFExp) { +TEST_F(AArch64GISelMITest, LibcallFExp) { setUp(); if (!TM) return; @@ -1776,7 +1776,7 @@ TEST_F(GISelMITest, LibcallFExp) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFExp2) { +TEST_F(AArch64GISelMITest, LibcallFExp2) { setUp(); if (!TM) return; @@ -1823,7 +1823,7 @@ TEST_F(GISelMITest, LibcallFExp2) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFRem) { +TEST_F(AArch64GISelMITest, LibcallFRem) { setUp(); if (!TM) return; @@ -1870,7 +1870,7 @@ TEST_F(GISelMITest, LibcallFRem) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFPow) { +TEST_F(AArch64GISelMITest, LibcallFPow) { setUp(); if (!TM) return; @@ -1917,7 +1917,7 @@ TEST_F(GISelMITest, LibcallFPow) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMa) { +TEST_F(AArch64GISelMITest, LibcallFMa) { setUp(); if (!TM) return; @@ -1965,7 +1965,7 @@ TEST_F(GISelMITest, LibcallFMa) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFCeil) { +TEST_F(AArch64GISelMITest, LibcallFCeil) { setUp(); if (!TM) return; @@ -2012,7 +2012,7 @@ TEST_F(GISelMITest, LibcallFCeil) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFFloor) { +TEST_F(AArch64GISelMITest, LibcallFFloor) { setUp(); if (!TM) return; @@ -2059,7 +2059,7 @@ TEST_F(GISelMITest, LibcallFFloor) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMinNum) { +TEST_F(AArch64GISelMITest, LibcallFMinNum) { setUp(); if (!TM) return; @@ -2109,7 +2109,7 @@ TEST_F(GISelMITest, LibcallFMinNum) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFMaxNum) { +TEST_F(AArch64GISelMITest, LibcallFMaxNum) { setUp(); if (!TM) return; @@ -2159,7 +2159,7 @@ TEST_F(GISelMITest, LibcallFMaxNum) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFSqrt) { +TEST_F(AArch64GISelMITest, LibcallFSqrt) { setUp(); if (!TM) return; @@ -2206,7 +2206,7 @@ TEST_F(GISelMITest, LibcallFSqrt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFRint) { +TEST_F(AArch64GISelMITest, LibcallFRint) { setUp(); if (!TM) return; @@ -2253,7 +2253,7 @@ TEST_F(GISelMITest, LibcallFRint) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LibcallFNearbyInt) { +TEST_F(AArch64GISelMITest, LibcallFNearbyInt) { setUp(); if (!TM) return; @@ -2303,7 +2303,7 @@ TEST_F(GISelMITest, LibcallFNearbyInt) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, NarrowScalarExtract) { +TEST_F(AArch64GISelMITest, NarrowScalarExtract) { setUp(); if (!TM) return; @@ -2342,7 +2342,7 @@ TEST_F(GISelMITest, NarrowScalarExtract) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, LowerInsert) { +TEST_F(AArch64GISelMITest, LowerInsert) { setUp(); if (!TM) return; @@ -2443,7 +2443,7 @@ TEST_F(GISelMITest, LowerInsert) { } // Test lowering of G_FFLOOR -TEST_F(GISelMITest, LowerFFloor) { +TEST_F(AArch64GISelMITest, LowerFFloor) { setUp(); if (!TM) return; @@ -2475,7 +2475,7 @@ TEST_F(GISelMITest, LowerFFloor) { } // Test lowering of G_BSWAP -TEST_F(GISelMITest, LowerBSWAP) { +TEST_F(AArch64GISelMITest, LowerBSWAP) { setUp(); if (!TM) return; @@ -2517,7 +2517,7 @@ TEST_F(GISelMITest, LowerBSWAP) { } // Test widening of G_UNMERGE_VALUES -TEST_F(GISelMITest, WidenUnmerge) { +TEST_F(AArch64GISelMITest, WidenUnmerge) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp b/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp index afb4614f07e4..edae7f945712 100644 --- a/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/LegalizerTest.cpp @@ -49,7 +49,7 @@ DefineLegalizerInfo(ALegalizer, { getActionDefinitionsBuilder(G_SHL).legalFor({{s32, s32}}); }) -TEST_F(GISelMITest, BasicLegalizerTest) { +TEST_F(AArch64GISelMITest, BasicLegalizerTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) @@ -85,7 +85,7 @@ TEST_F(GISelMITest, BasicLegalizerTest) { // Making sure the legalization finishes successfully w/o failure to combine // away all the legalization artifacts regardless of the order of their // creation. -TEST_F(GISelMITest, UnorderedArtifactCombiningTest) { +TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) @@ -169,7 +169,7 @@ TEST_F(GISelMITest, UnorderedArtifactCombiningTest) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckString)) << *MF; } -TEST_F(GISelMITest, UnorderedArtifactCombiningManyCopiesTest) { +TEST_F(AArch64GISelMITest, UnorderedArtifactCombiningManyCopiesTest) { StringRef MIRString = R"( %vptr:_(p0) = COPY $x4 %v:_(<2 x s8>) = G_LOAD %vptr:_(p0) :: (load 2, align 1) diff --git a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp index f6fed8e75d2c..4d766cd42bee 100644 --- a/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/MachineIRBuilderTest.cpp @@ -9,7 +9,7 @@ #include "GISelMITest.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" -TEST_F(GISelMITest, TestBuildConstantFConstant) { +TEST_F(AArch64GISelMITest, TestBuildConstantFConstant) { setUp(); if (!TM) return; @@ -37,11 +37,10 @@ TEST_F(GISelMITest, TestBuildConstantFConstant) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } - #ifdef GTEST_HAS_DEATH_TEST #ifndef NDEBUG -TEST_F(GISelMITest, TestBuildConstantFConstantDeath) { +TEST_F(AArch64GISelMITest, TestBuildConstantFConstantDeath) { setUp(); if (!TM) return; @@ -73,7 +72,7 @@ TEST_F(GISelMITest, TestBuildConstantFConstantDeath) { #endif #endif -TEST_F(GISelMITest, DstOpSrcOp) { +TEST_F(AArch64GISelMITest, DstOpSrcOp) { setUp(); if (!TM) return; @@ -99,7 +98,7 @@ TEST_F(GISelMITest, DstOpSrcOp) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildUnmerge) { +TEST_F(AArch64GISelMITest, BuildUnmerge) { setUp(); if (!TM) return; @@ -120,7 +119,7 @@ TEST_F(GISelMITest, BuildUnmerge) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, TestBuildFPInsts) { +TEST_F(AArch64GISelMITest, TestBuildFPInsts) { setUp(); if (!TM) return; @@ -156,7 +155,7 @@ TEST_F(GISelMITest, TestBuildFPInsts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildIntrinsic) { +TEST_F(AArch64GISelMITest, BuildIntrinsic) { setUp(); if (!TM) return; @@ -185,7 +184,7 @@ TEST_F(GISelMITest, BuildIntrinsic) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildXor) { +TEST_F(AArch64GISelMITest, BuildXor) { setUp(); if (!TM) return; @@ -214,7 +213,7 @@ TEST_F(GISelMITest, BuildXor) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildBitCounts) { +TEST_F(AArch64GISelMITest, BuildBitCounts) { setUp(); if (!TM) return; @@ -242,7 +241,7 @@ TEST_F(GISelMITest, BuildBitCounts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildCasts) { +TEST_F(AArch64GISelMITest, BuildCasts) { setUp(); if (!TM) return; @@ -267,7 +266,7 @@ TEST_F(GISelMITest, BuildCasts) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildMinMax) { +TEST_F(AArch64GISelMITest, BuildMinMax) { setUp(); if (!TM) return; @@ -293,7 +292,7 @@ TEST_F(GISelMITest, BuildMinMax) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildAtomicRMW) { +TEST_F(AArch64GISelMITest, BuildAtomicRMW) { setUp(); if (!TM) return; @@ -324,7 +323,7 @@ TEST_F(GISelMITest, BuildAtomicRMW) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildMerge) { +TEST_F(AArch64GISelMITest, BuildMerge) { setUp(); if (!TM) return; @@ -363,7 +362,7 @@ TEST_F(GISelMITest, BuildMerge) { EXPECT_TRUE(CheckMachineFunction(*MF, CheckStr)) << *MF; } -TEST_F(GISelMITest, BuildAddoSubo) { +TEST_F(AArch64GISelMITest, BuildAddoSubo) { setUp(); if (!TM) return; diff --git a/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp b/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp index 66c1d6793a7a..172eca46b4a9 100644 --- a/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp +++ b/llvm/unittests/CodeGen/GlobalISel/PatternMatchTest.cpp @@ -30,7 +30,7 @@ using namespace MIPatternMatch; namespace { -TEST_F(GISelMITest, MatchIntConstant) { +TEST_F(AArch64GISelMITest, MatchIntConstant) { setUp(); if (!TM) return; @@ -41,7 +41,7 @@ TEST_F(GISelMITest, MatchIntConstant) { EXPECT_EQ(Cst, 42); } -TEST_F(GISelMITest, MatchBinaryOp) { +TEST_F(AArch64GISelMITest, MatchBinaryOp) { setUp(); if (!TM) return; @@ -139,7 +139,7 @@ TEST_F(GISelMITest, MatchBinaryOp) { EXPECT_EQ(Src1, TruncCopy1.getReg(0)); } -TEST_F(GISelMITest, MatchICmp) { +TEST_F(AArch64GISelMITest, MatchICmp) { setUp(); if (!TM) return; @@ -164,7 +164,7 @@ TEST_F(GISelMITest, MatchICmp) { EXPECT_EQ(Copies[1], Reg1); } -TEST_F(GISelMITest, MatchFCmp) { +TEST_F(AArch64GISelMITest, MatchFCmp) { setUp(); if (!TM) return; @@ -189,7 +189,7 @@ TEST_F(GISelMITest, MatchFCmp) { EXPECT_EQ(Copies[1], Reg1); } -TEST_F(GISelMITest, MatchFPUnaryOp) { +TEST_F(AArch64GISelMITest, MatchFPUnaryOp) { setUp(); if (!TM) return; @@ -251,7 +251,7 @@ TEST_F(GISelMITest, MatchFPUnaryOp) { EXPECT_NE(TmpFP16, TmpFP); } -TEST_F(GISelMITest, MatchExtendsTrunc) { +TEST_F(AArch64GISelMITest, MatchExtendsTrunc) { setUp(); if (!TM) return; @@ -298,7 +298,7 @@ TEST_F(GISelMITest, MatchExtendsTrunc) { EXPECT_EQ(Src0, Copies[0]); } -TEST_F(GISelMITest, MatchSpecificType) { +TEST_F(AArch64GISelMITest, MatchSpecificType) { setUp(); if (!TM) return; @@ -335,7 +335,7 @@ TEST_F(GISelMITest, MatchSpecificType) { EXPECT_EQ(Src0, Copies[0]); } -TEST_F(GISelMITest, MatchCombinators) { +TEST_F(AArch64GISelMITest, MatchCombinators) { setUp(); if (!TM) return; @@ -369,7 +369,7 @@ TEST_F(GISelMITest, MatchCombinators) { EXPECT_FALSE(match); } -TEST_F(GISelMITest, MatchMiscellaneous) { +TEST_F(AArch64GISelMITest, MatchMiscellaneous) { setUp(); if (!TM) return; diff --git a/llvm/unittests/MC/AMDGPU/CMakeLists.txt b/llvm/unittests/MC/AMDGPU/CMakeLists.txt index b3581949a6da..9a77415590d7 100644 --- a/llvm/unittests/MC/AMDGPU/CMakeLists.txt +++ b/llvm/unittests/MC/AMDGPU/CMakeLists.txt @@ -1,5 +1,7 @@ set(LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} + AMDGPUCodeGen + AMDGPUDesc + AMDGPUInfo MC Support ) diff --git a/llvm/unittests/MC/CMakeLists.txt b/llvm/unittests/MC/CMakeLists.txt index 05d6410bd8f7..48c06183ab99 100644 --- a/llvm/unittests/MC/CMakeLists.txt +++ b/llvm/unittests/MC/CMakeLists.txt @@ -1,3 +1,9 @@ +foreach(t ${LLVM_TARGETS_TO_BUILD}) + if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${t}) + add_subdirectory(${t}) + endif() +endforeach() + set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} MC @@ -13,4 +19,3 @@ add_llvm_unittest(MCTests TargetRegistry.cpp ) -add_subdirectory(AMDGPU) diff --git a/llvm/unittests/Passes/CMakeLists.txt b/llvm/unittests/Passes/CMakeLists.txt index c04aa9f84458..823bc56851fa 100644 --- a/llvm/unittests/Passes/CMakeLists.txt +++ b/llvm/unittests/Passes/CMakeLists.txt @@ -16,7 +16,7 @@ if (NOT WIN32) add_llvm_unittest(PluginsTests PluginsTest.cpp ) - export_executable_symbols(PluginsTests) + export_executable_symbols_for_plugins(PluginsTests) target_link_libraries(PluginsTests PRIVATE LLVMTestingSupport) set(LLVM_LINK_COMPONENTS) diff --git a/llvm/unittests/Support/Path.cpp b/llvm/unittests/Support/Path.cpp index affba601a8bc..671966b52dd0 100644 --- a/llvm/unittests/Support/Path.cpp +++ b/llvm/unittests/Support/Path.cpp @@ -1895,7 +1895,7 @@ TEST_F(FileSystemTest, widenPath) { // Result should not start with the long path prefix. EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(), LongPathPrefix.size()) != 0); - EXPECT_EQ(Result.size(), MAX_PATH - 1); + EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1); // Add another Pi to exceed the MAX_PATH limit. Input += Pi; @@ -1921,7 +1921,7 @@ TEST_F(FileSystemTest, widenPath) { // Result should not start with the long path prefix. EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(), LongPathPrefix.size()) != 0); - EXPECT_EQ(Result.size(), MAX_PATH - 1); + EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1); // Extend the directory name so the input exceeds the MAX_PATH limit. DirName += DirChar; diff --git a/llvm/unittests/Target/AMDGPU/CMakeLists.txt b/llvm/unittests/Target/AMDGPU/CMakeLists.txt index 3e8134708b4f..ba6b92f378a6 100644 --- a/llvm/unittests/Target/AMDGPU/CMakeLists.txt +++ b/llvm/unittests/Target/AMDGPU/CMakeLists.txt @@ -4,9 +4,11 @@ include_directories( ) set(LLVM_LINK_COMPONENTS - ${LLVM_TARGETS_TO_BUILD} + AMDGPUCodeGen + AMDGPUDesc + AMDGPUInfo + MC Support - Target ) add_llvm_target_unittest(AMDGPUTests diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp b/llvm/unittests/Transforms/Utils/LocalTest.cpp index cd32669ca2f6..4fa6a09f2022 100644 --- a/llvm/unittests/Transforms/Utils/LocalTest.cpp +++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp @@ -1001,3 +1001,63 @@ TEST(Local, SimplifyCFGWithNullAC) { // %test.bb is expected to be simplified by FoldCondBranchOnPHI. EXPECT_TRUE(simplifyCFG(TestBB, TTI, Options)); } + +TEST(Local, CanReplaceOperandWithVariable) { + LLVMContext Ctx; + Module M("test_module", Ctx); + IRBuilder<> B(Ctx); + + FunctionType *FnType = + FunctionType::get(Type::getVoidTy(Ctx), {}, false); + + FunctionType *VarArgFnType = + FunctionType::get(Type::getVoidTy(Ctx), {B.getInt32Ty()}, true); + + Function *TestBody = Function::Create(FnType, GlobalValue::ExternalLinkage, + 0, "", &M); + + BasicBlock *BB0 = BasicBlock::Create(Ctx, "", TestBody); + B.SetInsertPoint(BB0); + + Value *Intrin = M.getOrInsertFunction("llvm.foo", FnType).getCallee(); + Value *Func = M.getOrInsertFunction("foo", FnType).getCallee(); + Value *VarArgFunc + = M.getOrInsertFunction("foo.vararg", VarArgFnType).getCallee(); + Value *VarArgIntrin + = M.getOrInsertFunction("llvm.foo.vararg", VarArgFnType).getCallee(); + + auto *CallToIntrin = B.CreateCall(Intrin); + auto *CallToFunc = B.CreateCall(Func); + + // Test if it's valid to replace the callee operand. + EXPECT_FALSE(canReplaceOperandWithVariable(CallToIntrin, 0)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToFunc, 0)); + + // That it's invalid to replace an argument in the variadic argument list for + // an intrinsic, but OK for a normal function. + auto *CallToVarArgFunc = B.CreateCall( + VarArgFunc, {B.getInt32(0), B.getInt32(1), B.getInt32(2)}); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 0)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 1)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 2)); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgFunc, 3)); + + auto *CallToVarArgIntrin = B.CreateCall( + VarArgIntrin, {B.getInt32(0), B.getInt32(1), B.getInt32(2)}); + EXPECT_TRUE(canReplaceOperandWithVariable(CallToVarArgIntrin, 0)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 1)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 2)); + EXPECT_FALSE(canReplaceOperandWithVariable(CallToVarArgIntrin, 3)); + + // Test that it's invalid to replace gcroot operands, even though it can't use + // immarg. + Type *PtrPtr = B.getInt8Ty()->getPointerTo(0); + Value *Alloca = B.CreateAlloca(PtrPtr, (unsigned)0); + CallInst *GCRoot = B.CreateIntrinsic(Intrinsic::gcroot, {}, + {Alloca, Constant::getNullValue(PtrPtr)}); + EXPECT_TRUE(canReplaceOperandWithVariable(GCRoot, 0)); // Alloca + EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 1)); + EXPECT_FALSE(canReplaceOperandWithVariable(GCRoot, 2)); + + BB0->dropAllReferences(); +} diff --git a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn index 228d13446cab..f37cc42c481e 100644 --- a/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/StaticAnalyzer/Core/BUILD.gn @@ -57,6 +57,7 @@ static_library("Core") { "Store.cpp", "SubEngine.cpp", "SymbolManager.cpp", + "TextDiagnostics.cpp", "WorkList.cpp", ] } diff --git a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni index 8306b5daabcc..2590432529b6 100644 --- a/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni +++ b/llvm/utils/gn/secondary/llvm/lib/Target/targets.gni @@ -44,6 +44,7 @@ if (llvm_targets_to_build == "host") { # and remember which targets are built where needed (for conditionally-built # unittest targets). llvm_build_AArch64 = false +llvm_build_AMDGPU = false llvm_build_ARM = false llvm_build_BPF = false llvm_build_Mips = false @@ -53,6 +54,8 @@ llvm_build_X86 = false foreach(target, llvm_targets_to_build) { if (target == "AArch64") { llvm_build_AArch64 = true + } else if (target == "AMDGPU") { + llvm_build_AMDGPU = true } else if (target == "ARM") { llvm_build_ARM = true } else if (target == "BPF") { @@ -65,7 +68,7 @@ foreach(target, llvm_targets_to_build) { llvm_build_WebAssembly = true } else if (target == "X86") { llvm_build_X86 = true - } else if (target == "AMDGPU" || target == "AVR" || target == "Hexagon" || + } else if (target == "AVR" || target == "Hexagon" || target == "Lanai" || target == "NVPTX" || target == "RISCV" || target == "Sparc" || target == "SystemZ") { # Nothing to do. diff --git a/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn index fb951086571d..3d960d501e42 100644 --- a/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/unittests/BUILD.gn @@ -56,6 +56,12 @@ group("unittests") { "tools/llvm-exegesis/AArch64:LLVMExegesisAArch64Tests", ] } + if (llvm_build_AMDGPU) { + deps += [ + "MC/AMDGPU:AMDGPUDwarfTests", + "Target/AMDGPU:AMDGPUTests", + ] + } if (llvm_build_ARM) { deps += [ "Target/ARM:ARMTests", diff --git a/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn new file mode 100644 index 000000000000..8d1763e65f0c --- /dev/null +++ b/llvm/utils/gn/secondary/llvm/unittests/MC/AMDGPU/BUILD.gn @@ -0,0 +1,14 @@ +import("//llvm/utils/unittest/unittest.gni") + +unittest("AMDGPUDwarfTests") { + deps = [ + "//llvm/lib/MC", + "//llvm/lib/Support", + "//llvm/lib/Target/AMDGPU:LLVMAMDGPUCodeGen", + "//llvm/lib/Target/AMDGPU/MCTargetDesc", + "//llvm/lib/Target/AMDGPU/TargetInfo", + ] + sources = [ + "DwarfRegMappings.cpp", + ] +} diff --git a/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn new file mode 100644 index 000000000000..238ff86b771c --- /dev/null +++ b/llvm/utils/gn/secondary/llvm/unittests/Target/AMDGPU/BUILD.gn @@ -0,0 +1,17 @@ +import("//llvm/utils/unittest/unittest.gni") + +unittest("AMDGPUTests") { + deps = [ + "//llvm/lib/Support", + "//llvm/lib/Target", + "//llvm/lib/Target/AMDGPU:LLVMAMDGPUCodeGen", + "//llvm/lib/Target/AMDGPU/MCTargetDesc", + "//llvm/lib/Target/AMDGPU/TargetInfo", + "//llvm/lib/Target/AMDGPU/Utils", + ] + include_dirs = [ "//llvm/lib/Target/AMDGPU" ] + sources = [ + # Make `gn format` not collapse this, for sync_source_lists_from_cmake.py. + "DwarfRegMappings.cpp", + ] +} diff --git a/mlir/include/mlir/Dialect/LoopOps/LoopOps.td b/mlir/include/mlir/Dialect/LoopOps/LoopOps.td index a20c44fa5e16..7b010729831b 100644 --- a/mlir/include/mlir/Dialect/LoopOps/LoopOps.td +++ b/mlir/include/mlir/Dialect/LoopOps/LoopOps.td @@ -223,20 +223,21 @@ def IfOp : Loop_Op<"if", OpBuilder<"Builder *builder, OperationState &result, " "Value cond, bool withElseRegion">, OpBuilder<"Builder *builder, OperationState &result, " - "TypeRange resultTypes, Value cond, " - "bool withElseRegion"> + "TypeRange resultTypes, Value cond, bool withElseRegion"> ]; let extraClassDeclaration = [{ OpBuilder getThenBodyBuilder() { assert(!thenRegion().empty() && "Unexpected empty 'then' region."); Block &body = thenRegion().front(); - return OpBuilder(&body, std::prev(body.end())); + return OpBuilder(&body, + results().empty() ? std::prev(body.end()) : body.end()); } OpBuilder getElseBodyBuilder() { assert(!elseRegion().empty() && "Unexpected empty 'else' region."); Block &body = elseRegion().front(); - return OpBuilder(&body, std::prev(body.end())); + return OpBuilder(&body, + results().empty() ? std::prev(body.end()) : body.end()); } }]; } diff --git a/mlir/include/mlir/Transforms/FoldUtils.h b/mlir/include/mlir/Transforms/FoldUtils.h index 83ce3bf0d072..0bab87c5e4e3 100644 --- a/mlir/include/mlir/Transforms/FoldUtils.h +++ b/mlir/include/mlir/Transforms/FoldUtils.h @@ -75,11 +75,20 @@ class OperationFolder { template void create(OpBuilder &builder, SmallVectorImpl &results, Location location, Args &&... args) { - Operation *op = builder.create(location, std::forward(args)...); - if (failed(tryToFold(op, results))) + // The op needs to be inserted only if the fold (below) fails, or the number + // of results of the op is zero (which is treated as an in-place + // fold). Using create methods of the builder will insert the op, so not + // using it here. + OperationState state(location, OpTy::getOperationName()); + OpTy::build(&builder, state, std::forward(args)...); + Operation *op = Operation::create(state); + + if (failed(tryToFold(builder, op, results)) || op->getNumResults() == 0) { + builder.insert(op); results.assign(op->result_begin(), op->result_end()); - else if (op->getNumResults() != 0) - op->erase(); + return; + } + op->destroy(); } /// Overload to create or fold a single result operation. @@ -120,7 +129,7 @@ class OperationFolder { /// Tries to perform folding on the given `op`. If successful, populates /// `results` with the results of the folding. LogicalResult tryToFold( - Operation *op, SmallVectorImpl &results, + OpBuilder &builder, Operation *op, SmallVectorImpl &results, function_ref processGeneratedConstants = nullptr); /// Try to get or create a new constant entry. On success this returns the diff --git a/mlir/lib/Dialect/AVX512/CMakeLists.txt b/mlir/lib/Dialect/AVX512/CMakeLists.txt index 3f03959891ca..eb1e7dc5c4b5 100644 --- a/mlir/lib/Dialect/AVX512/CMakeLists.txt +++ b/mlir/lib/Dialect/AVX512/CMakeLists.txt @@ -11,5 +11,6 @@ target_link_libraries(MLIRAVX512 PUBLIC MLIRIR MLIRSideEffects + MLIRVectorToLLVM LLVMSupport ) diff --git a/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt index 9cdc4b92fcd5..89abbd521dec 100644 --- a/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt +++ b/mlir/lib/Dialect/Affine/Transforms/CMakeLists.txt @@ -19,7 +19,11 @@ target_link_libraries(MLIRAffineTransforms MLIRAffine MLIREDSC MLIRIR + MLIRPass MLIRSideEffects MLIRStandardOps + MLIRTransformUtils + MLIRVector + MLIRVectorToLLVM ) diff --git a/mlir/lib/Dialect/LoopOps/LoopOps.cpp b/mlir/lib/Dialect/LoopOps/LoopOps.cpp index 5106cc63cb46..3d7ee3846c22 100644 --- a/mlir/lib/Dialect/LoopOps/LoopOps.cpp +++ b/mlir/lib/Dialect/LoopOps/LoopOps.cpp @@ -201,18 +201,25 @@ ForOp mlir::loop::getForInductionVarOwner(Value val) { void IfOp::build(Builder *builder, OperationState &result, Value cond, bool withElseRegion) { - build(builder, result, /*resultTypes=*/llvm::None, cond, withElseRegion); + build(builder, result, /*resultTypes=*/llvm::None, cond, withElseRegion); } void IfOp::build(Builder *builder, OperationState &result, TypeRange resultTypes, Value cond, bool withElseRegion) { result.addOperands(cond); result.addTypes(resultTypes); + Region *thenRegion = result.addRegion(); + thenRegion->push_back(new Block()); + if (resultTypes.empty()) + IfOp::ensureTerminator(*thenRegion, *builder, result.location); + Region *elseRegion = result.addRegion(); - IfOp::ensureTerminator(*thenRegion, *builder, result.location); - if (withElseRegion) - IfOp::ensureTerminator(*elseRegion, *builder, result.location); + if (withElseRegion) { + elseRegion->push_back(new Block()); + if (resultTypes.empty()) + IfOp::ensureTerminator(*elseRegion, *builder, result.location); + } } static LogicalResult verify(IfOp op) { diff --git a/mlir/lib/Transforms/Utils/FoldUtils.cpp b/mlir/lib/Transforms/Utils/FoldUtils.cpp index 7d209b2231a2..f2099bca75ea 100644 --- a/mlir/lib/Transforms/Utils/FoldUtils.cpp +++ b/mlir/lib/Transforms/Utils/FoldUtils.cpp @@ -24,8 +24,8 @@ using namespace mlir; /// inserted into. static Region *getInsertionRegion( DialectInterfaceCollection &interfaces, - Operation *op) { - while (Region *region = op->getParentRegion()) { + Block *insertionBlock) { + while (Region *region = insertionBlock->getParent()) { // Insert in this region for any of the following scenarios: // * The parent is unregistered, or is known to be isolated from above. // * The parent is a top-level operation. @@ -40,7 +40,7 @@ static Region *getInsertionRegion( return region; // Traverse up the parent looking for an insertion region. - op = parentOp; + insertionBlock = parentOp->getBlock(); } llvm_unreachable("expected valid insertion region"); } @@ -82,7 +82,8 @@ LogicalResult OperationFolder::tryToFold( // Try to fold the operation. SmallVector results; - if (failed(tryToFold(op, results, processGeneratedConstants))) + OpBuilder builder(op); + if (failed(tryToFold(builder, op, results, processGeneratedConstants))) return failure(); // Check to see if the operation was just updated in place. @@ -117,7 +118,8 @@ void OperationFolder::notifyRemoval(Operation *op) { assert(constValue); // Get the constant map that this operation was uniqued in. - auto &uniquedConstants = foldScopes[getInsertionRegion(interfaces, op)]; + auto &uniquedConstants = + foldScopes[getInsertionRegion(interfaces, op->getBlock())]; // Erase all of the references to this operation. auto type = op->getResult(0).getType(); @@ -135,7 +137,7 @@ void OperationFolder::clear() { /// Tries to perform folding on the given `op`. If successful, populates /// `results` with the results of the folding. LogicalResult OperationFolder::tryToFold( - Operation *op, SmallVectorImpl &results, + OpBuilder &builder, Operation *op, SmallVectorImpl &results, function_ref processGeneratedConstants) { SmallVector operandConstants; SmallVector foldResults; @@ -164,9 +166,11 @@ LogicalResult OperationFolder::tryToFold( // Create a builder to insert new operations into the entry block of the // insertion region. - auto *insertRegion = getInsertionRegion(interfaces, op); + auto *insertRegion = + getInsertionRegion(interfaces, builder.getInsertionBlock()); auto &entry = insertRegion->front(); - OpBuilder builder(&entry, entry.begin()); + OpBuilder::InsertionGuard foldGuard(builder); + builder.setInsertionPoint(&entry, entry.begin()); // Get the constant map for the insertion region of this operation. auto &uniquedConstants = foldScopes[insertRegion]; diff --git a/mlir/test/lib/TestDialect/CMakeLists.txt b/mlir/test/lib/TestDialect/CMakeLists.txt index d625a5819096..0d8b13c61030 100644 --- a/mlir/test/lib/TestDialect/CMakeLists.txt +++ b/mlir/test/lib/TestDialect/CMakeLists.txt @@ -27,6 +27,7 @@ target_link_libraries(MLIRTestDialect MLIRLinalgTransforms MLIRPass MLIRStandardOps + MLIRStandardToStandard MLIRTransforms MLIRTransformUtils MLIRInferTypeOpInterface diff --git a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp index 2a2259547b37..e0c4c1907c4f 100644 --- a/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp +++ b/mlir/test/lib/Transforms/TestConvertGPUKernelToCubin.cpp @@ -9,18 +9,15 @@ #include "mlir/Conversion/GPUToCUDA/GPUToCUDAPass.h" #include "mlir/Pass/Pass.h" #include "mlir/Pass/PassManager.h" - using namespace mlir; -namespace { +#if MLIR_CUDA_CONVERSIONS_ENABLED static OwnedCubin compilePtxToCubinForTesting(const std::string &, Location, StringRef) { const char data[] = "CUBIN"; return std::make_unique>(data, data + sizeof(data) - 1); } -} // end anonymous namespace -#if MLIR_CUDA_CONVERSIONS_ENABLED namespace mlir { void registerTestConvertGPUKernelToCubinPass() { PassPipelineRegistration<>("test-kernel-to-cubin", diff --git a/openmp/runtime/src/kmp_tasking.cpp b/openmp/runtime/src/kmp_tasking.cpp index 15ffc1454fe9..6dae9dc73e7a 100644 --- a/openmp/runtime/src/kmp_tasking.cpp +++ b/openmp/runtime/src/kmp_tasking.cpp @@ -3923,9 +3923,12 @@ kmp_task_t *__kmp_task_dup_alloc(kmp_info_t *thread, kmp_task_t *task_src) { } taskdata->td_alloc_thread = thread; taskdata->td_parent = parent_task; - taskdata->td_taskgroup = - parent_task - ->td_taskgroup; // task inherits the taskgroup from the parent task + // task inherits the taskgroup from the parent task + taskdata->td_taskgroup = parent_task->td_taskgroup; + // tied task needs to initialize the td_last_tied at creation, + // untied one does this when it is scheduled for execution + if (taskdata->td_flags.tiedness == TASK_TIED) + taskdata->td_last_tied = taskdata; // Only need to keep track of child task counts if team parallel and tasking // not serialized diff --git a/openmp/runtime/test/tasking/omp_task_red_taskloop.c b/openmp/runtime/test/tasking/omp_task_red_taskloop.c new file mode 100644 index 000000000000..89c66256da73 --- /dev/null +++ b/openmp/runtime/test/tasking/omp_task_red_taskloop.c @@ -0,0 +1,57 @@ +// RUN: %libomp-compile-and-run + +#include +#include + +int r; + +int work(int k, int l) +{ + return k + l + 1; +} +void bar(int i) { + #pragma omp taskgroup task_reduction(+:r) + { int th_gen = omp_get_thread_num(); + #pragma omp task in_reduction(+:r) firstprivate(i, th_gen) + { + r += work(i, 0); +printf("executing task (%d, 0), th %d (gen by th %d)\n", i, omp_get_thread_num(), th_gen); + } + #pragma omp task in_reduction(+:r) firstprivate(i, th_gen) + { + r += work(i, 1); +printf("executing task (%d, 1), th %d (gen by th %d)\n", i, omp_get_thread_num(), th_gen); + } + } +} +int foo() { + int i; + int th_gen = omp_get_thread_num(); + #pragma omp taskgroup task_reduction(+:r) + { + bar(0); + } +printf("th %d passed bar0\n", th_gen); + #pragma omp taskloop reduction(+:r) firstprivate(th_gen) + for (i = 1; i < 4; ++i) { + bar(i); +printf("th %d (gen by th %d) passed bar%d in taskloop\n", omp_get_thread_num(), th_gen, i); +// #pragma omp task in_reduction(+:r) + r += i; + } + return 0; +} +// res = 2*((1+2)+(2+3)+(3+4)+(4+5)+1+2+3) = 60 +#define res 60 +int main() +{ + r = 0; + #pragma omp parallel num_threads(2) + foo(); + if (r == res) { + return 0; + } else { + printf("error r = %d (!= %d)\n", r, res); + return 1; + } +}