diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
commit | 8746d127c04f5bbaf6c6e88cef8606ca5a6a54e9 (patch) | |
tree | 84c9d77f8c764f04bcef0b1da4eedfa233d67a46 | |
parent | cf1b401909b5e54edfd80656b1a18eaa31f9f6f1 (diff) |
Vendor import of clang trunk r307894:vendor/clang/clang-trunk-r307894
Notes
Notes:
svn path=/vendor/clang/dist/; revision=320959
svn path=/vendor/clang/clang-trunk-r307894/; revision=320960; tag=vendor/clang/clang-trunk-r307894
269 files changed, 6842 insertions, 3728 deletions
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 5e70bde770f8..236803a9ab9b 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -782,7 +782,7 @@ CursorKind.CONVERSION_FUNCTION = CursorKind(26) # A C++ template type parameter CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27) -# A C++ non-type template paramater. +# A C++ non-type template parameter. CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28) # A C++ template template parameter. @@ -1478,6 +1478,11 @@ class Cursor(Structure): """ return conf.lib.clang_CXXMethod_isVirtual(self) + def is_scoped_enum(self): + """Returns True if the cursor refers to a scoped enum declaration. + """ + return conf.lib.clang_EnumDecl_isScoped(self) + def get_definition(self): """ If the cursor is a reference to a declaration or a declaration of @@ -3314,6 +3319,10 @@ functionList = [ [Cursor], bool), + ("clang_EnumDecl_isScoped", + [Cursor], + bool), + ("clang_defaultDiagnosticDisplayOptions", [], c_uint), diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py index 8103e96df4f9..4787ea931e13 100644 --- a/bindings/python/tests/cindex/test_cursor.py +++ b/bindings/python/tests/cindex/test_cursor.py @@ -255,6 +255,22 @@ def test_is_virtual_method(): assert foo.is_virtual_method() assert not bar.is_virtual_method() +def test_is_scoped_enum(): + """Ensure Cursor.is_scoped_enum works.""" + source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' + tu = get_tu(source, lang='cpp') + + cls = get_cursor(tu, 'X') + regular_enum = get_cursor(tu, 'RegularEnum') + scoped_enum = get_cursor(tu, 'ScopedEnum') + assert cls is not None + assert regular_enum is not None + assert scoped_enum is not None + + assert not cls.is_scoped_enum() + assert not regular_enum.is_scoped_enum() + assert scoped_enum.is_scoped_enum() + def test_underlying_type(): tu = get_tu('typedef int foo;') typedef = get_cursor(tu, 'foo') diff --git a/docs/ControlFlowIntegrityDesign.rst b/docs/ControlFlowIntegrityDesign.rst index 69b72f9ea5b2..e4225b35476a 100644 --- a/docs/ControlFlowIntegrityDesign.rst +++ b/docs/ControlFlowIntegrityDesign.rst @@ -437,12 +437,17 @@ export this information, every DSO implements .. code-block:: none - void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr) - -This function provides external modules with access to CFI checks for the -targets inside this DSO. For each known ``CallSiteTypeId``, this function -performs an ``llvm.type.test`` with the corresponding type identifier. It -aborts if the type is unknown, or if the check fails. + void __cfi_check(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData) + +This function provides external modules with access to CFI checks for +the targets inside this DSO. For each known ``CallSiteTypeId``, this +function performs an ``llvm.type.test`` with the corresponding type +identifier. It reports an error if the type is unknown, or if the +check fails. Depending on the values of compiler flags +``-fsanitize-trap`` and ``-fsanitize-recover``, this function may +print an error, abort and/or return to the caller. ``DiagData`` is an +opaque pointer to the diagnostic information about the error, or +``null`` if the caller does not provide this information. The basic implementation is a large switch statement over all values of CallSiteTypeId supported by this DSO, and each case is similar to @@ -452,11 +457,10 @@ CFI Shadow ---------- To route CFI checks to the target DSO's __cfi_check function, a -mapping from possible virtual / indirect call targets to -the corresponding __cfi_check functions is maintained. This mapping is +mapping from possible virtual / indirect call targets to the +corresponding __cfi_check functions is maintained. This mapping is implemented as a sparse array of 2 bytes for every possible page (4096 -bytes) of memory. The table is kept readonly (FIXME: not yet) most of -the time. +bytes) of memory. The table is kept readonly most of the time. There are 3 types of shadow values: @@ -481,14 +485,24 @@ them. CFI_SlowPath ------------ -The slow path check is implemented in compiler-rt library as +The slow path check is implemented in a runtime support library as .. code-block:: none void __cfi_slowpath(uint64 CallSiteTypeId, void *TargetAddr) - -This functions loads a shadow value for ``TargetAddr``, finds the -address of __cfi_check as described above and calls that. + void __cfi_slowpath_diag(uint64 CallSiteTypeId, void *TargetAddr, void *DiagData) + +These functions loads a shadow value for ``TargetAddr``, finds the +address of ``__cfi_check`` as described above and calls +that. ``DiagData`` is an opaque pointer to diagnostic data which is +passed verbatim to ``__cfi_check``, and ``__cfi_slowpath`` passes +``nullptr`` instead. + +Compiler-RT library contains reference implementations of slowpath +functions, but they have unresolvable issues with correctness and +performance in the handling of dlopen(). It is recommended that +platforms provide their own implementations, usually as part of libc +or libdl. Position-independent executable requirement ------------------------------------------- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index a0403a5edf65..cb5020af49c6 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1872,6 +1872,14 @@ floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2)) integerLiteral(equals(42)) matches 42 +Note that you cannot directly match a negative numeric literal because the +minus sign is not part of the literal: It is a unary operator whose operand +is the positive numeric literal. Instead, you must use a unaryOperator() +matcher to match the minus sign: + +unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(equals(13)))) + Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>> </pre></td></tr> @@ -2327,6 +2335,14 @@ floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2)) integerLiteral(equals(42)) matches 42 +Note that you cannot directly match a negative numeric literal because the +minus sign is not part of the literal: It is a unary operator whose operand +is the positive numeric literal. Instead, you must use a unaryOperator() +matcher to match the minus sign: + +unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(equals(13)))) + Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>> </pre></td></tr> @@ -2583,6 +2599,14 @@ floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2)) integerLiteral(equals(42)) matches 42 +Note that you cannot directly match a negative numeric literal because the +minus sign is not part of the literal: It is a unary operator whose operand +is the positive numeric literal. Instead, you must use a unaryOperator() +matcher to match the minus sign: + +unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(equals(13)))) + Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>> </pre></td></tr> @@ -2866,6 +2890,14 @@ floatLiteral(equals(3.14)) and floatLiteral(equals(314e-2)) integerLiteral(equals(42)) matches 42 +Note that you cannot directly match a negative numeric literal because the +minus sign is not part of the literal: It is a unary operator whose operand +is the positive numeric literal. Instead, you must use a unaryOperator() +matcher to match the minus sign: + +unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(equals(13)))) + Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CharacterLiteral.html">CharacterLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1CXXBoolLiteralExpr.html">CXXBoolLiteralExpr</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>, Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1IntegerLiteral.html">IntegerLiteral</a>> </pre></td></tr> diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index f9a3317811eb..8f1515dafd97 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -52,6 +52,9 @@ Major New Features Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- -Wcast-qual was implemented for C++. C-style casts are now properly + diagnosed. + - -Wunused-lambda-capture warns when a variable explicitly captured by a lambda is not used in the body of the lambda. @@ -60,6 +63,16 @@ New Compiler Flags The option .... +Deprecated Compiler Flags +------------------------- + +The following options are deprecated and ignored. They will be removed in +future versions of Clang. + +- -fslp-vectorize-aggressive used to enable the BB vectorizing pass. They have been superseeded + by the normal SLP vectorizer. +- -fno-slp-vectorize-aggressive used to be the default behavior of clang. + New Pragmas in Clang ----------------------- diff --git a/docs/UsersManual.rst b/docs/UsersManual.rst index df6344af9102..387ec63e9c3d 100644 --- a/docs/UsersManual.rst +++ b/docs/UsersManual.rst @@ -332,6 +332,19 @@ output format of the diagnostics that it generates. using a structured YAML format, users can parse or sort the remarks in a convenient way. +.. _opt_foptimization-record-file: + +**-foptimization-record-file** + Control the file to which optimization reports are written. + + When optimization reports are being output (see + :ref:`-fsave-optimization-record <opt_fsave-optimization-record>`), this + option controls the file to which those reports are written. + + If this option is not used, optimization records are output to a file named + after the primary file being compiled. If that's "foo.c", for example, + optimization records are output to "foo.opt.yaml". + .. _opt_fdiagnostics-show-hotness: **-f[no-]diagnostics-show-hotness** diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index f404e6d72ec9..09f4403556c8 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -4417,6 +4417,11 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isStatic(CXCursor C); CINDEX_LINKAGE unsigned clang_CXXMethod_isVirtual(CXCursor C); /** + * \brief Determine if an enum declaration refers to a scoped enum. + */ +CINDEX_LINKAGE unsigned clang_EnumDecl_isScoped(CXCursor C); + +/** * \brief Determine if a C++ member function or member function template is * declared 'const'. */ diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 0f1f481ae49b..041f0fd484d4 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -749,7 +749,7 @@ public: /// Set that this declaration is globally visible, even if it came from a /// module that is not visible. void setVisibleDespiteOwningModule() { - if (hasOwningModule()) + if (isHidden()) setModuleOwnershipKind(ModuleOwnershipKind::Visible); } diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 6965e8143ff6..9d64f0244ec3 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1886,6 +1886,19 @@ public: return (CD->begin_overridden_methods() != CD->end_overridden_methods()); } + /// If it's possible to devirtualize a call to this method, return the called + /// function. Otherwise, return null. + + /// \param Base The object on which this virtual function is called. + /// \param IsAppleKext True if we are compiling for Apple kext. + CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, bool IsAppleKext); + + const CXXMethodDecl *getDevirtualizedMethod(const Expr *Base, + bool IsAppleKext) const { + return const_cast<CXXMethodDecl *>(this)->getDevirtualizedMethod( + Base, IsAppleKext); + } + /// \brief Determine whether this is a usual deallocation function /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded /// delete or delete[] operator with a particular signature. diff --git a/include/clang/AST/ExternalASTMerger.h b/include/clang/AST/ExternalASTMerger.h index 92d7b39c48d2..51d0c30ad23b 100644 --- a/include/clang/AST/ExternalASTMerger.h +++ b/include/clang/AST/ExternalASTMerger.h @@ -44,10 +44,6 @@ public: FindExternalLexicalDecls(const DeclContext *DC, llvm::function_ref<bool(Decl::Kind)> IsKindWeWant, SmallVectorImpl<Decl *> &Result) override; - - using ExternalASTSource::CompleteType; - - void CompleteType(TagDecl *Tag) override; }; } // end namespace clang diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 152e05bca740..917b240428e7 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1799,6 +1799,7 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); }) if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \ TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \ \ + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); \ if (!getDerived().shouldVisitTemplateInstantiations() && \ D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) \ /* Returning from here skips traversing the \ diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index cba4c99be959..c9b496df33f7 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -3821,6 +3821,14 @@ AST_MATCHER_P(CompoundStmt, statementCountIs, unsigned, N) { /// integerLiteral(equals(42)) /// matches 42 /// +/// Note that you cannot directly match a negative numeric literal because the +/// minus sign is not part of the literal: It is a unary operator whose operand +/// is the positive numeric literal. Instead, you must use a unaryOperator() +/// matcher to match the minus sign: +/// +/// unaryOperator(hasOperatorName("-"), +/// hasUnaryOperand(integerLiteral(equals(13)))) +/// /// Usable as: Matcher<CharacterLiteral>, Matcher<CXXBoolLiteralExpr>, /// Matcher<FloatingLiteral>, Matcher<IntegerLiteral> template <typename ValueT> diff --git a/include/clang/Analysis/AnalysisContext.h b/include/clang/Analysis/AnalysisContext.h index f6a47d646d1d..ec7549d4535c 100644 --- a/include/clang/Analysis/AnalysisContext.h +++ b/include/clang/Analysis/AnalysisContext.h @@ -426,6 +426,7 @@ public: bool addImplicitDtors = false, bool addInitializers = false, bool addTemporaryDtors = false, + bool addLifetime = false, bool synthesizeBodies = false, bool addStaticInitBranches = false, bool addCXXNewAllocator = true, diff --git a/include/clang/Analysis/CFG.h b/include/clang/Analysis/CFG.h index d23ed77ded13..97639bbfade2 100644 --- a/include/clang/Analysis/CFG.h +++ b/include/clang/Analysis/CFG.h @@ -58,6 +58,7 @@ public: Statement, Initializer, NewAllocator, + LifetimeEnds, // dtor kind AutomaticObjectDtor, DeleteDtor, @@ -167,6 +168,28 @@ private: } }; +/// Represents the point where the lifetime of an automatic object ends +class CFGLifetimeEnds : public CFGElement { +public: + explicit CFGLifetimeEnds(const VarDecl *var, const Stmt *stmt) + : CFGElement(LifetimeEnds, var, stmt) {} + + const VarDecl *getVarDecl() const { + return static_cast<VarDecl *>(Data1.getPointer()); + } + + const Stmt *getTriggerStmt() const { + return static_cast<Stmt *>(Data2.getPointer()); + } + +private: + friend class CFGElement; + CFGLifetimeEnds() {} + static bool isKind(const CFGElement &elem) { + return elem.getKind() == LifetimeEnds; + } +}; + /// CFGImplicitDtor - Represents C++ object destructor implicitly generated /// by compiler on various occasions. class CFGImplicitDtor : public CFGElement { @@ -701,6 +724,10 @@ public: Elements.push_back(CFGAutomaticObjDtor(VD, S), C); } + void appendLifetimeEnds(VarDecl *VD, Stmt *S, BumpVectorContext &C) { + Elements.push_back(CFGLifetimeEnds(VD, S), C); + } + void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) { Elements.push_back(CFGDeleteDtor(RD, DE), C); } @@ -717,6 +744,19 @@ public: *I = CFGAutomaticObjDtor(VD, S); return ++I; } + + // Scope leaving must be performed in reversed order. So insertion is in two + // steps. First we prepare space for some number of elements, then we insert + // the elements beginning at the last position in prepared space. + iterator beginLifetimeEndsInsert(iterator I, size_t Cnt, + BumpVectorContext &C) { + return iterator( + Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C)); + } + iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) { + *I = CFGLifetimeEnds(VD, S); + return ++I; + } }; /// \brief CFGCallback defines methods that should be called when a logical @@ -753,6 +793,7 @@ public: bool AddEHEdges; bool AddInitializers; bool AddImplicitDtors; + bool AddLifetime; bool AddTemporaryDtors; bool AddStaticInitBranches; bool AddCXXNewAllocator; @@ -774,8 +815,10 @@ public: BuildOptions() : forcedBlkExprs(nullptr), Observer(nullptr), - PruneTriviallyFalseEdges(true), AddEHEdges(false), + PruneTriviallyFalseEdges(true), + AddEHEdges(false), AddInitializers(false), AddImplicitDtors(false), + AddLifetime(false), AddTemporaryDtors(false), AddStaticInitBranches(false), AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {} }; diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h index 1ca3514e69b0..6339deef41bd 100644 --- a/include/clang/Analysis/CloneDetection.h +++ b/include/clang/Analysis/CloneDetection.h @@ -15,6 +15,8 @@ #ifndef LLVM_CLANG_AST_CLONEDETECTION_H #define LLVM_CLANG_AST_CLONEDETECTION_H +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -29,6 +31,192 @@ class VarDecl; class ASTContext; class CompoundStmt; +namespace clone_detection { + +/// Returns a string that represents all macro expansions that expanded into the +/// given SourceLocation. +/// +/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations +/// A and B are expanded from the same macros in the same order. +std::string getMacroStack(SourceLocation Loc, ASTContext &Context); + +/// Collects the data of a single Stmt. +/// +/// This class defines what a code clone is: If it collects for two statements +/// the same data, then those two statements are considered to be clones of each +/// other. +/// +/// All collected data is forwarded to the given data consumer of the type T. +/// The data consumer class needs to provide a member method with the signature: +/// update(StringRef Str) +template <typename T> +class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> { + + ASTContext &Context; + /// The data sink to which all data is forwarded. + T &DataConsumer; + +public: + /// Collects data of the given Stmt. + /// \param S The given statement. + /// \param Context The ASTContext of S. + /// \param DataConsumer The data sink to which all data is forwarded. + StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer) + : Context(Context), DataConsumer(DataConsumer) { + this->Visit(S); + } + + typedef unsigned DataPiece; + + // Below are utility methods for appending different data to the vector. + + void addData(DataPiece Integer) { + DataConsumer.update( + StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer))); + } + + void addData(llvm::StringRef Str) { DataConsumer.update(Str); } + + void addData(const QualType &QT) { addData(QT.getAsString()); } + +// The functions below collect the class specific data of each Stmt subclass. + +// Utility macro for defining a visit method for a given class. This method +// calls back to the ConstStmtVisitor to visit all parent classes. +#define DEF_ADD_DATA(CLASS, CODE) \ + void Visit##CLASS(const CLASS *S) { \ + CODE; \ + ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \ + } + + DEF_ADD_DATA(Stmt, { + addData(S->getStmtClass()); + // This ensures that macro generated code isn't identical to macro-generated + // code. + addData(getMacroStack(S->getLocStart(), Context)); + addData(getMacroStack(S->getLocEnd(), Context)); + }) + DEF_ADD_DATA(Expr, { addData(S->getType()); }) + + //--- Builtin functionality ----------------------------------------------// + DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); }) + DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); }) + DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); }) + DEF_ADD_DATA(TypeTraitExpr, { + addData(S->getTrait()); + for (unsigned i = 0; i < S->getNumArgs(); ++i) + addData(S->getArg(i)->getType()); + }) + + //--- Calls --------------------------------------------------------------// + DEF_ADD_DATA(CallExpr, { + // Function pointers don't have a callee and we just skip hashing it. + if (const FunctionDecl *D = S->getDirectCallee()) { + // If the function is a template specialization, we also need to handle + // the template arguments as they are not included in the qualified name. + if (auto Args = D->getTemplateSpecializationArgs()) { + std::string ArgString; + + // Print all template arguments into ArgString + llvm::raw_string_ostream OS(ArgString); + for (unsigned i = 0; i < Args->size(); ++i) { + Args->get(i).print(Context.getLangOpts(), OS); + // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. + OS << '\n'; + } + OS.flush(); + + addData(ArgString); + } + addData(D->getQualifiedNameAsString()); + } + }) + + //--- Exceptions ---------------------------------------------------------// + DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); }) + + //--- C++ OOP Stmts ------------------------------------------------------// + DEF_ADD_DATA(CXXDeleteExpr, { + addData(S->isArrayFormAsWritten()); + addData(S->isGlobalDelete()); + }) + + //--- Casts --------------------------------------------------------------// + DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); }) + + //--- Miscellaneous Exprs ------------------------------------------------// + DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); }) + DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); }) + + //--- Control flow -------------------------------------------------------// + DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); }) + DEF_ADD_DATA(IndirectGotoStmt, { + if (S->getConstantTarget()) + addData(S->getConstantTarget()->getName()); + }) + DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); }) + DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); }) + DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); }) + + //--- Objective-C --------------------------------------------------------// + DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); }) + DEF_ADD_DATA(ObjCPropertyRefExpr, { + addData(S->isSuperReceiver()); + addData(S->isImplicitProperty()); + }) + DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); }) + + //--- Miscellaneous Stmts ------------------------------------------------// + DEF_ADD_DATA(CXXFoldExpr, { + addData(S->isRightFold()); + addData(S->getOperator()); + }) + DEF_ADD_DATA(GenericSelectionExpr, { + for (unsigned i = 0; i < S->getNumAssocs(); ++i) { + addData(S->getAssocType(i)); + } + }) + DEF_ADD_DATA(LambdaExpr, { + for (const LambdaCapture &C : S->captures()) { + addData(C.isPackExpansion()); + addData(C.getCaptureKind()); + if (C.capturesVariable()) + addData(C.getCapturedVar()->getType()); + } + addData(S->isGenericLambda()); + addData(S->isMutable()); + }) + DEF_ADD_DATA(DeclStmt, { + auto numDecls = std::distance(S->decl_begin(), S->decl_end()); + addData(static_cast<DataPiece>(numDecls)); + for (const Decl *D : S->decls()) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + addData(VD->getType()); + } + } + }) + DEF_ADD_DATA(AsmStmt, { + addData(S->isSimple()); + addData(S->isVolatile()); + addData(S->generateAsmString(Context)); + for (unsigned i = 0; i < S->getNumInputs(); ++i) { + addData(S->getInputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumOutputs(); ++i) { + addData(S->getOutputConstraint(i)); + } + for (unsigned i = 0; i < S->getNumClobbers(); ++i) { + addData(S->getClobber(i)); + } + }) + DEF_ADD_DATA(AttributedStmt, { + for (const Attr *A : S->getAttrs()) { + addData(std::string(A->getSpelling())); + } + }) +}; +} // namespace clone_detection + /// Identifies a list of statements. /// /// Can either identify a single arbitrary Stmt object, a continuous sequence of diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index 42e1e5edaf9e..a28d63182749 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -178,6 +178,8 @@ def warn_drv_optimization_value : Warning<"optimization level '%0' is not suppor InGroup<InvalidCommandLineArgument>; def warn_ignored_gcc_optimization : Warning<"optimization flag '%0' is not supported">, InGroup<IgnoredOptimizationArgument>; +def warn_ignored_clang_option : Warning<"the flag '%0' has been deprecated and will be ignored">, + InGroup<UnusedCommandLineArgument>; def warn_drv_unsupported_opt_for_target : Warning< "optimization flag '%0' is not supported for target '%1'">, InGroup<IgnoredOptimizationArgument>; diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td index 8b4cb47e545d..57c24e9be73a 100644 --- a/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/include/clang/Basic/DiagnosticFrontendKinds.td @@ -179,6 +179,8 @@ def warn_incompatible_analyzer_plugin_api : Warning< def note_incompatible_analyzer_plugin_api : Note< "current API version is '%0', but plugin was compiled with version '%1'">; +def err_module_build_requires_fmodules : Error< + "module compilation requires '-fmodules'">; def err_module_interface_requires_modules_ts : Error< "module interface compilation requires '-fmodules-ts'">; def warn_module_config_mismatch : Warning< diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 136e48ab5e54..5a8750e4dab6 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1029,6 +1029,8 @@ def warn_auto_synthesizing_protocol_property :Warning< "auto property synthesis will not synthesize property %0" " declared in protocol %1">, InGroup<DiagGroup<"objc-protocol-property-synthesis">>; +def note_add_synthesize_directive : Note< + "add a '@synthesize' directive">; def warn_no_autosynthesis_shared_ivar_property : Warning < "auto property synthesis will not synthesize property " "%0 because it cannot share an ivar with another synthesized property">, @@ -2878,7 +2880,7 @@ def warn_partial_availability : Warning<"%0 is only available conditionally">, def warn_partial_availability_new : Warning<warn_partial_availability.Text>, InGroup<UnguardedAvailabilityNew>; def note_partial_availability_silence : Note< - "explicitly redeclare %0 to silence this warning">; + "annotate %select{%1|anonymous %1}0 with an availability attribute to silence">; def note_unguarded_available_silence : Note< "enclose %0 in %select{an @available|a __builtin_available}1 check to silence" " this warning">; @@ -3516,6 +3518,8 @@ def note_ovl_candidate_substitution_failure : Note< "candidate template ignored: substitution failure%0%1">; def note_ovl_candidate_disabled_by_enable_if : Note< "candidate template ignored: disabled by %0%1">; +def note_ovl_candidate_disabled_by_requirement : Note< + "candidate template ignored: requirement '%0' was not satisfied%1">; def note_ovl_candidate_has_pass_object_size_params: Note< "candidate address cannot be taken because parameter %0 has " "pass_object_size attribute">; @@ -4429,6 +4433,9 @@ def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_enable_if : Error< "no type named 'type' in %0; 'enable_if' cannot be used to disable " "this declaration">; +def err_typename_nested_not_found_requirement : Error< + "failed requirement '%0'; 'enable_if' cannot be used to disable this " + "declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; def note_typename_refers_here : Note< @@ -6353,15 +6360,13 @@ def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; -def warn_throw_in_noexcept_func - : Warning<"%0 has a non-throwing exception specification but can still " - "throw, resulting in unexpected program termination">, - InGroup<Exceptions>; -def note_throw_in_dtor - : Note<"destructor or deallocator has a (possibly implicit) non-throwing " - "excepton specification">; -def note_throw_in_function - : Note<"non-throwing function declare here">; +def warn_throw_in_noexcept_func : Warning< + "%0 has a non-throwing exception specification but can still throw">, + InGroup<Exceptions>; +def note_throw_in_dtor : Note< + "%select{destructor|deallocator}0 has a %select{non-throwing|implicit " + "non-throwing}1 exception specification">; +def note_throw_in_function : Note<"function declared non-throwing here">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< @@ -8455,8 +8460,6 @@ def err_opencl_builtin_to_addr_invalid_arg : Error< // OpenCL v2.0 s6.13.17 Enqueue kernel restrictions. def err_opencl_enqueue_kernel_incorrect_args : Error< "illegal call to enqueue_kernel, incorrect argument types">; -def err_opencl_enqueue_kernel_expected_type : Error< - "illegal call to enqueue_kernel, expected %0 argument type">; def err_opencl_enqueue_kernel_local_size_args : Error< "mismatch in number of block parameters and local size arguments passed">; def err_opencl_enqueue_kernel_invalid_local_size_type : Error< @@ -8466,6 +8469,9 @@ def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error< def err_opencl_enqueue_kernel_blocks_no_args : Error< "blocks with parameters are not accepted in this prototype of enqueue_kernel call">; +def err_opencl_builtin_expected_type : Error< + "illegal call to %0, expected %1 argument type">; + // OpenCL v2.2 s2.1.2.3 - Vector Component Access def ext_opencl_ext_vector_type_rgba_selector: ExtWarn< "vector component name '%0' is an OpenCL version 2.2 feature">, @@ -8854,6 +8860,10 @@ def warn_omp_nesting_simd : Warning< def err_omp_orphaned_device_directive : Error< "orphaned 'omp %0' directives are prohibited" "; perhaps you forget to enclose the directive into a %select{|||target |teams }1region?">; +def err_omp_reduction_non_addressable_expression : Error< + "expected addressable reduction item for the task-based directives">; +def err_omp_reduction_with_nogroup : Error< + "'reduction' clause cannot be used with 'nogroup' clause">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/include/clang/Basic/DiagnosticSerializationKinds.td b/include/clang/Basic/DiagnosticSerializationKinds.td index 3c64ebb9c7f4..0fc54848581c 100644 --- a/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/include/clang/Basic/DiagnosticSerializationKinds.td @@ -127,11 +127,11 @@ def err_module_odr_violation_mismatch_decl : Error< "%select{definition in module '%2'|defined here}1 found " "%select{end of class|public access specifier|private access specifier|" "protected access specifier|static assert|field|method|type alias|typedef|" - "data member}3">; + "data member|friend declaration}3">; def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found " "%select{end of class|public access specifier|private access specifier|" "protected access specifier|static assert|field|method|type alias|typedef|" - "data member}1">; + "data member|friend declaration}1">; def err_module_odr_violation_mismatch_decl_diff : Error< "%q0 has different definitions in different modules; first difference is " @@ -166,6 +166,9 @@ def err_module_odr_violation_mismatch_decl_diff : Error< "data member %4 with%select{out|}5 an initializer|" "data member %4 with an initializer|" "data member %4 %select{is constexpr|is not constexpr}5|" + "friend %select{class|function}4|" + "friend %4|" + "friend function %4|" "}3">; def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " @@ -199,18 +202,21 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found " "data member %2 with%select{out|}3 an initializer|" "data member %2 with a different initializer|" "data member %2 %select{is constexpr|is not constexpr}3|" + "friend %select{class|function}2|" + "friend %2|" + "friend function %2|" "}1">; def err_module_odr_violation_mismatch_decl_unknown : Error< "%q0 %select{with definition in module '%2'|defined here}1 has different " "definitions in different modules; first difference is this " "%select{||||static assert|field|method|type alias|typedef|data member|" - "unexpected decl}3">; + "friend declaration|unexpected decl}3">; def note_module_odr_violation_mismatch_decl_unknown : Note< "but in '%0' found " "%select{||||different static assert|different field|different method|" "different type alias|different typedef|different data member|" - "another unexpected decl}1">; + "different friend declaration|another unexpected decl}1">; def warn_duplicate_module_file_extension : Warning< "duplicate module file extension block name '%0'">, diff --git a/include/clang/Basic/Linkage.h b/include/clang/Basic/Linkage.h index e96fb568c009..6ec8763f2491 100644 --- a/include/clang/Basic/Linkage.h +++ b/include/clang/Basic/Linkage.h @@ -45,6 +45,17 @@ enum Linkage : unsigned char { /// translation units because of types defined in a inline function. VisibleNoLinkage, + /// \brief Internal linkage according to the Modules TS, but can be referred + /// to from other translation units indirectly through inline functions and + /// templates in the module interface. + ModuleInternalLinkage, + + /// \brief Module linkage, which indicates that the entity can be referred + /// to from other translation units within the same module, and indirectly + /// from arbitrary other translation units through inline functions and + /// templates in the module interface. + ModuleLinkage, + /// \brief External linkage, which indicates that the entity can /// be referred to from other translation units. ExternalLinkage @@ -74,15 +85,20 @@ inline bool isDiscardableGVALinkage(GVALinkage L) { } inline bool isExternallyVisible(Linkage L) { - return L == ExternalLinkage || L == VisibleNoLinkage; + return L >= VisibleNoLinkage; } inline Linkage getFormalLinkage(Linkage L) { - if (L == UniqueExternalLinkage) + switch (L) { + case UniqueExternalLinkage: return ExternalLinkage; - if (L == VisibleNoLinkage) + case VisibleNoLinkage: return NoLinkage; - return L; + case ModuleInternalLinkage: + return InternalLinkage; + default: + return L; + } } inline bool isExternalFormalLinkage(Linkage L) { diff --git a/include/clang/Basic/PartialDiagnostic.h b/include/clang/Basic/PartialDiagnostic.h index 53ce95cab1b0..b2f14afe5695 100644 --- a/include/clang/Basic/PartialDiagnostic.h +++ b/include/clang/Basic/PartialDiagnostic.h @@ -329,6 +329,15 @@ public: bool hasStorage() const { return DiagStorage != nullptr; } + /// Retrieve the string argument at the given index. + StringRef getStringArg(unsigned I) { + assert(DiagStorage && "No diagnostic storage?"); + assert(I < DiagStorage->NumDiagArgs && "Not enough diagnostic args"); + assert(DiagStorage->DiagArgumentsKind[I] + == DiagnosticsEngine::ak_std_string && "Not a string arg"); + return DiagStorage->DiagArgumentsStr[I]; + } + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, unsigned I) { PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index 9bdb288eef4f..5885532b91db 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -23,6 +23,7 @@ #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -954,6 +955,14 @@ public: return *AddrSpaceMap; } + /// \brief Return an AST address space which can be used opportunistically + /// for constant global memory. It must be possible to convert pointers into + /// this address space to LangAS::Default. If no such address space exists, + /// this may return None, and such optimizations will be disabled. + virtual llvm::Optional<unsigned> getConstantAddressSpace() const { + return LangAS::Default; + } + /// \brief Retrieve the name of the platform as it is used in the /// availability attribute. StringRef getPlatformName() const { return PlatformName; } diff --git a/include/clang/Basic/arm_neon.td b/include/clang/Basic/arm_neon.td index d5c16a91a34f..ad8d679a1664 100644 --- a/include/clang/Basic/arm_neon.td +++ b/include/clang/Basic/arm_neon.td @@ -227,7 +227,6 @@ def OP_UNAVAILABLE : Operation { // u: unsigned integer (int/float args) // f: float (int args) // F: double (int args) -// H: half (int args) // d: default // g: default, ignore 'Q' size modifier. // j: default, force 'Q' size modifier. @@ -346,7 +345,6 @@ def OP_MLSLHi : Op<(call "vmlsl", $p0, (call "vget_high", $p1), (call "vget_high", $p2))>; def OP_MLSLHi_N : Op<(call "vmlsl_n", $p0, (call "vget_high", $p1), $p2)>; def OP_MUL_N : Op<(op "*", $p0, (dup $p1))>; -def OP_MULX_N : Op<(call "vmulx", $p0, (dup $p1))>; def OP_MLA_N : Op<(op "+", $p0, (op "*", $p1, (dup $p2)))>; def OP_MLS_N : Op<(op "-", $p0, (op "*", $p1, (dup $p2)))>; def OP_FMLA_N : Op<(call "vfma", $p0, $p1, (dup $p2))>; @@ -1663,186 +1661,3 @@ def SCALAR_SQRDMLSH_LANEQ : SOpInst<"vqrdmlsh_laneq", "sssji", "SsSi", OP_SCALAR def SCALAR_VDUP_LANE : IInst<"vdup_lane", "sdi", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; def SCALAR_VDUP_LANEQ : IInst<"vdup_laneq", "sji", "ScSsSiSlSfSdSUcSUsSUiSUlSPcSPs">; } - -// ARMv8.2-A FP16 intrinsics. -let ArchGuard = "defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC) && defined(__aarch64__)" in { - - // ARMv8.2-A FP16 one-operand vector intrinsics. - - // Comparison - def CMEQH : SInst<"vceqz", "ud", "hQh">; - def CMGEH : SInst<"vcgez", "ud", "hQh">; - def CMGTH : SInst<"vcgtz", "ud", "hQh">; - def CMLEH : SInst<"vclez", "ud", "hQh">; - def CMLTH : SInst<"vcltz", "ud", "hQh">; - - // Vector conversion - def VCVT_F16 : SInst<"vcvt_f16", "Hd", "sUsQsQUs">; - def VCVT_S16 : SInst<"vcvt_s16", "xd", "hQh">; - def VCVT_U16 : SInst<"vcvt_u16", "ud", "hQh">; - def VCVTA_S16 : SInst<"vcvta_s16", "xd", "hQh">; - def VCVTA_U16 : SInst<"vcvta_u16", "ud", "hQh">; - def VCVTM_S16 : SInst<"vcvtm_s16", "xd", "hQh">; - def VCVTM_U16 : SInst<"vcvtm_u16", "ud", "hQh">; - def VCVTN_S16 : SInst<"vcvtn_s16", "xd", "hQh">; - def VCVTN_U16 : SInst<"vcvtn_u16", "ud", "hQh">; - def VCVTP_S16 : SInst<"vcvtp_s16", "xd", "hQh">; - def VCVTP_U16 : SInst<"vcvtp_u16", "ud", "hQh">; - - // Vector rounding - def FRINTZH : SInst<"vrnd", "dd", "hQh">; - def FRINTNH : SInst<"vrndn", "dd", "hQh">; - def FRINTAH : SInst<"vrnda", "dd", "hQh">; - def FRINTPH : SInst<"vrndp", "dd", "hQh">; - def FRINTMH : SInst<"vrndm", "dd", "hQh">; - def FRINTXH : SInst<"vrndx", "dd", "hQh">; - def FRINTIH : SInst<"vrndi", "dd", "hQh">; - - // Misc. - def VABSH : SInst<"vabs", "dd", "hQh">; - def VNEGH : SOpInst<"vneg", "dd", "hQh", OP_NEG>; - def VRECPEH : SInst<"vrecpe", "dd", "hQh">; - def FRSQRTEH : SInst<"vrsqrte", "dd", "hQh">; - def FSQRTH : SInst<"vsqrt", "dd", "hQh">; - - // ARMv8.2-A FP16 two-operands vector intrinsics. - - // Misc. - def VADDH : SOpInst<"vadd", "ddd", "hQh", OP_ADD>; - def VABDH : SInst<"vabd", "ddd", "hQh">; - def VSUBH : SOpInst<"vsub", "ddd", "hQh", OP_SUB>; - - // Comparison - let InstName = "vacge" in { - def VCAGEH : SInst<"vcage", "udd", "hQh">; - def VCALEH : SInst<"vcale", "udd", "hQh">; - } - let InstName = "vacgt" in { - def VCAGTH : SInst<"vcagt", "udd", "hQh">; - def VCALTH : SInst<"vcalt", "udd", "hQh">; - } - def VCEQH : SOpInst<"vceq", "udd", "hQh", OP_EQ>; - def VCGEH : SOpInst<"vcge", "udd", "hQh", OP_GE>; - def VCGTH : SOpInst<"vcgt", "udd", "hQh", OP_GT>; - let InstName = "vcge" in - def VCLEH : SOpInst<"vcle", "udd", "hQh", OP_LE>; - let InstName = "vcgt" in - def VCLTH : SOpInst<"vclt", "udd", "hQh", OP_LT>; - - // Vector conversion - let isVCVT_N = 1 in { - def VCVT_N_F16 : SInst<"vcvt_n_f16", "Hdi", "sUsQsQUs">; - def VCVT_N_S16 : SInst<"vcvt_n_s16", "xdi", "hQh">; - def VCVT_N_U16 : SInst<"vcvt_n_u16", "udi", "hQh">; - } - - // Max/Min - def VMAXH : SInst<"vmax", "ddd", "hQh">; - def VMINH : SInst<"vmin", "ddd", "hQh">; - def FMAXNMH : SInst<"vmaxnm", "ddd", "hQh">; - def FMINNMH : SInst<"vminnm", "ddd", "hQh">; - - // Multiplication/Division - def VMULH : SOpInst<"vmul", "ddd", "hQh", OP_MUL>; - def MULXH : SInst<"vmulx", "ddd", "hQh">; - def FDIVH : IOpInst<"vdiv", "ddd", "hQh", OP_DIV>; - - // Pairwise addition - def VPADDH : SInst<"vpadd", "ddd", "hQh">; - - // Pairwise Max/Min - def VPMAXH : SInst<"vpmax", "ddd", "hQh">; - def VPMINH : SInst<"vpmin", "ddd", "hQh">; - // Pairwise MaxNum/MinNum - def FMAXNMPH : SInst<"vpmaxnm", "ddd", "hQh">; - def FMINNMPH : SInst<"vpminnm", "ddd", "hQh">; - - // Reciprocal/Sqrt - def VRECPSH : SInst<"vrecps", "ddd", "hQh">; - def VRSQRTSH : SInst<"vrsqrts", "ddd", "hQh">; - - // ARMv8.2-A FP16 three-operands vector intrinsics. - - // Vector fused multiply-add operations - def VFMAH : SInst<"vfma", "dddd", "hQh">; - def VFMSH : SOpInst<"vfms", "dddd", "hQh", OP_FMLS>; - - // ARMv8.2-A FP16 lane vector intrinsics. - - // FMA lane - def VFMA_LANEH : IInst<"vfma_lane", "dddgi", "hQh">; - def VFMA_LANEQH : IInst<"vfma_laneq", "dddji", "hQh">; - - // FMA lane with scalar argument - def FMLA_NH : SOpInst<"vfma_n", "ddds", "hQh", OP_FMLA_N>; - // Scalar floating point fused multiply-add (scalar, by element) - def SCALAR_FMLA_LANEH : IInst<"vfma_lane", "sssdi", "Sh">; - def SCALAR_FMLA_LANEQH : IInst<"vfma_laneq", "sssji", "Sh">; - - // FMS lane - def VFMS_LANEH : IOpInst<"vfms_lane", "dddgi", "hQh", OP_FMS_LN>; - def VFMS_LANEQH : IOpInst<"vfms_laneq", "dddji", "hQh", OP_FMS_LNQ>; - // FMS lane with scalar argument - def FMLS_NH : SOpInst<"vfms_n", "ddds", "hQh", OP_FMLS_N>; - // Scalar floating foint fused multiply-subtract (scalar, by element) - def SCALAR_FMLS_LANEH : IOpInst<"vfms_lane", "sssdi", "Sh", OP_FMS_LN>; - def SCALAR_FMLS_LANEQH : IOpInst<"vfms_laneq", "sssji", "Sh", OP_FMS_LNQ>; - - // Mul lane - def VMUL_LANEH : IOpInst<"vmul_lane", "ddgi", "hQh", OP_MUL_LN>; - def VMUL_LANEQH : IOpInst<"vmul_laneq", "ddji", "hQh", OP_MUL_LN>; - def VMUL_NH : IOpInst<"vmul_n", "dds", "hQh", OP_MUL_N>; - // Scalar floating point multiply (scalar, by element) - def SCALAR_FMUL_LANEH : IOpInst<"vmul_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>; - def SCALAR_FMUL_LANEQH : IOpInst<"vmul_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>; - - // Mulx lane - def VMULX_LANEH : IOpInst<"vmulx_lane", "ddgi", "hQh", OP_MULX_LN>; - def VMULX_LANEQH : IOpInst<"vmulx_laneq", "ddji", "hQh", OP_MULX_LN>; - def VMULX_NH : IOpInst<"vmulx_n", "dds", "hQh", OP_MULX_N>; - // TODO: Scalar floating point multiply extended (scalar, by element) - // Below ones are commented out because they need vmulx_f16(float16_t, float16_t) - // which will be implemented later with fp16 scalar intrinsic (arm_fp16.h) - //def SCALAR_FMULX_LANEH : IOpInst<"vmulx_lane", "ssdi", "Sh", OP_SCALAR_MUL_LN>; - //def SCALAR_FMULX_LANEQH : IOpInst<"vmulx_laneq", "ssji", "Sh", OP_SCALAR_MUL_LN>; - - // ARMv8.2-A FP16 reduction vector intrinsics. - def VMAXVH : SInst<"vmaxv", "sd", "hQh">; - def VMINVH : SInst<"vminv", "sd", "hQh">; - def FMAXNMVH : SInst<"vmaxnmv", "sd", "hQh">; - def FMINNMVH : SInst<"vminnmv", "sd", "hQh">; - - // Data processing intrinsics - section 5 - - // Logical operations - let isHiddenLInst = 1 in - def VBSLH : SInst<"vbsl", "dudd", "hQh">; - - // Transposition operations - def VZIPH : WInst<"vzip", "2dd", "hQh">; - def VUZPH : WInst<"vuzp", "2dd", "hQh">; - def VTRNH : WInst<"vtrn", "2dd", "hQh">; - - // Set all lanes to same value. - /* Already implemented prior to ARMv8.2-A. - def VMOV_NH : WOpInst<"vmov_n", "ds", "hQh", OP_DUP>; - def VDUP_NH : WOpInst<"vdup_n", "ds", "hQh", OP_DUP>; - def VDUP_LANE1H : WOpInst<"vdup_lane", "dgi", "hQh", OP_DUP_LN>;*/ - - // Vector Extract - def VEXTH : WInst<"vext", "dddi", "hQh">; - - // Reverse vector elements - def VREV64H : WOpInst<"vrev64", "dd", "hQh", OP_REV64>; - - // Permutation - def VTRN1H : SOpInst<"vtrn1", "ddd", "hQh", OP_TRN1>; - def VZIP1H : SOpInst<"vzip1", "ddd", "hQh", OP_ZIP1>; - def VUZP1H : SOpInst<"vuzp1", "ddd", "hQh", OP_UZP1>; - def VTRN2H : SOpInst<"vtrn2", "ddd", "hQh", OP_TRN2>; - def VZIP2H : SOpInst<"vzip2", "ddd", "hQh", OP_ZIP2>; - def VUZP2H : SOpInst<"vuzp2", "ddd", "hQh", OP_UZP2>; - - def SCALAR_VDUP_LANEH : IInst<"vdup_lane", "sdi", "Sh">; - def SCALAR_VDUP_LANEQH : IInst<"vdup_laneq", "sji", "Sh">; -} diff --git a/include/clang/CodeGen/CodeGenABITypes.h b/include/clang/CodeGen/CodeGenABITypes.h index 8ba769dfc3af..615e55c8b69f 100644 --- a/include/clang/CodeGen/CodeGenABITypes.h +++ b/include/clang/CodeGen/CodeGenABITypes.h @@ -31,6 +31,8 @@ namespace llvm { class DataLayout; class Module; + class FunctionType; + class Type; } namespace clang { @@ -70,6 +72,12 @@ const CGFunctionInfo &arrangeFreeFunctionCall(CodeGenModule &CGM, FunctionType::ExtInfo info, RequiredArgs args); +// Returns null if the function type is incomplete and can't be lowered. +llvm::FunctionType *convertFreeFunctionType(CodeGenModule &CGM, + const FunctionDecl *FD); + +llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T); + } // end namespace CodeGen } // end namespace clang diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td index b65b984731f6..861dfbf1916e 100644 --- a/include/clang/Driver/Options.td +++ b/include/clang/Driver/Options.td @@ -194,6 +194,16 @@ def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">, def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">, Group<m_Group>, Flags<[Ignored]>; +// Group for clang options in the process of deprecation. +// Please include the version that deprecated the flag as comment to allow +// easier garbage collection. +def clang_ignored_legacy_options_Group : OptionGroup<"<clang legacy flags>">, + Group<f_Group>, Flags<[Ignored]>; + +// Retired with clang-5.0 +def : Flag<["-"], "fslp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>; +def : Flag<["-"], "fno-slp-vectorize-aggressive">, Group<clang_ignored_legacy_options_Group>; + // Group that ignores all gcc optimizations that won't be implemented def clang_ignored_gcc_optimization_f_Group : OptionGroup< "<clang_ignored_gcc_optimization_f_Group>">, Group<f_Group>, Flags<[Ignored]>; @@ -2017,6 +2027,10 @@ def mmsa : Flag<["-"], "mmsa">, Group<m_Group>, HelpText<"Enable MSA ASE (MIPS only)">; def mno_msa : Flag<["-"], "mno-msa">, Group<m_Group>, HelpText<"Disable MSA ASE (MIPS only)">; +def mmt : Flag<["-"], "mmt">, Group<m_Group>, + HelpText<"Enable MT ASE (MIPS only)">; +def mno_mt : Flag<["-"], "mno-mt">, Group<m_Group>, + HelpText<"Disable MT ASE (MIPS only)">; def mfp64 : Flag<["-"], "mfp64">, Group<m_Group>, HelpText<"Use 64-bit floating point registers (MIPS only)">; def mfp32 : Flag<["-"], "mfp32">, Group<m_Group>, diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 105d0f338ac6..eb42f1260d92 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -411,7 +411,8 @@ public: /// \brief Add options that need to be passed to cc1 for this target. virtual void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const; /// \brief Add warning options that need to be passed to cc1 for this target. virtual void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const; diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index ee24c55fef61..99d54e55e828 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -1120,7 +1120,10 @@ struct FormatStyle { /// (https://developers.google.com/protocol-buffers/). LK_Proto, /// Should be used for TableGen code. - LK_TableGen + LK_TableGen, + /// Should be used for Protocol Buffer messages in text format + /// (https://developers.google.com/protocol-buffers/). + LK_TextProto }; bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; } @@ -1750,6 +1753,8 @@ inline StringRef getLanguageName(FormatStyle::LanguageKind Language) { return "JavaScript"; case FormatStyle::LK_Proto: return "Proto"; + case FormatStyle::LK_TextProto: + return "TextProto"; default: return "Unknown"; } diff --git a/include/clang/Frontend/FrontendActions.h b/include/clang/Frontend/FrontendActions.h index 84db293c46f3..c45aeaa208c8 100644 --- a/include/clang/Frontend/FrontendActions.h +++ b/include/clang/Frontend/FrontendActions.h @@ -111,6 +111,8 @@ protected: class GenerateModuleFromModuleMapAction : public GenerateModuleAction { private: + bool BeginSourceFileAction(CompilerInstance &CI) override; + std::unique_ptr<raw_pwrite_stream> CreateOutputFile(CompilerInstance &CI, StringRef InFile) override; }; diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 712e1ab9fbf5..62090d6496ed 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -1048,6 +1048,10 @@ public: /// which implicitly adds the builtin defines etc. void EnterMainSourceFile(); + /// \brief After parser warm-up, initialize the conditional stack from + /// the preamble. + void replayPreambleConditionalStack(); + /// \brief Inform the preprocessor callbacks that processing is complete. void EndSourceFile(); @@ -1733,11 +1737,6 @@ public: /// \brief Return true if we're in the top-level file, not in a \#include. bool isInPrimaryFile() const; - /// \brief Return true if we're in the main file (specifically, if we are 0 - /// (zero) levels deep \#include. This is used by the lexer to determine if - /// it needs to generate errors about unterminated \#if directives. - bool isInMainFile() const; - /// \brief Handle cases where the \#include name is expanded /// from a macro as multiple tokens, which need to be glued together. /// diff --git a/include/clang/Sema/DelayedDiagnostic.h b/include/clang/Sema/DelayedDiagnostic.h index b73ec0868f52..d65dbf0cd34e 100644 --- a/include/clang/Sema/DelayedDiagnostic.h +++ b/include/clang/Sema/DelayedDiagnostic.h @@ -124,7 +124,8 @@ public: static DelayedDiagnostic makeAvailability(AvailabilityResult AR, SourceLocation Loc, - const NamedDecl *D, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, @@ -164,9 +165,13 @@ public: return *reinterpret_cast<const AccessedEntity*>(AccessData); } - const NamedDecl *getAvailabilityDecl() const { + const NamedDecl *getAvailabilityReferringDecl() const { assert(Kind == Availability && "Not an availability diagnostic."); - return AvailabilityData.Decl; + return AvailabilityData.ReferringDecl; + } + + const NamedDecl *getAvailabilityOffendingDecl() const { + return AvailabilityData.OffendingDecl; } StringRef getAvailabilityMessage() const { @@ -213,7 +218,8 @@ public: private: struct AD { - const NamedDecl *Decl; + const NamedDecl *ReferringDecl; + const NamedDecl *OffendingDecl; const ObjCInterfaceDecl *UnknownObjCClass; const ObjCPropertyDecl *ObjCProperty; const char *Message; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 95134d52f873..95629a2591cf 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1266,6 +1266,7 @@ public: void emitAndClearUnusedLocalTypedefWarnings(); + void ActOnStartOfTranslationUnit(); void ActOnEndOfTranslationUnit(); void CheckDelegatingCtorCycles(); @@ -1541,6 +1542,7 @@ public: llvm::SmallVectorImpl<Module *> *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); + bool hasMergedDefinitionInCurrentModule(NamedDecl *Def); /// Determine if \p D and \p Suggested have a structurally compatible /// layout as described in C11 6.2.7/1. @@ -3358,9 +3360,10 @@ public: /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. - void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl); - void DefaultSynthesizeProperties(Scope *S, Decl *D); + void DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, + ObjCInterfaceDecl *IDecl, + SourceLocation AtEnd); + void DefaultSynthesizeProperties(Scope *S, Decl *D, SourceLocation AtEnd); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor @@ -3878,7 +3881,9 @@ public: void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, + void EmitAvailabilityWarning(AvailabilityResult AR, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, @@ -3895,8 +3900,9 @@ public: bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass=nullptr, - bool ObjCPropertyAccess=false); + const ObjCInterfaceDecl *UnknownObjCClass = nullptr, + bool ObjCPropertyAccess = false, + bool AvoidPartialAvailabilityChecks = false); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); @@ -3938,7 +3944,7 @@ public: void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); - void MarkDeclRefReferenced(DeclRefExpr *E); + void MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base = nullptr); void MarkMemberReferenced(MemberExpr *E); void UpdateMarkingForLValueToRValue(Expr *E); @@ -10410,16 +10416,14 @@ public: return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } - /// \brief The diagnostic we should emit for \c D, or \c AR_Available. - /// - /// \param D The declaration to check. Note that this may be altered to point - /// to another declaration that \c D gets it's availability from. i.e., we - /// walk the list of typedefs to find an availability attribute. + /// The diagnostic we should emit for \c D, and the declaration that + /// originated it, or \c AR_Available. /// + /// \param D The declaration to check. /// \param Message If non-null, this will be populated with the message from /// the availability attribute that is selected. - AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, - std::string *Message); + std::pair<AvailabilityResult, const NamedDecl *> + ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, std::string *Message); const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h index d92cbab4fbcf..cd9ed6abfaf9 100644 --- a/include/clang/Sema/TemplateDeduction.h +++ b/include/clang/Sema/TemplateDeduction.h @@ -88,6 +88,12 @@ public: HasSFINAEDiagnostic = false; } + /// Peek at the SFINAE diagnostic. + const PartialDiagnosticAt &peekSFINAEDiagnostic() const { + assert(HasSFINAEDiagnostic); + return SuppressedDiagnostics.front(); + } + /// \brief Provide a new template argument list that contains the /// results of template argument deduction. void reset(TemplateArgumentList *NewDeduced) { diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 4fb50deb0f6b..5dd6bdf38496 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -205,9 +205,15 @@ private: /// Controls which C++ member functions will be considered for inlining. CXXInlineableMemberKind CXXMemberInliningMode; + /// \sa includeImplicitDtorsInCFG + Optional<bool> IncludeImplicitDtorsInCFG; + /// \sa includeTemporaryDtorsInCFG Optional<bool> IncludeTemporaryDtorsInCFG; - + + /// \sa IncludeLifetimeInCFG + Optional<bool> IncludeLifetimeInCFG; + /// \sa mayInlineCXXStandardLibrary Optional<bool> InlineCXXStandardLibrary; @@ -395,6 +401,20 @@ public: /// accepts the values "true" and "false". bool includeTemporaryDtorsInCFG(); + /// Returns whether or not implicit destructors for C++ objects should + /// be included in the CFG. + /// + /// This is controlled by the 'cfg-implicit-dtors' config option, which + /// accepts the values "true" and "false". + bool includeImplicitDtorsInCFG(); + + /// Returns whether or not end-of-lifetime information should be included in + /// the CFG. + /// + /// This is controlled by the 'cfg-lifetime' config option, which accepts + /// the values "true" and "false". + bool includeLifetimeInCFG(); + /// Returns whether or not C++ standard library functions may be considered /// for inlining. /// diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 52ed260346bf..88cb08a4b647 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -286,7 +286,7 @@ public: void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng); - /// \brief Run checkers on begining of function. + /// \brief Run checkers on beginning of function. void runCheckersForBeginFunction(ExplodedNodeSet &Dst, const BlockEdge &L, ExplodedNode *Pred, diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h index b8ec2aa6ae8d..4aa87443e4c2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -124,7 +124,7 @@ public: /// Returns the type of the APSInt used to store values of the given QualType. APSIntType getAPSIntType(QualType T) const { assert(T->isIntegralOrEnumerationType() || Loc::isLocType(T)); - return APSIntType(Ctx.getTypeSize(T), + return APSIntType(Ctx.getIntWidth(T), !T->isSignedIntegerOrEnumerationType()); } diff --git a/include/clang/Tooling/ArgumentsAdjusters.h b/include/clang/Tooling/ArgumentsAdjusters.h index 1fd7be688761..4eb02251a775 100644 --- a/include/clang/Tooling/ArgumentsAdjusters.h +++ b/include/clang/Tooling/ArgumentsAdjusters.h @@ -44,6 +44,10 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster(); /// arguments. ArgumentsAdjuster getClangStripOutputAdjuster(); +/// \brief Gets an argument adjuster which removes dependency-file +/// related command line arguments. +ArgumentsAdjuster getClangStripDependencyFileAdjuster(); + enum class ArgumentInsertPosition { BEGIN, END }; /// \brief Gets an argument adjuster which inserts \p Extra arguments in the diff --git a/include/clang/Tooling/Core/Diagnostic.h b/include/clang/Tooling/Core/Diagnostic.h index d657f16df183..b4920d4fe456 100644 --- a/include/clang/Tooling/Core/Diagnostic.h +++ b/include/clang/Tooling/Core/Diagnostic.h @@ -58,9 +58,9 @@ struct Diagnostic { Diagnostic(llvm::StringRef DiagnosticName, Level DiagLevel, StringRef BuildDirectory); - Diagnostic(llvm::StringRef DiagnosticName, DiagnosticMessage &Message, - llvm::StringMap<Replacements> &Fix, - SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, + Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message, + const llvm::StringMap<Replacements> &Fix, + const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, llvm::StringRef BuildDirectory); /// \brief Name identifying the Diagnostic. diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h index 1c974f998852..6f9bc9e1a150 100644 --- a/include/clang/Tooling/Tooling.h +++ b/include/clang/Tooling/Tooling.h @@ -202,12 +202,15 @@ buildASTFromCode(const Twine &Code, const Twine &FileName = "input.cc", /// \param PCHContainerOps The PCHContainerOperations for loading and creating /// clang modules. /// +/// \param Adjuster A function to filter the command line arguments as specified. +/// /// \return The resulting AST or null if an error occurred. std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( const Twine &Code, const std::vector<std::string> &Args, const Twine &FileName = "input.cc", const Twine &ToolName = "clang-tool", std::shared_ptr<PCHContainerOperations> PCHContainerOps = - std::make_shared<PCHContainerOperations>()); + std::make_shared<PCHContainerOperations>(), + ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster()); /// \brief Utility to run a FrontendAction in a single clang invocation. class ToolInvocation { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a2ff176df11f..fd9723298fca 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -8523,7 +8523,10 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, RequiresICE = false; // Read the prefixed modifiers first. - bool Done = false, IsSpecialLong = false; + bool Done = false; + #ifndef NDEBUG + bool IsSpecialLong = false; + #endif while (!Done) { switch (*Str++) { default: Done = true; --Str; break; @@ -8549,7 +8552,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); + #ifndef NDEBUG IsSpecialLong = true; + #endif if (Context.getTargetInfo().getLongWidth() == 32) ++HowLong; break; @@ -8558,7 +8563,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // This modifier represents int64 type. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!"); + #ifndef NDEBUG IsSpecialLong = true; + #endif switch (Context.getTargetInfo().getInt64Type()) { default: llvm_unreachable("Unexpected integer type"); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 267c6992af89..573a98efe980 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -573,6 +573,44 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { return false; } +static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { + switch (D->getModuleOwnershipKind()) { + case Decl::ModuleOwnershipKind::Unowned: + case Decl::ModuleOwnershipKind::ModulePrivate: + return false; + case Decl::ModuleOwnershipKind::Visible: + case Decl::ModuleOwnershipKind::VisibleWhenImported: + if (auto *M = D->getOwningModule()) + return M->Kind == Module::ModuleInterfaceUnit; + } + llvm_unreachable("unexpected module ownership kind"); +} + +static LinkageInfo getInternalLinkageFor(const NamedDecl *D) { + // Internal linkage declarations within a module interface unit are modeled + // as "module-internal linkage", which means that they have internal linkage + // formally but can be indirectly accessed from outside the module via inline + // functions and templates defined within the module. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + + return LinkageInfo::internal(); +} + +static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { + // C++ Modules TS [basic.link]/6.8: + // - A name declared at namespace scope that does not have internal linkage + // by the previous rules and that is introduced by a non-exported + // declaration has module linkage. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + if (!isExportedFromModuleIntefaceUnit(D)) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -588,16 +626,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (const auto *Var = dyn_cast<VarDecl>(D)) { // Explicitly declared static. if (Var->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); // - a non-inline, non-volatile object or reference that is explicitly // declared const or constexpr and neither explicitly declared extern // nor previously declared to have external linkage; or (there is no // equivalent in C99) + // The C++ modules TS adds "non-exported" to this list. if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && - !Var->isInline()) { + !Var->isInline() && + !isExportedFromModuleIntefaceUnit(Var)) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); @@ -605,7 +645,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && !isSingleLineLanguageLinkage(*Var)) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; @@ -615,7 +655,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return PrevVar->getLinkageAndVisibility(); // Explicitly declared static. if (PrevVar->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } } else if (const FunctionDecl *Function = D->getAsFunction()) { // C++ [temp]p4: @@ -624,7 +664,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo(InternalLinkage, DefaultVisibility, false); + return getInternalLinkageFor(Function); } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); @@ -637,7 +677,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); // FIXME: In C++11 onwards, anonymous namespaces should give decls - // within them internal linkage, not unique external linkage. + // within them (including those inside extern "C" contexts) internal + // linkage, not unique external linkage: + // + // C++11 [basic.link]p4: + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); @@ -718,7 +763,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); - if (TypeLV.getLinkage() != ExternalLinkage) + if (TypeLV.getLinkage() != ExternalLinkage && + TypeLV.getLinkage() != ModuleLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); @@ -816,7 +862,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // - a namespace (7.3), unless it is declared within an unnamed // namespace. - } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) { + // + // We handled names in anonymous namespaces above. + } else if (isa<NamespaceDecl>(D)) { return LV; // By extension, we assign external linkage to Objective-C @@ -1125,6 +1173,8 @@ static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, if (const auto *ND = dyn_cast<NamedDecl>(DC)) return getLVForDecl(ND, computation); + // FIXME: We have a closure at TU scope with no context declaration. This + // should probably have no linkage. return LinkageInfo::external(); } @@ -1137,7 +1187,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Function); LinkageInfo LV; if (!hasExplicitVisibilityAlready(computation)) { @@ -1226,7 +1276,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); // Objective-C: treat all Objective-C declarations as having external // linkage. @@ -1259,8 +1309,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::TypeAlias: // A typedef declaration has linkage if it gives a type a name for // linkage purposes. - if (!D->getASTContext().getLangOpts().CPlusPlus || - !cast<TypedefNameDecl>(D) + if (!cast<TypedefNameDecl>(D) ->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) return LinkageInfo::none(); break; @@ -1276,14 +1325,14 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: - return LinkageInfo::external(); + return getExternalLinkageFor(D); case Decl::CXXRecord: { const auto *Record = cast<CXXRecordDecl>(D); if (Record->isLambda()) { if (!Record->getLambdaManglingNumber()) { // This lambda has no mangling number, so it's internal. - return LinkageInfo::internal(); + return getInternalLinkageFor(D); } // This lambda has its linkage/visibility determined: @@ -1299,7 +1348,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, const CXXRecordDecl *OuterMostLambda = getOutermostEnclosingLambda(Record); if (!OuterMostLambda->getLambdaManglingNumber()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); return getLVForClosure( OuterMostLambda->getDeclContext()->getRedeclContext(), @@ -1350,7 +1399,7 @@ public: LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); if (computation == LVForLinkageOnly && D->hasCachedLinkage()) return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a0594a020362..cd2c83a02f59 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -283,8 +283,10 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { setLocalOwningModule(cast<Decl>(DC)->getOwningModule()); } - assert((!hasOwningModule() || getOwningModule()) && - "hidden declaration has no owning module"); + assert( + (getModuleOwnershipKind() != ModuleOwnershipKind::VisibleWhenImported || + getOwningModule()) && + "hidden declaration has no owning module"); } void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 07d128ba555b..5cab48882251 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1605,6 +1605,84 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SC_None, false, false, SourceLocation()); } +CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, + bool IsAppleKext) { + assert(isVirtual() && "this method is expected to be virtual"); + + // When building with -fapple-kext, all calls must go through the vtable since + // the kernel linker can do runtime patching of vtables. + if (IsAppleKext) + return nullptr; + + // If the member function is marked 'final', we know that it can't be + // overridden and can therefore devirtualize it unless it's pure virtual. + if (hasAttr<FinalAttr>()) + return isPure() ? nullptr : this; + + // If Base is unknown, we cannot devirtualize. + if (!Base) + return nullptr; + + // If the base expression (after skipping derived-to-base conversions) is a + // class prvalue, then we can devirtualize. + Base = Base->getBestDynamicClassTypeExpr(); + if (Base->isRValue() && Base->getType()->isRecordType()) + return this; + + // If we don't even know what we would call, we can't devirtualize. + const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); + if (!BestDynamicDecl) + return nullptr; + + // There may be a method corresponding to MD in a derived class. + CXXMethodDecl *DevirtualizedMethod = + getCorrespondingMethodInClass(BestDynamicDecl); + + // If that method is pure virtual, we can't devirtualize. If this code is + // reached, the result would be UB, not a direct call to the derived class + // function, and we can't assume the derived class function is defined. + if (DevirtualizedMethod->isPure()) + return nullptr; + + // If that method is marked final, we can devirtualize it. + if (DevirtualizedMethod->hasAttr<FinalAttr>()) + return DevirtualizedMethod; + + // Similarly, if the class itself is marked 'final' it can't be overridden + // and we can therefore devirtualize the member function call. + if (BestDynamicDecl->hasAttr<FinalAttr>()) + return DevirtualizedMethod; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VD->getType()->isRecordType()) + // This is a record decl. We know the type and can devirtualize it. + return DevirtualizedMethod; + + return nullptr; + } + + // We can devirtualize calls on an object accessed by a class member access + // expression, since by C++11 [basic.life]p6 we know that it can't refer to + // a derived class object constructed in the same location. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) + if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) + return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr; + + // Likewise for calls on an object accessed by a (non-reference) pointer to + // member access. + if (auto *BO = dyn_cast<BinaryOperator>(Base)) { + if (BO->isPtrMemOp()) { + auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>(); + if (MPT->getPointeeType()->isRecordType()) + return DevirtualizedMethod; + } + } + + // We can't devirtualize the call. + return nullptr; +} + bool CXXMethodDecl::isUsualDeallocationFunction() const { if (getOverloadedOperator() != OO_Delete && getOverloadedOperator() != OO_Array_Delete) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e836135cf2f9..0c0c861e5d56 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1665,6 +1665,19 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return true; } +/// Member pointers are constant expressions unless they point to a +/// non-virtual dllimport member function. +static bool CheckMemberPointerConstantExpression(EvalInfo &Info, + SourceLocation Loc, + QualType Type, + const APValue &Value) { + const ValueDecl *Member = Value.getMemberPointerDecl(); + const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); + if (!FD) + return true; + return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); +} + /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E, @@ -1757,6 +1770,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); } + if (Value.isMemberPointer()) + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + // Everything else is fine. return true; } @@ -9508,7 +9524,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BO_Mul: if (Result.isComplexFloat()) { // This is an implementation of complex multiplication according to the - // constraints laid out in C11 Annex G. The implemantion uses the + // constraints laid out in C11 Annex G. The implemention uses the // following naming scheme: // (a + ib) * (c + id) ComplexValue LHS = Result; @@ -9589,7 +9605,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BO_Div: if (Result.isComplexFloat()) { // This is an implementation of complex division according to the - // constraints laid out in C11 Annex G. The implemantion uses the + // constraints laid out in C11 Annex G. The implemention uses the // following naming scheme: // (a + ib) / (c + id) ComplexValue LHS = Result; diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp index b746edaf6439..4f4a99794c5b 100644 --- a/lib/AST/ExternalASTMerger.cpp +++ b/lib/AST/ExternalASTMerger.cpp @@ -180,8 +180,3 @@ void ExternalASTMerger::FindExternalLexicalDecls( }); } -void ExternalASTMerger::CompleteType(TagDecl *Tag) { - SmallVector<Decl *, 0> Result; - FindExternalLexicalDecls(Tag, [](Decl::Kind) { return true; }, Result); - Tag->setHasExternalLexicalStorage(false); -} diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 3f66e58eb868..66b9940b8b08 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -228,6 +228,13 @@ public: Hash.AddQualType(T); } + void AddDecl(const Decl *D) { + Hash.AddBoolean(D); + if (D) { + Hash.AddDecl(D); + } + } + void Visit(const Decl *D) { ID.AddInteger(D->getKind()); Inherited::Visit(D); @@ -321,6 +328,16 @@ public: void VisitTypeAliasDecl(const TypeAliasDecl *D) { Inherited::VisitTypeAliasDecl(D); } + + void VisitFriendDecl(const FriendDecl *D) { + TypeSourceInfo *TSI = D->getFriendType(); + Hash.AddBoolean(TSI); + if (TSI) { + AddQualType(TSI->getType()); + } else { + AddDecl(D->getFriendDecl()); + } + } }; // Only allow a small portion of Decl's to be processed. Remove this once @@ -335,6 +352,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { case Decl::AccessSpec: case Decl::CXXMethod: case Decl::Field: + case Decl::Friend: case Decl::StaticAssert: case Decl::TypeAlias: case Decl::Typedef: diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 7c0f5543da04..ec15f34fb231 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -67,6 +67,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, bool addTemporaryDtors, + bool addLifetime, bool synthesizeBodies, bool addStaticInitBranch, bool addCXXNewAllocator, @@ -77,6 +78,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; + cfgBuildOptions.AddLifetime = addLifetime; cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 2a2b3d73b5ca..6a77455edeef 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -233,6 +233,7 @@ public: } int distance(const_iterator L); + const_iterator shared_parent(const_iterator L); }; friend class const_iterator; @@ -275,6 +276,30 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { return D; } +/// Calculates the closest parent of this iterator +/// that is in a scope reachable through the parents of L. +/// I.e. when using 'goto' from this to L, the lifetime of all variables +/// between this and shared_parent(L) end. +LocalScope::const_iterator +LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) { + llvm::SmallPtrSet<const LocalScope *, 4> ScopesOfL; + while (true) { + ScopesOfL.insert(L.Scope); + if (L == const_iterator()) + break; + L = L.Scope->Prev; + } + + const_iterator F = *this; + while (true) { + if (ScopesOfL.count(F.Scope)) + return F; + assert(F != const_iterator() && + "L iterator is not reachable from F iterator."); + F = F.Scope->Prev; + } +} + /// Structure for specifying position in CFG during its build process. It /// consists of CFGBlock that specifies position in CFG and /// LocalScope::const_iterator that specifies position in LocalScope graph. @@ -579,6 +604,10 @@ private: CFGBlock *addInitializer(CXXCtorInitializer *I); void addAutomaticObjDtors(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S); + void addLifetimeEnds(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S); + void addAutomaticObjHandling(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S); void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); // Local scopes creation. @@ -619,6 +648,10 @@ private: B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext()); } + void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) { + B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext()); + } + void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) { B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext()); } @@ -626,6 +659,10 @@ private: void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E); + void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk, + LocalScope::const_iterator B, + LocalScope::const_iterator E); + void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) { B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable), cfg->getBumpVectorContext()); @@ -957,7 +994,8 @@ private: return TryResult(); } - + + bool hasTrivialDestructor(VarDecl *VD); }; inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, @@ -1031,6 +1069,9 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { assert(Succ == &cfg->getExit()); Block = nullptr; // the EXIT block is empty. Create all other blocks lazily. + assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && + "AddImplicitDtors and AddLifetime cannot be used at the same time"); + if (BuildOpts.AddImplicitDtors) if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D)) addImplicitDtorsForDestructor(DD); @@ -1067,6 +1108,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { if (LI == LabelMap.end()) continue; JumpTarget JT = LI->second; + prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition, + JT.scopePosition); prependAutomaticObjDtorsWithTerminator(B, I->scopePosition, JT.scopePosition); addSuccessor(B, JT.block); @@ -1209,7 +1252,61 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context, return Init->getType(); } - + +void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, + LocalScope::const_iterator E, + Stmt *S) { + if (BuildOpts.AddImplicitDtors) + addAutomaticObjDtors(B, E, S); + if (BuildOpts.AddLifetime) + addLifetimeEnds(B, E, S); +} + +/// Add to current block automatic objects that leave the scope. +void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S) { + if (!BuildOpts.AddLifetime) + return; + + if (B == E) + return; + + // To go from B to E, one first goes up the scopes from B to P + // then sideways in one scope from P to P' and then down + // the scopes from P' to E. + // The lifetime of all objects between B and P end. + LocalScope::const_iterator P = B.shared_parent(E); + int dist = B.distance(P); + if (dist <= 0) + return; + + // We need to perform the scope leaving in reverse order + SmallVector<VarDecl *, 10> DeclsTrivial; + SmallVector<VarDecl *, 10> DeclsNonTrivial; + DeclsTrivial.reserve(dist); + DeclsNonTrivial.reserve(dist); + + for (LocalScope::const_iterator I = B; I != P; ++I) + if (hasTrivialDestructor(*I)) + DeclsTrivial.push_back(*I); + else + DeclsNonTrivial.push_back(*I); + + autoCreateBlock(); + // object with trivial destructor end their lifetime last (when storage + // duration ends) + for (SmallVectorImpl<VarDecl *>::reverse_iterator I = DeclsTrivial.rbegin(), + E = DeclsTrivial.rend(); + I != E; ++I) + appendLifetimeEnds(Block, *I, S); + + for (SmallVectorImpl<VarDecl *>::reverse_iterator + I = DeclsNonTrivial.rbegin(), + E = DeclsNonTrivial.rend(); + I != E; ++I) + appendLifetimeEnds(Block, *I, S); +} + /// addAutomaticObjDtors - Add to current block automatic objects destructors /// for objects in range of local scope positions. Use S as trigger statement /// for destructors. @@ -1309,7 +1406,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement /// that should create implicit scope (e.g. if/else substatements). void CFGBuilder::addLocalScopeForStmt(Stmt *S) { - if (!BuildOpts.AddImplicitDtors) + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) return; LocalScope *Scope = nullptr; @@ -1334,7 +1431,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) { /// reuse Scope if not NULL. LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope) { - if (!BuildOpts.AddImplicitDtors) + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) return Scope; for (auto *DI : DS->decls()) @@ -1343,23 +1440,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, return Scope; } -/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will -/// create add scope for automatic objects and temporary objects bound to -/// const reference. Will reuse Scope if not NULL. -LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, - LocalScope* Scope) { - if (!BuildOpts.AddImplicitDtors) - return Scope; - - // Check if variable is local. - switch (VD->getStorageClass()) { - case SC_None: - case SC_Auto: - case SC_Register: - break; - default: return Scope; - } - +bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) { // Check for const references bound to temporary. Set type to pointee. QualType QT = VD->getType(); if (QT.getTypePtr()->isReferenceType()) { @@ -1370,44 +1451,74 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, // temporaries, and a single declaration can extend multiple temporaries. // We should look at the storage duration on each nested // MaterializeTemporaryExpr instead. + const Expr *Init = VD->getInit(); if (!Init) - return Scope; + return true; // Lifetime-extending a temporary. bool FoundMTE = false; QT = getReferenceInitTemporaryType(*Context, Init, &FoundMTE); if (!FoundMTE) - return Scope; + return true; } // Check for constant size array. Set type to array element type. while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { if (AT->getSize() == 0) - return Scope; + return true; QT = AT->getElementType(); } // Check if type is a C++ class with non-trivial destructor. if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) - if (CD->hasDefinition() && !CD->hasTrivialDestructor()) { + return !CD->hasDefinition() || CD->hasTrivialDestructor(); + return true; +} + +/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will +/// create add scope for automatic objects and temporary objects bound to +/// const reference. Will reuse Scope if not NULL. +LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, + LocalScope* Scope) { + assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && + "AddImplicitDtors and AddLifetime cannot be used at the same time"); + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) + return Scope; + + // Check if variable is local. + switch (VD->getStorageClass()) { + case SC_None: + case SC_Auto: + case SC_Register: + break; + default: return Scope; + } + + if (BuildOpts.AddImplicitDtors) { + if (!hasTrivialDestructor(VD)) { // Add the variable to scope Scope = createOrReuseLocalScope(Scope); Scope->addVar(VD); ScopePos = Scope->begin(); } + return Scope; + } + + assert(BuildOpts.AddLifetime); + // Add the variable to scope + Scope = createOrReuseLocalScope(Scope); + Scope->addVar(VD); + ScopePos = Scope->begin(); return Scope; } /// addLocalScopeAndDtors - For given statement add local scope for it and /// add destructors that will cleanup the scope. Will reuse Scope if not NULL. void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { - if (!BuildOpts.AddImplicitDtors) - return; - LocalScope::const_iterator scopeBeginPos = ScopePos; addLocalScopeForStmt(S); - addAutomaticObjDtors(ScopePos, scopeBeginPos, S); + addAutomaticObjHandling(ScopePos, scopeBeginPos, S); } /// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for @@ -1419,6 +1530,8 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { /// no-return destructors properly. void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { + if (!BuildOpts.AddImplicitDtors) + return; BumpVectorContext &C = cfg->getBumpVectorContext(); CFGBlock::iterator InsertPos = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C); @@ -1427,6 +1540,21 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, Blk->getTerminator()); } +/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for +/// variables with automatic storage duration to CFGBlock's elements vector. +/// Elements will be prepended to physical beginning of the vector which +/// happens to be logical end. Use blocks terminator as statement that specifies +/// where lifetime ends. +void CFGBuilder::prependAutomaticObjLifetimeWithTerminator( + CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { + if (!BuildOpts.AddLifetime) + return; + BumpVectorContext &C = cfg->getBumpVectorContext(); + CFGBlock::iterator InsertPos = + Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C); + for (LocalScope::const_iterator I = B; I != E; ++I) + InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator()); +} /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). @@ -1815,7 +1943,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { // If there is no target for the break, then we are looking at an incomplete // AST. This means that the CFG cannot be constructed. if (BreakJumpTarget.block) { - addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B); + addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B); addSuccessor(Block, BreakJumpTarget.block); } else badCFG = true; @@ -1947,13 +2075,12 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { LocalScope::const_iterator scopeBeginPos = ScopePos; - if (BuildOpts.AddImplicitDtors) { - addLocalScopeForStmt(C); - } + addLocalScopeForStmt(C); + if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) { // If the body ends with a ReturnStmt, the dtors will be added in // VisitReturnStmt. - addAutomaticObjDtors(ScopePos, scopeBeginPos, C); + addAutomaticObjHandling(ScopePos, scopeBeginPos, C); } CFGBlock *LastBlock = Block; @@ -2183,7 +2310,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { if (VarDecl *VD = I->getConditionVariable()) addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), I); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I); // The block we were processing is now finished. Make it the successor // block. @@ -2308,7 +2435,7 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { // Create the new block. Block = createBlock(false); - addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R); + addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R); // If the one of the destructors does not return, we already have the Exit // block as a successor. @@ -2389,7 +2516,7 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) { BackpatchBlocks.push_back(JumpSource(Block, ScopePos)); else { JumpTarget JT = I->second; - addAutomaticObjDtors(ScopePos, JT.scopePosition, G); + addAutomaticObjHandling(ScopePos, JT.scopePosition, G); addSuccessor(Block, JT.block); } @@ -2414,7 +2541,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { addLocalScopeForVarDecl(VD); LocalScope::const_iterator ContinueScopePos = ScopePos; - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F); // "for" is a control-flow statement. Thus we stop processing the current // block. @@ -2466,7 +2593,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { ContinueJumpTarget.block->setLoopTarget(F); // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F); // If body is not a compound statement create implicit scope // and add destructors. @@ -2753,7 +2880,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { LocalScope::const_iterator LoopBeginScopePos = ScopePos; if (VarDecl *VD = W->getConditionVariable()) { addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W); } // "while" is a control-flow statement. Thus we stop processing the current @@ -2788,7 +2915,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W); // If body is not a compound statement create implicit scope // and add destructors. @@ -3030,7 +3157,7 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { // If there is no target for the continue, then we are looking at an // incomplete AST. This means the CFG cannot be constructed. if (ContinueJumpTarget.block) { - addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C); + addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition, C); addSuccessor(Block, ContinueJumpTarget.block); } else badCFG = true; @@ -3085,7 +3212,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { if (VarDecl *VD = Terminator->getConditionVariable()) addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), Terminator); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator); if (Block) { if (badCFG) @@ -3373,7 +3500,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { if (VarDecl *VD = CS->getExceptionDecl()) { LocalScope::const_iterator BeginScopePos = ScopePos; addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, BeginScopePos, CS); + addAutomaticObjHandling(ScopePos, BeginScopePos, CS); } if (CS->getHandlerBlock()) @@ -3427,7 +3554,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { addLocalScopeForStmt(Begin); if (Stmt *End = S->getEndStmt()) addLocalScopeForStmt(End); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S); LocalScope::const_iterator ContinueScopePos = ScopePos; @@ -3898,6 +4025,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { case CFGElement::Statement: case CFGElement::Initializer: case CFGElement::NewAllocator: + case CFGElement::LifetimeEnds: llvm_unreachable("getDestructorDecl should only be used with " "ImplicitDtors"); case CFGElement::AutomaticObjectDtor: { @@ -4308,6 +4436,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; + } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) { + const VarDecl *VD = DE->getVarDecl(); + Helper.handleDecl(VD, OS); + + OS << " (Lifetime ends)\n"; + } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) { OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp index ee848ac711d6..5ea74989a7ec 100644 --- a/lib/Analysis/CloneDetection.cpp +++ b/lib/Analysis/CloneDetection.cpp @@ -16,13 +16,13 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" using namespace clang; +using namespace clang::clone_detection; StmtSequence::StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex, unsigned EndIndex) @@ -103,12 +103,8 @@ static void printMacroName(llvm::raw_string_ostream &MacroStack, MacroStack << " "; } -/// Returns a string that represents all macro expansions that expanded into the -/// given SourceLocation. -/// -/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations -/// A and B are expanded from the same macros in the same order. -static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) { +std::string clone_detection::getMacroStack(SourceLocation Loc, + ASTContext &Context) { std::string MacroStack; llvm::raw_string_ostream MacroStackStream(MacroStack); SourceManager &SM = Context.getSourceManager(); @@ -123,184 +119,6 @@ static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) { return MacroStack; } -namespace { -typedef unsigned DataPiece; - -/// Collects the data of a single Stmt. -/// -/// This class defines what a code clone is: If it collects for two statements -/// the same data, then those two statements are considered to be clones of each -/// other. -/// -/// All collected data is forwarded to the given data consumer of the type T. -/// The data consumer class needs to provide a member method with the signature: -/// update(StringRef Str) -template <typename T> -class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> { - - ASTContext &Context; - /// The data sink to which all data is forwarded. - T &DataConsumer; - -public: - /// Collects data of the given Stmt. - /// \param S The given statement. - /// \param Context The ASTContext of S. - /// \param DataConsumer The data sink to which all data is forwarded. - StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer) - : Context(Context), DataConsumer(DataConsumer) { - this->Visit(S); - } - - // Below are utility methods for appending different data to the vector. - - void addData(DataPiece Integer) { - DataConsumer.update( - StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer))); - } - - void addData(llvm::StringRef Str) { DataConsumer.update(Str); } - - void addData(const QualType &QT) { addData(QT.getAsString()); } - -// The functions below collect the class specific data of each Stmt subclass. - -// Utility macro for defining a visit method for a given class. This method -// calls back to the ConstStmtVisitor to visit all parent classes. -#define DEF_ADD_DATA(CLASS, CODE) \ - void Visit##CLASS(const CLASS *S) { \ - CODE; \ - ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \ - } - - DEF_ADD_DATA(Stmt, { - addData(S->getStmtClass()); - // This ensures that macro generated code isn't identical to macro-generated - // code. - addData(getMacroStack(S->getLocStart(), Context)); - addData(getMacroStack(S->getLocEnd(), Context)); - }) - DEF_ADD_DATA(Expr, { addData(S->getType()); }) - - //--- Builtin functionality ----------------------------------------------// - DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); }) - DEF_ADD_DATA(TypeTraitExpr, { - addData(S->getTrait()); - for (unsigned i = 0; i < S->getNumArgs(); ++i) - addData(S->getArg(i)->getType()); - }) - - //--- Calls --------------------------------------------------------------// - DEF_ADD_DATA(CallExpr, { - // Function pointers don't have a callee and we just skip hashing it. - if (const FunctionDecl *D = S->getDirectCallee()) { - // If the function is a template specialization, we also need to handle - // the template arguments as they are not included in the qualified name. - if (auto Args = D->getTemplateSpecializationArgs()) { - std::string ArgString; - - // Print all template arguments into ArgString - llvm::raw_string_ostream OS(ArgString); - for (unsigned i = 0; i < Args->size(); ++i) { - Args->get(i).print(Context.getLangOpts(), OS); - // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. - OS << '\n'; - } - OS.flush(); - - addData(ArgString); - } - addData(D->getQualifiedNameAsString()); - } - }) - - //--- Exceptions ---------------------------------------------------------// - DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); }) - - //--- C++ OOP Stmts ------------------------------------------------------// - DEF_ADD_DATA(CXXDeleteExpr, { - addData(S->isArrayFormAsWritten()); - addData(S->isGlobalDelete()); - }) - - //--- Casts --------------------------------------------------------------// - DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); }) - - //--- Miscellaneous Exprs ------------------------------------------------// - DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); }) - DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); }) - - //--- Control flow -------------------------------------------------------// - DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); }) - DEF_ADD_DATA(IndirectGotoStmt, { - if (S->getConstantTarget()) - addData(S->getConstantTarget()->getName()); - }) - DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); }) - DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); }) - DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); }) - - //--- Objective-C --------------------------------------------------------// - DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); }) - DEF_ADD_DATA(ObjCPropertyRefExpr, { - addData(S->isSuperReceiver()); - addData(S->isImplicitProperty()); - }) - DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); }) - - //--- Miscellaneous Stmts ------------------------------------------------// - DEF_ADD_DATA(CXXFoldExpr, { - addData(S->isRightFold()); - addData(S->getOperator()); - }) - DEF_ADD_DATA(GenericSelectionExpr, { - for (unsigned i = 0; i < S->getNumAssocs(); ++i) { - addData(S->getAssocType(i)); - } - }) - DEF_ADD_DATA(LambdaExpr, { - for (const LambdaCapture &C : S->captures()) { - addData(C.isPackExpansion()); - addData(C.getCaptureKind()); - if (C.capturesVariable()) - addData(C.getCapturedVar()->getType()); - } - addData(S->isGenericLambda()); - addData(S->isMutable()); - }) - DEF_ADD_DATA(DeclStmt, { - auto numDecls = std::distance(S->decl_begin(), S->decl_end()); - addData(static_cast<DataPiece>(numDecls)); - for (const Decl *D : S->decls()) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - addData(VD->getType()); - } - } - }) - DEF_ADD_DATA(AsmStmt, { - addData(S->isSimple()); - addData(S->isVolatile()); - addData(S->generateAsmString(Context)); - for (unsigned i = 0; i < S->getNumInputs(); ++i) { - addData(S->getInputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumOutputs(); ++i) { - addData(S->getOutputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumClobbers(); ++i) { - addData(S->getClobber(i)); - } - }) - DEF_ADD_DATA(AttributedStmt, { - for (const Attr *A : S->getAttrs()) { - addData(std::string(A->getSpelling())); - } - }) -}; -} // end anonymous namespace - void CloneDetector::analyzeCodeBody(const Decl *D) { assert(D); assert(D->hasBody()); @@ -421,16 +239,27 @@ size_t RecursiveCloneTypeIIConstraint::saveHash( } if (CS) { - for (unsigned Length = 2; Length <= CS->size(); ++Length) { - for (unsigned Pos = 0; Pos <= CS->size() - Length; ++Pos) { - llvm::MD5 Hash; - for (unsigned i = Pos; i < Pos + Length; ++i) { - size_t ChildHash = ChildHashes[i]; - Hash.update(StringRef(reinterpret_cast<char *>(&ChildHash), - sizeof(ChildHash))); + // If we're in a CompoundStmt, we hash all possible combinations of child + // statements to find clones in those subsequences. + // We first go through every possible starting position of a subsequence. + for (unsigned Pos = 0; Pos < CS->size(); ++Pos) { + // Then we try all possible lengths this subsequence could have and + // reuse the same hash object to make sure we only hash every child + // hash exactly once. + llvm::MD5 Hash; + for (unsigned Length = 1; Length <= CS->size() - Pos; ++Length) { + // Grab the current child hash and put it into our hash. We do + // -1 on the index because we start counting the length at 1. + size_t ChildHash = ChildHashes[Pos + Length - 1]; + Hash.update( + StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash))); + // If we have at least two elements in our subsequence, we can start + // saving it. + if (Length > 1) { + llvm::MD5 SubHash = Hash; + StmtsByHash.push_back(std::make_pair( + createHash(SubHash), StmtSequence(CS, D, Pos, Pos + Length))); } - StmtsByHash.push_back(std::make_pair( - createHash(Hash), StmtSequence(CS, D, Pos, Pos + Length))); } } } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 4f04489a4a10..50b4fc34ad3a 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -499,6 +499,10 @@ public: switch (Triple.getArch()) { default: break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: @@ -2049,7 +2053,7 @@ ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } -static const LangAS::Map AMDGPUNonOpenCLPrivateIsZeroMap = { +static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = { 4, // Default 1, // opencl_global 3, // opencl_local @@ -2059,7 +2063,7 @@ static const LangAS::Map AMDGPUNonOpenCLPrivateIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUNonOpenCLGenericIsZeroMap = { +static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = { 0, // Default 1, // opencl_global 3, // opencl_local @@ -2069,7 +2073,7 @@ static const LangAS::Map AMDGPUNonOpenCLGenericIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUOpenCLPrivateIsZeroMap = { +static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = { 0, // Default 1, // opencl_global 3, // opencl_local @@ -2079,7 +2083,7 @@ static const LangAS::Map AMDGPUOpenCLPrivateIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUOpenCLGenericIsZeroMap = { +static const LangAS::Map AMDGPUGenIsZeroDefIsPrivMap = { 5, // Default 1, // opencl_global 3, // opencl_local @@ -2184,20 +2188,37 @@ public: : DataLayoutStringR600); assert(DataLayout->getAllocaAddrSpace() == AS.Private); + setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || + Triple.getEnvironment() == llvm::Triple::OpenCL || + Triple.getEnvironmentName() == "amdgizcl" || + !isAMDGCN(Triple)); UseAddrSpaceMapMangling = true; + + // Set pointer width and alignment for target address space 0. + PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits(); + if (getMaxPointerWidth() == 64) { + LongWidth = LongAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } } - void adjust(LangOptions &Opts) override { - TargetInfo::adjust(Opts); + void setAddressSpaceMap(bool DefaultIsPrivate) { if (isGenericZero(getTriple())) { - AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLGenericIsZeroMap - : &AMDGPUNonOpenCLGenericIsZeroMap; + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap + : &AMDGPUGenIsZeroDefIsGenMap; } else { - AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLPrivateIsZeroMap - : &AMDGPUNonOpenCLPrivateIsZeroMap; + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap + : &AMDGPUPrivIsZeroDefIsGenMap; } } + void adjust(LangOptions &Opts) override { + TargetInfo::adjust(Opts); + setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple())); + } + uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (GPU <= GK_CAYMAN) return 32; @@ -2208,6 +2229,10 @@ public: return 64; } + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } + uint64_t getMaxPointerWidth() const override { return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; } @@ -2383,14 +2408,13 @@ public: return LangAS::opencl_constant; } - /// \returns Target specific vtbl ptr address space. - unsigned getVtblPtrAddressSpace() const override { - // \todo: We currently have address spaces defined in AMDGPU Backend. It - // would be nice if we could use it here instead of using bare numbers (same - // applies to getDWARFAddressSpace). - return 2; // constant. + llvm::Optional<unsigned> getConstantAddressSpace() const override { + return LangAS::FirstTargetAddressSpace + AS.Constant; } + /// \returns Target specific vtbl ptr address space. + unsigned getVtblPtrAddressSpace() const override { return AS.Constant; } + /// \returns If a target requires an address within a target specific address /// space \p AddressSpace to be converted in order to be used, then return the /// corresponding target specific DWARF address space. @@ -3874,7 +3898,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_PentiumMMX: Builder.defineMacro("__pentium_mmx__"); Builder.defineMacro("__tune_pentium_mmx__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_i586: case CK_Pentium: defineCPUMacros(Builder, "i586"); @@ -3884,15 +3908,15 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_Pentium3M: case CK_PentiumM: Builder.defineMacro("__tune_pentium3__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_Pentium2: case CK_C3_2: Builder.defineMacro("__tune_pentium2__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_PentiumPro: Builder.defineMacro("__tune_i686__"); Builder.defineMacro("__tune_pentiumpro__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_i686: Builder.defineMacro("__i686"); Builder.defineMacro("__i686__"); @@ -3948,7 +3972,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_K6_2: Builder.defineMacro("__k6_2__"); Builder.defineMacro("__tune_k6_2__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_K6_3: if (CPU != CK_K6_2) { // In case of fallthrough // FIXME: GCC may be enabling these in cases where some other k6 @@ -3957,7 +3981,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__k6_3__"); Builder.defineMacro("__tune_k6_3__"); } - // Fallthrough + LLVM_FALLTHROUGH; case CK_K6: defineCPUMacros(Builder, "k6"); break; @@ -6310,9 +6334,6 @@ public: MacroBuilder &Builder) const { // Also include the ARMv8.1 defines getTargetDefinesARMV81A(Opts, Builder); - - if (FPU == NeonMode && HasFullFP16) - Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); } void getTargetDefines(const LangOptions &Opts, @@ -7408,13 +7429,14 @@ class SystemZTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char *const GCCRegNames[]; std::string CPU; + int ISARevision; bool HasTransactionalExecution; bool HasVector; public: SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), - HasVector(false) { + : TargetInfo(Triple), CPU("z10"), ISARevision(8), + HasTransactionalExecution(false), HasVector(false) { IntMaxType = SignedLong; Int64Type = SignedLong; TLSSupported = true; @@ -7436,14 +7458,7 @@ public: Builder.defineMacro("__zarch__"); Builder.defineMacro("__LONG_DOUBLE_128__"); - const std::string ISARev = llvm::StringSwitch<std::string>(CPU) - .Cases("arch8", "z10", "8") - .Cases("arch9", "z196", "9") - .Cases("arch10", "zEC12", "10") - .Cases("arch11", "z13", "11") - .Default(""); - if (!ISARev.empty()) - Builder.defineMacro("__ARCH__", ISARev); + Builder.defineMacro("__ARCH__", Twine(ISARevision)); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -7476,37 +7491,35 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::SystemZBuiltinVaList; } + int getISARevision(const StringRef &Name) const { + return llvm::StringSwitch<int>(Name) + .Cases("arch8", "z10", 8) + .Cases("arch9", "z196", 9) + .Cases("arch10", "zEC12", 10) + .Cases("arch11", "z13", 11) + .Default(-1); + } bool setCPU(const std::string &Name) override { CPU = Name; - bool CPUKnown = llvm::StringSwitch<bool>(Name) - .Case("z10", true) - .Case("arch8", true) - .Case("z196", true) - .Case("arch9", true) - .Case("zEC12", true) - .Case("arch10", true) - .Case("z13", true) - .Case("arch11", true) - .Default(false); - - return CPUKnown; + ISARevision = getISARevision(CPU); + return ISARevision != -1; } bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector<std::string> &FeaturesVec) const override { - if (CPU == "zEC12" || CPU == "arch10") - Features["transactional-execution"] = true; - if (CPU == "z13" || CPU == "arch11") { + int ISARevision = getISARevision(CPU); + if (ISARevision >= 10) Features["transactional-execution"] = true; + if (ISARevision >= 11) Features["vector"] = true; - } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override { HasTransactionalExecution = false; + HasVector = false; for (const auto &Feature : Features) { if (Feature == "+transactional-execution") HasTransactionalExecution = true; @@ -7525,6 +7538,10 @@ public: bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch<bool>(Feature) .Case("systemz", true) + .Case("arch8", ISARevision >= 8) + .Case("arch9", ISARevision >= 9) + .Case("arch10", ISARevision >= 10) + .Case("arch11", ISARevision >= 11) .Case("htm", HasTransactionalExecution) .Case("vx", HasVector) .Default(false); diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 9b3850abcce7..513896d98634 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -998,7 +998,7 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile, BackendAction Action) { - StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> + StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 528a2b33acf8..181048957879 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -736,9 +736,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { llvm::Constant *isa = (!CGM.getContext().getLangOpts().OpenCL) ? CGM.getNSConcreteStackBlock() - : CGM.getNullPointer(cast<llvm::PointerType>( - CGM.getNSConcreteStackBlock()->getType()), - QualType(getContext().VoidPtrTy)); + : CGM.getNullPointer(VoidPtrPtrTy, + CGM.getContext().getPointerType( + QualType(CGM.getContext().VoidPtrTy))); isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy); // Build the block descriptor. @@ -1141,12 +1141,11 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, auto fields = builder.beginStruct(); // isa - fields.add( - (!CGM.getContext().getLangOpts().OpenCL) - ? CGM.getNSConcreteGlobalBlock() - : CGM.getNullPointer(cast<llvm::PointerType>( - CGM.getNSConcreteGlobalBlock()->getType()), - QualType(CGM.getContext().VoidPtrTy))); + fields.add((!CGM.getContext().getLangOpts().OpenCL) + ? CGM.getNSConcreteGlobalBlock() + : CGM.getNullPointer(CGM.VoidPtrPtrTy, + CGM.getContext().getPointerType(QualType( + CGM.getContext().VoidPtrTy)))); // __flags BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; @@ -1255,7 +1254,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, // For OpenCL passed block pointer can be private AS local variable or // global AS program scope variable (for the case with and without captures). - // Generic AS is used therefore to be able to accomodate both private and + // Generic AS is used therefore to be able to accommodate both private and // generic AS in one implementation. if (getLangOpts().OpenCL) selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType( diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2a6e92e7f3ce..bc902507c46e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1810,12 +1810,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__atomic_signal_fence: case Builtin::BI__c11_atomic_thread_fence: case Builtin::BI__c11_atomic_signal_fence: { - llvm::SynchronizationScope Scope; + llvm::SyncScope::ID SSID; if (BuiltinID == Builtin::BI__atomic_signal_fence || BuiltinID == Builtin::BI__c11_atomic_signal_fence) - Scope = llvm::SingleThread; + SSID = llvm::SyncScope::SingleThread; else - Scope = llvm::CrossThread; + SSID = llvm::SyncScope::System; Value *Order = EmitScalarExpr(E->getArg(0)); if (isa<llvm::ConstantInt>(Order)) { int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); @@ -1825,17 +1825,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, break; case 1: // memory_order_consume case 2: // memory_order_acquire - Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID); break; case 3: // memory_order_release - Builder.CreateFence(llvm::AtomicOrdering::Release, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Release, SSID); break; case 4: // memory_order_acq_rel - Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope); + Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID); break; case 5: // memory_order_seq_cst - Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - Scope); + Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID); break; } return RValue::get(nullptr); @@ -1852,23 +1851,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB); Builder.SetInsertPoint(AcquireBB); - Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(1), AcquireBB); SI->addCase(Builder.getInt32(2), AcquireBB); Builder.SetInsertPoint(ReleaseBB); - Builder.CreateFence(llvm::AtomicOrdering::Release, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Release, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(3), ReleaseBB); Builder.SetInsertPoint(AcqRelBB); - Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope); + Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(4), AcqRelBB); Builder.SetInsertPoint(SeqCstBB); - Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, Scope); + Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(5), SeqCstBB); @@ -2956,9 +2955,8 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF, return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad)); case NeonTypeFlags::Int16: case NeonTypeFlags::Poly16: - return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Float16: - return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad)); + return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -2981,8 +2979,6 @@ static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF, NeonTypeFlags IntTypeFlags) { int IsQuad = IntTypeFlags.isQuad(); switch (IntTypeFlags.getEltType()) { - case NeonTypeFlags::Int16: - return llvm::VectorType::get(CGF->HalfTy, (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->FloatTy, (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -3130,80 +3126,55 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0), NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), - NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvt_s16_v), NEONMAP0(vcvt_s32_v), NEONMAP0(vcvt_s64_v), - NEONMAP0(vcvt_u16_v), NEONMAP0(vcvt_u32_v), NEONMAP0(vcvt_u64_v), - NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0), - NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0), - NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0), - NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0), - NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0), - NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0), - NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0), - NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0), - NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0), - NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0), - NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0), - NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0), - NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0), - NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0), - NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0), NEONMAP0(vcvtq_f32_v), - NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvtq_s16_v), NEONMAP0(vcvtq_s32_v), NEONMAP0(vcvtq_s64_v), - NEONMAP0(vcvtq_u16_v), NEONMAP0(vcvtq_u32_v), NEONMAP0(vcvtq_u64_v), NEONMAP0(vext_v), @@ -3366,27 +3337,19 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = { NEONMAP1(vcnt_v, ctpop, Add1ArgType), NEONMAP1(vcntq_v, ctpop, Add1ArgType), NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0), - NEONMAP0(vcvt_f16_v), NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), - NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvtq_f16_v), NEONMAP0(vcvtq_f32_v), - NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType), @@ -3855,20 +3818,9 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcageq_v: case NEON::BI__builtin_neon_vcagt_v: case NEON::BI__builtin_neon_vcagtq_v: { - llvm::Type *Ty; - switch (VTy->getScalarSizeInBits()) { - default: llvm_unreachable("unexpected type"); - case 32: - Ty = FloatTy; - break; - case 64: - Ty = DoubleTy; - break; - case 16: - Ty = HalfTy; - break; - } - llvm::Type *VecFlt = llvm::VectorType::get(Ty, VTy->getNumElements()); + llvm::Type *VecFlt = llvm::VectorType::get( + VTy->getScalarSizeInBits() == 32 ? FloatTy : DoubleTy, + VTy->getNumElements()); llvm::Type *Tys[] = { VTy, VecFlt }; Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys); return EmitNeonCall(F, Ops, NameHint); @@ -3885,16 +3837,8 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad)); return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); - case NEON::BI__builtin_neon_vcvt_f16_v: - case NEON::BI__builtin_neon_vcvtq_f16_v: - Ops[0] = Builder.CreateBitCast(Ops[0], Ty); - Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad)); - return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") - : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); - case NEON::BI__builtin_neon_vcvt_n_f16_v: case NEON::BI__builtin_neon_vcvt_n_f32_v: case NEON::BI__builtin_neon_vcvt_n_f64_v: - case NEON::BI__builtin_neon_vcvtq_n_f16_v: case NEON::BI__builtin_neon_vcvtq_n_f32_v: case NEON::BI__builtin_neon_vcvtq_n_f64_v: { llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty }; @@ -3902,15 +3846,11 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Function *F = CGM.getIntrinsic(Int, Tys); return EmitNeonCall(F, Ops, "vcvt_n"); } - case NEON::BI__builtin_neon_vcvt_n_s16_v: case NEON::BI__builtin_neon_vcvt_n_s32_v: - case NEON::BI__builtin_neon_vcvt_n_u16_v: case NEON::BI__builtin_neon_vcvt_n_u32_v: case NEON::BI__builtin_neon_vcvt_n_s64_v: case NEON::BI__builtin_neon_vcvt_n_u64_v: - case NEON::BI__builtin_neon_vcvtq_n_s16_v: case NEON::BI__builtin_neon_vcvtq_n_s32_v: - case NEON::BI__builtin_neon_vcvtq_n_u16_v: case NEON::BI__builtin_neon_vcvtq_n_u32_v: case NEON::BI__builtin_neon_vcvtq_n_s64_v: case NEON::BI__builtin_neon_vcvtq_n_u64_v: { @@ -3922,63 +3862,44 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: - case NEON::BI__builtin_neon_vcvt_s16_v: - case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: - case NEON::BI__builtin_neon_vcvtq_s16_v: - case NEON::BI__builtin_neon_vcvtq_u16_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt") : Builder.CreateFPToSI(Ops[0], Ty, "vcvt"); } - case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvta_u32_v: case NEON::BI__builtin_neon_vcvta_u64_v: - case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: - case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvtaq_u64_v: - case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: - case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: case NEON::BI__builtin_neon_vcvtn_u64_v: - case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: - case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtnq_u64_v: - case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: - case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: case NEON::BI__builtin_neon_vcvtp_u64_v: - case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: - case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtpq_u64_v: - case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: - case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: case NEON::BI__builtin_neon_vcvtm_u64_v: - case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: - case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtmq_u64_v: { llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; @@ -6188,9 +6109,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3])); return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]}); } - case NEON::BI__builtin_neon_vfmah_lane_f16: case NEON::BI__builtin_neon_vfmas_lane_f32: - case NEON::BI__builtin_neon_vfmah_laneq_f16: case NEON::BI__builtin_neon_vfmas_laneq_f32: case NEON::BI__builtin_neon_vfmad_lane_f64: case NEON::BI__builtin_neon_vfmad_laneq_f64: { @@ -6365,25 +6284,18 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: - case NEON::BI__builtin_neon_vcvt_s16_v: - case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: - case NEON::BI__builtin_neon_vcvtq_s16_v: - case NEON::BI__builtin_neon_vcvtq_u16_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); if (usgn) return Builder.CreateFPToUI(Ops[0], Ty); return Builder.CreateFPToSI(Ops[0], Ty); } - case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: - case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvta_u32_v: - case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: @@ -6393,13 +6305,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta"); } - case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: - case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: - case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: - case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: @@ -6409,13 +6317,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm"); } - case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: - case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: - case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: - case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: @@ -6425,13 +6329,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn"); } - case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: - case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: - case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: - case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: @@ -6604,24 +6504,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } - case NEON::BI__builtin_neon_vmaxv_f16: { - Int = Intrinsic::aarch64_neon_fmaxv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxvq_f16: { - Int = Intrinsic::aarch64_neon_fmaxv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } case NEON::BI__builtin_neon_vminv_u8: { Int = Intrinsic::aarch64_neon_uminv; Ty = Int32Ty; @@ -6694,60 +6576,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } - case NEON::BI__builtin_neon_vminv_f16: { - Int = Intrinsic::aarch64_neon_fminv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminvq_f16: { - Int = Intrinsic::aarch64_neon_fminv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxnmv_f16: { - Int = Intrinsic::aarch64_neon_fmaxnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxnmvq_f16: { - Int = Intrinsic::aarch64_neon_fmaxnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminnmv_f16: { - Int = Intrinsic::aarch64_neon_fminnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminnmvq_f16: { - Int = Intrinsic::aarch64_neon_fminnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } case NEON::BI__builtin_neon_vmul_n_f64: { Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy); Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy); @@ -7506,6 +7334,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, AVX512PF, AVX512VBMI, AVX512IFMA, + AVX5124VNNIW, // TODO implement this fully + AVX5124FMAPS, // TODO implement this fully AVX512VPOPCNTDQ, MAX }; @@ -8208,13 +8038,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__faststorefence: { return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - llvm::CrossThread); + llvm::SyncScope::System); } case X86::BI_ReadWriteBarrier: case X86::BI_ReadBarrier: case X86::BI_WriteBarrier: { return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - llvm::SingleThread); + llvm::SyncScope::SingleThread); } case X86::BI_BitScanForward: case X86::BI_BitScanForward64: diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 13a156c7bbd7..cee656a62fe7 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -129,7 +129,7 @@ static void addExtParameterInfosForCall( paramInfos.resize(totalArgs); } -/// Adds the formal paramaters in FPT to the given prefix. If any parameter in +/// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size attrs, then we'll add parameters for those, too. static void appendParameterTypes(const CodeGenTypes &CGT, SmallVectorImpl<CanQualType> &prefix, diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 127d7df348ee..50d702c62268 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -2716,88 +2716,6 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( cast<llvm::PointerType>(VTable->getType())->getElementType()); } -bool -CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, - const CXXMethodDecl *MD) { - // When building with -fapple-kext, all calls must go through the vtable since - // the kernel linker can do runtime patching of vtables. - if (getLangOpts().AppleKext) - return false; - - // If the member function is marked 'final', we know that it can't be - // overridden and can therefore devirtualize it unless it's pure virtual. - if (MD->hasAttr<FinalAttr>()) - return !MD->isPure(); - - // If the base expression (after skipping derived-to-base conversions) is a - // class prvalue, then we can devirtualize. - Base = Base->getBestDynamicClassTypeExpr(); - if (Base->isRValue() && Base->getType()->isRecordType()) - return true; - - // If we don't even know what we would call, we can't devirtualize. - const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); - if (!BestDynamicDecl) - return false; - - // There may be a method corresponding to MD in a derived class. - const CXXMethodDecl *DevirtualizedMethod = - MD->getCorrespondingMethodInClass(BestDynamicDecl); - - // If that method is pure virtual, we can't devirtualize. If this code is - // reached, the result would be UB, not a direct call to the derived class - // function, and we can't assume the derived class function is defined. - if (DevirtualizedMethod->isPure()) - return false; - - // If that method is marked final, we can devirtualize it. - if (DevirtualizedMethod->hasAttr<FinalAttr>()) - return true; - - // Similarly, if the class itself is marked 'final' it can't be overridden - // and we can therefore devirtualize the member function call. - if (BestDynamicDecl->hasAttr<FinalAttr>()) - return true; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - // This is a record decl. We know the type and can devirtualize it. - return VD->getType()->isRecordType(); - } - - return false; - } - - // We can devirtualize calls on an object accessed by a class member access - // expression, since by C++11 [basic.life]p6 we know that it can't refer to - // a derived class object constructed in the same location. However, we avoid - // devirtualizing a call to a template function that we could instantiate - // implicitly, but have not decided to do so. This is needed because if this - // function does not get instantiated, the devirtualization will create a - // direct call to a function whose body may not exist. In contrast, calls to - // template functions that are not defined in this TU are allowed to be - // devirtualized under assumption that it is user responsibility to - // instantiate them in some other TU. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) - if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) - return VD->getType()->isRecordType() && - (MD->instantiationIsPending() || MD->isDefined() || - !MD->isImplicitlyInstantiable()); - - // Likewise for calls on an object accessed by a (non-reference) pointer to - // member access. - if (auto *BO = dyn_cast<BinaryOperator>(Base)) { - if (BO->isPtrMemOp()) { - auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>(); - if (MPT->getPointeeType()->isRecordType()) - return true; - } - } - - // We can't devirtualize the call. - return false; -} - void CodeGenFunction::EmitForwardingCallToLambda( const CXXMethodDecl *callOperator, CallArgList &callArgs) { diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 4b656ea4a879..23517867437c 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -221,8 +221,8 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( Name = getStaticDeclName(*this, D); llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty); - unsigned AddrSpace = - GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty)); + unsigned AS = GetGlobalVarAddressSpace(&D); + unsigned TargetAS = getContext().getTargetAddressSpace(AS); // Local address space cannot have an initializer. llvm::Constant *Init = nullptr; @@ -231,12 +231,9 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( else Init = llvm::UndefValue::get(LTy); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(getModule(), LTy, - Ty.isConstant(getContext()), Linkage, - Init, Name, nullptr, - llvm::GlobalVariable::NotThreadLocal, - AddrSpace); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name, + nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); setGlobalVisibility(GV, &D); @@ -254,11 +251,12 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( } // Make sure the result is of the correct type. - unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty); + unsigned ExpectedAS = Ty.getAddressSpace(); llvm::Constant *Addr = GV; - if (AddrSpace != ExpectedAddrSpace) { - llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace); - Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy); + if (AS != ExpectedAS) { + Addr = getTargetCodeGenInfo().performAddrSpaceCast( + *this, GV, AS, ExpectedAS, + LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS))); } setStaticLocalDeclAddress(&D, Addr); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2ee1c96a6619..9f40ee5a00a3 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -338,9 +338,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } } -static Address -createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, const Expr *Inner) { +static Address createReferenceTemporary(CodeGenFunction &CGF, + const MaterializeTemporaryExpr *M, + const Expr *Inner) { + auto &TCG = CGF.getTargetHooks(); switch (M->getStorageDuration()) { case SD_FullExpression: case SD_Automatic: { @@ -353,13 +354,24 @@ createReferenceTemporary(CodeGenFunction &CGF, (Ty->isArrayType() || Ty->isRecordType()) && CGF.CGM.isTypeConstant(Ty, true)) if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) { - auto *GV = new llvm::GlobalVariable( - CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, - llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp"); - CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty); - GV->setAlignment(alignment.getQuantity()); - // FIXME: Should we put the new global into a COMDAT? - return Address(GV, alignment); + if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) { + auto AS = AddrSpace.getValue(); + auto *GV = new llvm::GlobalVariable( + CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, + llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr, + llvm::GlobalValue::NotThreadLocal, + CGF.getContext().getTargetAddressSpace(AS)); + CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty); + GV->setAlignment(alignment.getQuantity()); + llvm::Constant *C = GV; + if (AS != LangAS::Default) + C = TCG.performAddrSpaceCast( + CGF.CGM, GV, AS, LangAS::Default, + GV->getValueType()->getPointerTo( + CGF.getContext().getTargetAddressSpace(LangAS::Default))); + // FIXME: Should we put the new global into a COMDAT? + return Address(C, alignment); + } } return CGF.CreateMemTemp(Ty, "ref.tmp"); } @@ -440,9 +452,11 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // Create and initialize the reference temporary. Address Object = createReferenceTemporary(*this, M, E); - if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) { + if (auto *Var = dyn_cast<llvm::GlobalVariable>( + Object.getPointer()->stripPointerCasts())) { Object = Address(llvm::ConstantExpr::getBitCast( - Var, ConvertTypeForMem(E->getType())->getPointerTo()), + cast<llvm::Constant>(Object.getPointer()), + ConvertTypeForMem(E->getType())->getPointerTo()), Object.getAlignment()); // If the temporary is a global and has a constant initializer or is a // constant temporary that we promoted to a global, we may have already diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index a9865f3703d4..ab170245284c 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -199,7 +199,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier; const CXXMethodDecl *DevirtualizedMethod = nullptr; - if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) { + if (CanUseVirtualCall && + MD->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) { const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl); assert(DevirtualizedMethod); diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 3df95a4e9b2a..a2ea0dec3e9d 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4157,9 +4157,15 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, /*IsInitializer=*/true); enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 }; llvm::Value *TaskArgs[] = { - UpLoc, ThreadID, Result.NewTask, IfVal, LBLVal.getPointer(), - UBLVal.getPointer(), CGF.EmitLoadOfScalar(StLVal, SourceLocation()), - llvm::ConstantInt::getSigned(CGF.IntTy, Data.Nogroup ? 1 : 0), + UpLoc, + ThreadID, + Result.NewTask, + IfVal, + LBLVal.getPointer(), + UBLVal.getPointer(), + CGF.EmitLoadOfScalar(StLVal, SourceLocation()), + llvm::ConstantInt::getNullValue( + CGF.IntTy), // Always 0 because taskgroup emitted by the compiler llvm::ConstantInt::getSigned( CGF.IntTy, Data.Schedule.getPointer() ? Data.Schedule.getInt() ? NumTasks : Grainsize @@ -4168,10 +4174,9 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty, /*isSigned=*/false) : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0), - Result.TaskDupFn - ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Result.TaskDupFn, - CGF.VoidPtrTy) - : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; + Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + Result.TaskDupFn, CGF.VoidPtrTy) + : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs); } diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 493cd627e418..71797e2e6fbe 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -4363,7 +4363,18 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop, CodeGen); }; - EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + if (Data.Nogroup) + EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + else { + CGM.getOpenMPRuntime().emitTaskgroupRegion( + *this, + [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + CGF.EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + }, + S.getLocStart()); + } } void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) { diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp index 166f44f816f3..0735a9c3dfbc 100644 --- a/lib/CodeGen/CodeGenABITypes.cpp +++ b/lib/CodeGen/CodeGenABITypes.cpp @@ -64,3 +64,19 @@ CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM, returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes, info, {}, args); } + +llvm::FunctionType * +CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) { + assert(FD != nullptr && "Expected a non-null function declaration!"); + llvm::Type *T = CGM.getTypes().ConvertFunctionType(FD->getType(), FD); + + if (auto FT = dyn_cast<llvm::FunctionType>(T)) + return FT; + + return nullptr; +} + +llvm::Type * +CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) { + return CGM.getTypes().ConvertTypeForMem(T); +} diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6785111bd052..5933e029be8d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1479,6 +1479,9 @@ public: const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } + const TargetCodeGenInfo &getTargetHooks() const { + return CGM.getTargetCodeGenInfo(); + } //===--------------------------------------------------------------------===// // Cleanups @@ -1749,11 +1752,6 @@ public: llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableByteOffset); - /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given - /// expr can be devirtualized. - bool CanDevirtualizeMemberFunctionCall(const Expr *Base, - const CXXMethodDecl *MD); - /// EnterDtorCleanups - Enter the cleanups necessary to complete the /// given phase of destruction for a destructor. The end result /// should call destructors on members and base classes in reverse @@ -3820,10 +3818,6 @@ public: private: QualType getVarArgType(const Expr *Arg); - const TargetCodeGenInfo &getTargetHooks() const { - return CGM.getTargetCodeGenInfo(); - } - void EmitDeclMetadata(); BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5319ccec163f..4b15b8ac4c71 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -98,7 +98,6 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, Int16Ty = llvm::Type::getInt16Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); - HalfTy = llvm::Type::getHalfTy(LLVMContext); FloatTy = llvm::Type::getFloatTy(LLVMContext); DoubleTy = llvm::Type::getDoubleTy(LLVMContext); PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); @@ -1099,7 +1098,7 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, const NamedDecl *ND) { // Set linkage and visibility in case we never see a definition. LinkageInfo LV = ND->getLinkageAndVisibility(); - if (LV.getLinkage() != ExternalLinkage) { + if (!isExternallyVisible(LV.getLinkage())) { // Don't set internal linkage on declarations. } else { if (ND->hasAttr<DLLImportAttr>()) { @@ -2368,11 +2367,13 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, return llvm::ConstantExpr::getBitCast(Entry, Ty); } - unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace()); + auto AddrSpace = GetGlobalVarAddressSpace(D); + auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace); + auto *GV = new llvm::GlobalVariable( getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr, - llvm::GlobalVariable::NotThreadLocal, AddrSpace); + llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace); // If we already created a global with the same mangled name (but different // type) before, take its name and remove it from its parent. @@ -2429,8 +2430,15 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, GV->setSection(".cp.rodata"); } - if (AddrSpace != Ty->getAddressSpace()) - return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty); + auto ExpectedAS = + D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangOpts.OpenCL ? LangAS::opencl_global + : LangAS::Default); + assert(getContext().getTargetAddressSpace(ExpectedAS) == + Ty->getPointerAddressSpace()); + if (AddrSpace != ExpectedAS) + return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace, + ExpectedAS, Ty); return GV; } @@ -2564,18 +2572,28 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { getDataLayout().getTypeStoreSizeInBits(Ty)); } -unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, - unsigned AddrSpace) { - if (D && LangOpts.CUDA && LangOpts.CUDAIsDevice) { - if (D->hasAttr<CUDAConstantAttr>()) - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant); - else if (D->hasAttr<CUDASharedAttr>()) - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared); +unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { + unsigned AddrSpace; + if (LangOpts.OpenCL) { + AddrSpace = D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangAS::opencl_global); + assert(AddrSpace == LangAS::opencl_global || + AddrSpace == LangAS::opencl_constant || + AddrSpace == LangAS::opencl_local || + AddrSpace >= LangAS::FirstTargetAddressSpace); + return AddrSpace; + } + + if (LangOpts.CUDA && LangOpts.CUDAIsDevice) { + if (D && D->hasAttr<CUDAConstantAttr>()) + return LangAS::cuda_constant; + else if (D && D->hasAttr<CUDASharedAttr>()) + return LangAS::cuda_shared; else - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device); + return LangAS::cuda_device; } - return AddrSpace; + return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D); } template<typename SomeDecl> @@ -2728,10 +2746,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, // "extern int x[];") and then a definition of a different type (e.g. // "int x[10];"). This also happens when an initializer has a different type // from the type of the global (this happens with unions). - if (!GV || - GV->getType()->getElementType() != InitType || + if (!GV || GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != - GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) { + getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) { // Move the old entry aside so that we'll create a new one. Entry->setName(StringRef()); @@ -3740,20 +3757,26 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( Linkage = llvm::GlobalVariable::InternalLinkage; } } - unsigned AddrSpace = GetGlobalVarAddressSpace( - VD, getContext().getTargetAddressSpace(MaterializedType)); + unsigned AddrSpace = + VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace(); + auto TargetAS = getContext().getTargetAddressSpace(AddrSpace); auto *GV = new llvm::GlobalVariable( getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(), - /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, - AddrSpace); + /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); setGlobalVisibility(GV, VD); GV->setAlignment(Align.getQuantity()); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); if (VD->getTLSKind()) setTLSMode(GV, *VD); - MaterializedGlobalTemporaryMap[E] = GV; - return ConstantAddress(GV, Align); + llvm::Constant *CV = GV; + if (AddrSpace != LangAS::Default) + CV = getTargetCodeGenInfo().performAddrSpaceCast( + *this, GV, AddrSpace, LangAS::Default, + Type->getPointerTo( + getContext().getTargetAddressSpace(LangAS::Default))); + MaterializedGlobalTemporaryMap[E] = CV; + return ConstantAddress(CV, Align); } /// EmitObjCPropertyImplementations - Emit information for synthesized diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c5f1a2b409ee..b162e72d1992 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -710,11 +710,15 @@ public: SourceLocation Loc = SourceLocation(), bool TLS = false); - /// Return the address space of the underlying global variable for D, as + /// Return the AST address space of the underlying global variable for D, as /// determined by its declaration. Normally this is the same as the address /// space of D's type, but in CUDA, address spaces are associated with - /// declarations, not types. - unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace); + /// declarations, not types. If D is nullptr, return the default address + /// space for global variable. + /// + /// For languages without explicit address spaces, if D has default address + /// space, target-specific global or constant address space may be returned. + unsigned GetGlobalVarAddressSpace(const VarDecl *D); /// Return the llvm::Constant for the address of the given global variable. /// If Ty is non-null and if the global doesn't exist, then it will be created diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h index 6910d36733dc..450eab48a3b4 100644 --- a/lib/CodeGen/CodeGenTypeCache.h +++ b/lib/CodeGen/CodeGenTypeCache.h @@ -36,7 +36,7 @@ struct CodeGenTypeCache { /// i8, i16, i32, and i64 llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; /// float, double - llvm::Type *HalfTy, *FloatTy, *DoubleTy; + llvm::Type *FloatTy, *DoubleTy; /// int llvm::IntegerType *IntTy; diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 39efb9f43921..c82b9677eacf 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2732,7 +2732,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, // function. bool IsDLLImport = RD->hasAttr<DLLImportAttr>(); if (CGM.getVTables().isVTableExternal(RD)) - return IsDLLImport ? false : true; + return IsDLLImport && !CGM.getTriple().isWindowsItaniumEnvironment() + ? false + : true; if (IsDLLImport) return true; @@ -2957,6 +2959,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: // RTTI is not enabled, which means that this type info struct is going // to be used for exception handling. Give it linkonce_odr linkage. @@ -2968,7 +2972,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, if (RD->hasAttr<WeakAttr>()) return llvm::GlobalValue::WeakODRLinkage; if (CGM.getTriple().isWindowsItaniumEnvironment()) - if (RD->hasAttr<DLLImportAttr>()) + if (RD->hasAttr<DLLImportAttr>() && + ShouldUseExternalRTTIDescriptor(CGM, Ty)) return llvm::GlobalValue::ExternalLinkage; if (RD->isDynamicClass()) { llvm::GlobalValue::LinkageTypes LT = CGM.getVTableLinkage(RD); @@ -3181,7 +3186,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force, if (DLLExport || (RD && RD->hasAttr<DLLExportAttr>())) { TypeName->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); - } else if (CGM.getLangOpts().RTTI && RD && RD->hasAttr<DLLImportAttr>()) { + } else if (RD && RD->hasAttr<DLLImportAttr>() && + ShouldUseExternalRTTIDescriptor(CGM, Ty)) { TypeName->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index e68a16e0bd51..78b510bb4665 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3425,6 +3425,8 @@ static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) { return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: return llvm::GlobalValue::LinkOnceODRLinkage; } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 8d00e055306d..eeebd60a2d20 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -416,14 +416,34 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule & return llvm::ConstantPointerNull::get(T); } +unsigned TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const { + assert(!CGM.getLangOpts().OpenCL && + !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && + "Address space agnostic languages only"); + return D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangAS::Default); +} + llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( CodeGen::CodeGenFunction &CGF, llvm::Value *Src, unsigned SrcAddr, unsigned DestAddr, llvm::Type *DestTy, bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. + if (auto *C = dyn_cast<llvm::Constant>(Src)) + return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy); return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy); } +llvm::Constant * +TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, + unsigned SrcAddr, unsigned DestAddr, + llvm::Type *DestTy) const { + // Since target may map different address spaces in AST to the same address + // space, an address space conversion may end up as a bitcast. + return llvm::ConstantExpr::getPointerCast(Src, DestTy); +} + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -7325,6 +7345,8 @@ public: return LangAS::FirstTargetAddressSpace + getABIInfo().getDataLayout().getAllocaAddrSpace(); } + unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const override; }; } @@ -7408,6 +7430,31 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer( llvm::ConstantPointerNull::get(NPT), PT); } +unsigned +AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const { + assert(!CGM.getLangOpts().OpenCL && + !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && + "Address space agnostic languages only"); + unsigned DefaultGlobalAS = + LangAS::FirstTargetAddressSpace + + CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + if (!D) + return DefaultGlobalAS; + + unsigned AddrSpace = D->getType().getAddressSpace(); + assert(AddrSpace == LangAS::Default || + AddrSpace >= LangAS::FirstTargetAddressSpace); + if (AddrSpace != LangAS::Default) + return AddrSpace; + + if (CGM.isTypeConstant(D->getType(), false)) { + if (auto ConstAS = CGM.getTarget().getConstantAddressSpace()) + return ConstAS.getValue(); + } + return DefaultGlobalAS; +} + //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 247d01dcb086..952ef96c4aef 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -229,6 +229,13 @@ public: virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const; + /// Get target favored AST address space of a global variable for languages + /// other than OpenCL and CUDA. + /// If \p D is nullptr, returns the default target favored address space + /// for global variable. + virtual unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const; + /// Get the AST address space for alloca. virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; } @@ -243,6 +250,15 @@ public: unsigned DestAddr, llvm::Type *DestTy, bool IsNonNull = false) const; + + /// Perform address space cast of a constant expression of pointer type. + /// \param V is the LLVM constant to be casted to another address space. + /// \param SrcAddr is the language address space of \p V. + /// \param DestAddr is the targeted language address space. + /// \param DestTy is the destination LLVM pointer type. + virtual llvm::Constant * + performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *V, unsigned SrcAddr, + unsigned DestAddr, llvm::Type *DestTy) const; }; } // namespace CodeGen diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index faced0697ed9..42478013ccec 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -572,8 +572,22 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, if (TT.getArch() == llvm::Triple::UnknownArch) Diag(clang::diag::err_drv_invalid_omp_target) << Val; else { - const ToolChain &TC = getToolChain(C.getInputArgs(), TT); - C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP); + const ToolChain *TC; + // CUDA toolchains have to be selected differently. They pair host + // and device in their implementation. + if (TT.isNVPTX()) { + const ToolChain *HostTC = + C.getSingleOffloadToolChain<Action::OFK_Host>(); + assert(HostTC && "Host toolchain should be always defined."); + auto &CudaTC = + ToolChains[TT.str() + "/" + HostTC->getTriple().str()]; + if (!CudaTC) + CudaTC = llvm::make_unique<toolchains::CudaToolChain>( + *this, TT, *HostTC, C.getInputArgs()); + TC = CudaTC.get(); + } else + TC = &getToolChain(C.getInputArgs(), TT); + C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); } } } else @@ -1247,11 +1261,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { StringRef PassedFlags = A->getValue(); std::vector<std::string> SuggestedCompletions; + unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; + // We want to show cc1-only options only when clang is invoked as "clang -cc1". + // When clang is invoked as "clang -cc1", we add "#" to the beginning of an --autocomplete + // option so that the clang driver can distinguish whether it is requested to show cc1-only options or not. + if (PassedFlags[0] == '#') { + DisableFlags &= ~options::NoDriverOption; + PassedFlags = PassedFlags.substr(1); + } + if (PassedFlags.find(',') == StringRef::npos) { // If the flag is in the form of "--autocomplete=-foo", // we were requested to print out all option names that start with "-foo". // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". - SuggestedCompletions = Opts->findByPrefix(PassedFlags); + SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); } else { // If the flag is in the form of "--autocomplete=foo,bar", we were // requested to print out all option values for "-foo" that start with diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 4f82503276f4..2be7f0f69004 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -544,9 +544,9 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Each toolchain should provide the appropriate include flags. } -void ToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { -} +void ToolChain::addClangTargetOptions( + const ArgList &DriverArgs, ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const {} void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index 8cafd3c74bfb..95b86f784f91 100644 --- a/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -179,6 +179,18 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { ABI = FloatABI::Hard; break; + case llvm::Triple::NetBSD: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + ABI = FloatABI::Hard; + break; + default: + ABI = FloatABI::Soft; + break; + } + break; + case llvm::Triple::FreeBSD: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp index 33eff32b9731..b45dcd6db678 100644 --- a/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/lib/Driver/ToolChains/Arch/Mips.cpp @@ -227,12 +227,11 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); } - if (IsN64 && NonPIC) { + if (IsN64 && NonPIC) Features.push_back("+noabicalls"); - } else { + else AddTargetFeature(Args, Features, options::OPT_mno_abicalls, options::OPT_mabicalls, "noabicalls"); - } mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args); if (FloatABI == mips::FloatABI::Soft) { @@ -298,13 +297,11 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, options::OPT_modd_spreg, "nooddspreg"); - - if (Arg *A = Args.getLastArg(options::OPT_mmadd4, options::OPT_mno_madd4)) { - if (A->getOption().matches(options::OPT_mmadd4)) - Features.push_back("-nomadd4"); - else - Features.push_back("+nomadd4"); - } + AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, + "nomadd4"); + AddTargetFeature(Args, Features, options::OPT_mlong_calls, + options::OPT_mno_long_calls, "long-calls"); + AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt,"mt"); } mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp index 66246f6d71cd..5dc6dfad927b 100644 --- a/lib/Driver/ToolChains/BareMetal.cpp +++ b/lib/Driver/ToolChains/BareMetal.cpp @@ -98,7 +98,8 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); } diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h index 064c1199735b..4b74899fa53e 100644 --- a/lib/Driver/ToolChains/BareMetal.h +++ b/lib/Driver/ToolChains/BareMetal.h @@ -54,7 +54,8 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 3731aa83ef06..e759e3ec619a 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -2544,7 +2544,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); - getToolChain().addClangTargetOptions(Args, CmdArgs); + getToolChain().addClangTargetOptions(Args, CmdArgs, + JA.getOffloadingDeviceKind()); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2974,6 +2975,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + for (const Arg *A : + Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) { + D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args); + A->claim(); + } + claimNoWarnArgs(Args); Args.AddAllArgs(CmdArgs, options::OPT_R_Group); diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index e8bb703054de..00bd60bc24bb 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -524,6 +524,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-lm"); // There's no libdl on FreeBSD or RTEMS. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::NetBSD && TC.getTriple().getOS() != llvm::Triple::RTEMS) CmdArgs.push_back("-ldl"); } diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp index 42bf164f1b3f..935a5a37ada5 100644 --- a/lib/Driver/ToolChains/Cuda.cpp +++ b/lib/Driver/ToolChains/Cuda.cpp @@ -338,24 +338,31 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, void CudaToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - HostTC.addClangTargetOptions(DriverArgs, CC1Args); + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - CC1Args.push_back("-fcuda-is-device"); + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + assert((DeviceOffloadingKind == Action::OFK_OpenMP || + DeviceOffloadingKind == Action::OFK_Cuda) && + "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs."); - if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, - options::OPT_fno_cuda_flush_denormals_to_zero, false)) - CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + if (DeviceOffloadingKind == Action::OFK_Cuda) { + CC1Args.push_back("-fcuda-is-device"); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); + if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, false)) + CC1Args.push_back("-fcuda-flush-denormals-to-zero"); - if (DriverArgs.hasArg(options::OPT_nocudalib)) - return; + if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, + options::OPT_fno_cuda_approx_transcendentals, false)) + CC1Args.push_back("-fcuda-approx-transcendentals"); + + if (DriverArgs.hasArg(options::OPT_nocudalib)) + return; + } - StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); - assert(!GpuArch.empty() && "Must have an explicit GPU arch."); std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); if (LibDeviceFile.empty()) { @@ -396,6 +403,24 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); + // For OpenMP device offloading, append derived arguments. Make sure + // flags are not duplicated. + // TODO: Append the compute capability. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + for (Arg *A : Args){ + bool IsDuplicate = false; + for (Arg *DALArg : *DAL){ + if (A == DALArg) { + IsDuplicate = true; + break; + } + } + if (!IsDuplicate) + DAL->append(A); + } + return DAL; + } + for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches BoundArch diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h index acdb4c4efd6d..e66fc23d82f3 100644 --- a/lib/Driver/ToolChains/Cuda.h +++ b/lib/Driver/ToolChains/Cuda.h @@ -130,7 +130,8 @@ public: TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index 7b61095c3ba9..ba1a5ee95594 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -1118,6 +1118,27 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } +/// Returns the most appropriate macOS target version for the current process. +/// +/// If the macOS SDK version is the same or earlier than the system version, +/// then the SDK version is returned. Otherwise the system version is returned. +static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { + unsigned Major, Minor, Micro; + llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); + if (!SystemTriple.isMacOSX()) + return MacOSSDKVersion; + SystemTriple.getMacOSXVersion(Major, Minor, Micro); + VersionTuple SystemVersion(Major, Minor, Micro); + bool HadExtra; + if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, + HadExtra)) + return MacOSSDKVersion; + VersionTuple SDKVersion(Major, Minor, Micro); + if (SDKVersion > SystemVersion) + return SystemVersion.getAsString(); + return MacOSSDKVersion; +} + void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); @@ -1229,7 +1250,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { SDK.startswith("iPhoneSimulator")) iOSTarget = Version; else if (SDK.startswith("MacOSX")) - OSXTarget = Version; + OSXTarget = getSystemOrSDKMacOSVersion(Version); else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) WatchOSTarget = Version; @@ -1708,7 +1729,8 @@ bool Darwin::isAlignedAllocationUnavailable() const { } void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { if (isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); } diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index ffcdf9a71a46..6cb1d04b78c0 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/lib/Driver/ToolChains/Darwin.h @@ -390,7 +390,8 @@ protected: bool isAlignedAllocationUnavailable() const; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; StringRef getPlatformFamily() const; static StringRef getSDKName(StringRef isysroot); diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp index b8757cf4aa73..d8b8fe8f0bfe 100644 --- a/lib/Driver/ToolChains/Fuchsia.cpp +++ b/lib/Driver/ToolChains/Fuchsia.cpp @@ -131,16 +131,44 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. +static std::string normalizeTriple(llvm::Triple Triple) { + SmallString<64> T; + T += Triple.getArchName(); + T += "-"; + T += Triple.getOSName(); + return T.str(); +} + +static std::string getTargetDir(const Driver &D, + llvm::Triple Triple) { + SmallString<128> P(llvm::sys::path::parent_path(D.Dir)); + llvm::sys::path::append(P, "lib", normalizeTriple(Triple)); + return P.str(); +} + Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - getFilePaths().push_back(D.SysRoot + "/lib"); - getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); + : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != D.Dir) + getProgramPaths().push_back(D.Dir); + + SmallString<128> P(getTargetDir(D, getTriple())); + llvm::sys::path::append(P, "lib"); + getFilePaths().push_back(P.str()); + + if (!D.SysRoot.empty()) { + SmallString<128> P(D.SysRoot); + llvm::sys::path::append(P, "lib"); + getFilePaths().push_back(P.str()); + } } -Tool *Fuchsia::buildAssembler() const { - return new tools::gnutools::Assembler(*this); +std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); + Triple.setTriple(normalizeTriple(Triple)); + return Triple.getTriple(); } Tool *Fuchsia::buildLinker() const { @@ -172,7 +200,8 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const { } void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fuse-init-array"); @@ -207,19 +236,44 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); + if (!D.SysRoot.empty()) { + SmallString<128> P(D.SysRoot); + llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); + } } -std::string Fuchsia::findLibCxxIncludePath() const { - return getDriver().SysRoot + "/include/c++/v1"; +void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + SmallString<128> P(getTargetDir(getDriver(), getTriple())); + llvm::sys::path::append(P, "include", "c++", "v1"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + break; + } + + default: + llvm_unreachable("invalid stdlib name"); + } } void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - (void) GetCXXStdlibType(Args); - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); + break; + + case ToolChain::CST_Libstdcxx: + llvm_unreachable("invalid stdlib name"); + } } SanitizerMask Fuchsia::getSupportedSanitizers() const { diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h index 1a8c9903fe4d..a723a99dfa3b 100644 --- a/lib/Driver/ToolChains/Fuchsia.h +++ b/lib/Driver/ToolChains/Fuchsia.h @@ -35,18 +35,29 @@ public: namespace toolchains { -class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { +class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain { public: Fuchsia(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { return true; } bool HasNativeLLVMSupport() const override { return true; } bool IsIntegratedAssemblerDefault() const override { return true; } + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return true; } + bool isPICDefaultForced() const override { return false; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::GDB; } + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, + types::ID InputType) const override; + SanitizerMask getSupportedSanitizers() const override; RuntimeLibType @@ -55,11 +66,14 @@ public: GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; + void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -68,7 +82,6 @@ public: } protected: - Tool *buildAssembler() const override; Tool *buildLinker() const override; }; diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index bca5d3a3f28b..ad5f7df50d2e 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -2461,7 +2461,8 @@ Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, void Generic_ELF::anchor() {} void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h index 1dc1ad49e305..cdf610054401 100644 --- a/lib/Driver/ToolChains/Gnu.h +++ b/lib/Driver/ToolChains/Gnu.h @@ -341,7 +341,8 @@ public: : Generic_GCC(D, Triple, Args) {} void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; }; } // end namespace toolchains diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp index 1d7bcf8e4df0..9bf1590e6a37 100644 --- a/lib/Driver/ToolChains/Hexagon.cpp +++ b/lib/Driver/ToolChains/Hexagon.cpp @@ -428,7 +428,8 @@ unsigned HexagonToolChain::getOptimizationLevel( } void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasArg(options::OPT_ffp_contract)) return; unsigned OptLevel = getOptimizationLevel(DriverArgs); diff --git a/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h index 78f97a3d59fd..7f9a6b2f34b9 100644 --- a/lib/Driver/ToolChains/Hexagon.h +++ b/lib/Driver/ToolChains/Hexagon.h @@ -69,7 +69,8 @@ public: ~HexagonToolChain() override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp index d7d3ad61df42..a1a3108cb28d 100644 --- a/lib/Driver/ToolChains/NetBSD.cpp +++ b/lib/Driver/ToolChains/NetBSD.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -246,6 +247,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); + bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); unsigned Major, Minor, Micro; @@ -279,6 +281,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); @@ -410,3 +414,12 @@ void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", "", DriverArgs, CC1Args); } + +SanitizerMask NetBSD::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + if (IsX86_64) { + Res |= SanitizerKind::Address; + } + return Res; +} diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h index d53aa6867872..412d0815e81a 100644 --- a/lib/Driver/ToolChains/NetBSD.h +++ b/lib/Driver/ToolChains/NetBSD.h @@ -66,6 +66,7 @@ public: llvm::opt::ArgStringList &CC1Args) const override; bool IsUnwindTablesDefault() const override { return true; } + SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildAssembler() const override; diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp index fcb6418b2517..058bc42323e2 100644 --- a/lib/Driver/ToolChains/WebAssembly.cpp +++ b/lib/Driver/ToolChains/WebAssembly.cpp @@ -134,7 +134,8 @@ bool WebAssembly::SupportsProfiling() const { return false; } bool WebAssembly::HasNativeLLVMSupport() const { return true; } void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fuse-init-array"); diff --git a/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h index ca42fc651a6d..2999db477f79 100644 --- a/lib/Driver/ToolChains/WebAssembly.h +++ b/lib/Driver/ToolChains/WebAssembly.h @@ -53,7 +53,8 @@ private: bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; RuntimeLibType GetDefaultRuntimeLibType() const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs( diff --git a/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp index c3ae9582124f..43175ad7d632 100644 --- a/lib/Driver/ToolChains/XCore.cpp +++ b/lib/Driver/ToolChains/XCore.cpp @@ -124,7 +124,8 @@ void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); } diff --git a/lib/Driver/ToolChains/XCore.h b/lib/Driver/ToolChains/XCore.h index 4084b1cdec13..00c89bd15f78 100644 --- a/lib/Driver/ToolChains/XCore.h +++ b/lib/Driver/ToolChains/XCore.h @@ -67,7 +67,8 @@ public: AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 4197587a74c0..3bf1cd8f7c13 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -66,6 +66,16 @@ static bool startsNextParameter(const FormatToken &Current, !Style.BreakBeforeInheritanceComma)); } +static bool opensProtoMessageField(const FormatToken &LessTok, + const FormatStyle &Style) { + if (LessTok.isNot(tok::less)) + return false; + return Style.Language == FormatStyle::LK_TextProto || + (Style.Language == FormatStyle::LK_Proto && + (LessTok.NestingLevel > 0 || + (LessTok.Previous && LessTok.Previous->is(tok::equal)))); +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -94,6 +104,13 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, State.LowestLevelOnLine = 0; State.IgnoreStackForComparison = false; + if (Style.Language == FormatStyle::LK_TextProto) { + // We need this in order to deal with the bin packing of text fields at + // global scope. + State.Stack.back().AvoidBinPacking = true; + State.Stack.back().BreakBeforeParameter = true; + } + // The first token has already been indented and thus consumed. moveStateToNextToken(State, DryRun, /*Newline=*/false); return State; @@ -176,7 +193,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) || (Previous.is(TT_ArrayInitializerLSquare) && - Previous.ParameterCount > 1)) && + Previous.ParameterCount > 1) || + opensProtoMessageField(Previous, Style)) && Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous) + State.Column - 1 > getColumnLimit(State)) @@ -501,13 +519,6 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } } -static bool lessOpensProtoMessageField(const FormatToken &LessTok, - const LineState &State) { - assert(LessTok.is(tok::less)); - return LessTok.NestingLevel > 0 || - (LessTok.Previous && LessTok.Previous->is(tok::equal)); -} - unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; @@ -650,9 +661,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && - PreviousNonComment->is(tok::less) && - lessOpensProtoMessageField(*PreviousNonComment, State)) || + opensProtoMessageField(*PreviousNonComment, Style) || (PreviousNonComment->is(TT_TemplateString) && PreviousNonComment->opensScope()))) State.Stack.back().BreakBeforeClosingBrace = true; @@ -695,7 +704,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; if ((Current.isOneOf(tok::r_brace, tok::r_square) || - (Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) && + (Current.is(tok::greater) && + (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto))) && State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; @@ -1050,8 +1061,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) && - lessOpensProtoMessageField(Current, State))) { + opensProtoMessageField(Current, Style)) { if (Current.opensBlockOrBlockTypeList(Style)) { NewIndent = Style.IndentWidth + std::min(State.Column, State.Stack.back().NestedBlockIndent); @@ -1064,7 +1074,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.MatchingParen->Previous->is(tok::comma); AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) || - Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto || + !Style.BinPackArguments || (NextNoComment && NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, TT_DesignatedInitializerLSquare)); diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index bb6781d79517..aa4ed8c42a70 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -56,6 +56,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); + IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); } }; @@ -631,6 +632,12 @@ FormatStyle getLLVMStyle() { } FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { + if (Language == FormatStyle::LK_TextProto) { + FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto); + GoogleStyle.Language = FormatStyle::LK_TextProto; + return GoogleStyle; + } + FormatStyle GoogleStyle = getLLVMStyle(); GoogleStyle.Language = Language; diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 0fe91adcd472..a60361a8e5fa 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -21,6 +21,7 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include <memory> +#include <unordered_set> namespace clang { namespace format { @@ -466,7 +467,8 @@ struct FormatToken { (is(tok::l_brace) && (BlockKind == BK_Block || is(TT_DictLiteral) || (!Style.Cpp11BracedListStyle && NestingLevel == 0))) || - (is(tok::less) && Style.Language == FormatStyle::LK_Proto); + (is(tok::less) && (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto)); } /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. @@ -639,6 +641,7 @@ struct AdditionalKeywords { kw_is = &IdentTable.get("is"); kw_let = &IdentTable.get("let"); kw_module = &IdentTable.get("module"); + kw_readonly = &IdentTable.get("readonly"); kw_set = &IdentTable.get("set"); kw_type = &IdentTable.get("type"); kw_var = &IdentTable.get("var"); @@ -671,6 +674,15 @@ struct AdditionalKeywords { kw_qsignals = &IdentTable.get("Q_SIGNALS"); kw_slots = &IdentTable.get("slots"); kw_qslots = &IdentTable.get("Q_SLOTS"); + + // Keep this at the end of the constructor to make sure everything here is + // already initialized. + JsExtraKeywords = std::unordered_set<IdentifierInfo *>( + {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, + kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, + kw_set, kw_type, kw_var, kw_yield, + // Keywords from the Java section. + kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); } // Context sensitive keywords. @@ -699,6 +711,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_is; IdentifierInfo *kw_let; IdentifierInfo *kw_module; + IdentifierInfo *kw_readonly; IdentifierInfo *kw_set; IdentifierInfo *kw_type; IdentifierInfo *kw_var; @@ -732,6 +745,18 @@ struct AdditionalKeywords { IdentifierInfo *kw_qsignals; IdentifierInfo *kw_slots; IdentifierInfo *kw_qslots; + + /// \brief Returns \c true if \p Tok is a true JavaScript identifier, returns + /// \c false if it is a keyword or a pseudo keyword. + bool IsJavaScriptIdentifier(const FormatToken &Tok) const { + return Tok.is(tok::identifier) && + JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == + JsExtraKeywords.end(); + } + +private: + /// \brief The JavaScript keywords beyond the C++ keyword set. + std::unordered_set<IdentifierInfo *> JsExtraKeywords; }; } // namespace format diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d78a37532fe8..c6e90a9175e1 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -90,7 +90,8 @@ private: } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - Style.Language != FormatStyle::LK_Proto)) + Style.Language != FormatStyle::LK_Proto && + Style.Language != FormatStyle::LK_TextProto)) return false; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the @@ -453,7 +454,8 @@ private: FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || - Style.Language == FormatStyle::LK_Proto) && + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal))) Previous->Type = TT_SelectorName; @@ -536,8 +538,13 @@ private: } } if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto) { + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { Tok->Type = TT_DictLiteral; + if (Style.Language == FormatStyle::LK_TextProto) { + if (FormatToken *Previous = Tok->getPreviousNonComment()) + Previous->Type = TT_SelectorName; + } } else if (Contexts.back().ColonIsObjCMethodExpr || Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; @@ -635,12 +642,22 @@ private: return false; break; case tok::l_brace: + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous =Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } if (!parseBrace()) return false; break; case tok::less: if (parseAngle()) { Tok->Type = TT_TemplateOpener; + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous = Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } } else { Tok->Type = TT_BinaryOperator; NonTemplateLess.insert(Tok); @@ -1572,7 +1589,8 @@ private: return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && (NextNonComment->is(TT_DictLiteral) || - (Style.Language == FormatStyle::LK_Proto && + ((Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) @@ -1676,17 +1694,26 @@ void TokenAnnotator::setCommentLineLevels( for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); I != E; ++I) { - bool CommentLine = (*I)->First; + bool CommentLine = true; for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; } } - if (NextNonCommentLine && CommentLine) - (*I)->Level = NextNonCommentLine->Level; - else + + if (NextNonCommentLine && CommentLine) { + // If the comment is currently aligned with the line immediately following + // it, that's probably intentional and we should keep it. + bool AlignedWithNextLine = + NextNonCommentLine->First->NewlinesBefore <= 1 && + NextNonCommentLine->First->OriginalColumn == + (*I)->First->OriginalColumn; + if (AlignedWithNextLine) + (*I)->Level = NextNonCommentLine->Level; + } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; + } setCommentLineLevels((*I)->Children); } @@ -2274,7 +2301,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Style.isCpp()) { if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); - } else if (Style.Language == FormatStyle::LK_Proto) { + } else if (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, Keywords.kw_repeated, Keywords.kw_extend)) @@ -2282,6 +2310,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(tok::l_paren) && Left.isOneOf(Keywords.kw_returns, Keywords.kw_option)) return true; + if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName)) + return true; } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; @@ -2300,7 +2330,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return false; - if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + // In tagged template literals ("html`bar baz`"), there is no space between + // the tag identifier and the template string. getIdentifierInfo makes sure + // that the identifier is not a pseudo keyword like `yield`, either. + if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) && + Right.is(TT_TemplateString)) return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) @@ -2604,11 +2638,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && - NonComment->isOneOf( - tok::kw_return, tok::kw_continue, tok::kw_break, tok::kw_throw, - Keywords.kw_interface, Keywords.kw_type, tok::kw_static, - tok::kw_public, tok::kw_private, tok::kw_protected, - Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set)) + NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break, + tok::kw_throw, Keywords.kw_interface, + Keywords.kw_type, tok::kw_static, tok::kw_public, + tok::kw_private, tok::kw_protected, + Keywords.kw_readonly, Keywords.kw_abstract, + Keywords.kw_get, Keywords.kw_set)) return false; // Otherwise automatic semicolon insertion would trigger. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index ba3a4c17ee12..4b57919d1929 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -286,7 +286,10 @@ void UnwrappedLineParser::parseFile() { !Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript; ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - parseLevel(/*HasOpeningBrace=*/false); + if (Style.Language == FormatStyle::LK_TextProto) + parseBracedList(); + else + parseLevel(/*HasOpeningBrace=*/false); // Make sure to format the remaining tokens. flushComments(true); addUnwrappedLine(); @@ -832,6 +835,7 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::at: nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); break; } @@ -996,8 +1000,10 @@ void UnwrappedLineParser::parseStructuralElement() { switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_enum: // Ignore if this is part of "template <enum ...". @@ -1176,12 +1182,15 @@ void UnwrappedLineParser::parseStructuralElement() { } nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); - else if (Style.Language == FormatStyle::LK_Proto && - FormatTok->Tok.is(tok::less)) + } else if (Style.Language == FormatStyle::LK_Proto && + FormatTok->Tok.is(tok::less)) { + nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*ClosingBraceKind=*/tok::greater); + } break; case tok::l_square: parseSquare(); @@ -1345,6 +1354,7 @@ bool UnwrappedLineParser::tryToParseBracedList() { assert(FormatTok->BlockKind != BK_Unknown); if (FormatTok->BlockKind == BK_Block) return false; + nextToken(); parseBracedList(); return true; } @@ -1352,7 +1362,6 @@ bool UnwrappedLineParser::tryToParseBracedList() { bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, tok::TokenKind ClosingBraceKind) { bool HasError = false; - nextToken(); // FIXME: Once we have an expression parser in the UnwrappedLineParser, // replace this by using parseAssigmentExpression() inside. @@ -1407,6 +1416,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, // Assume there are no blocks inside a braced init list apart // from the ones we explicitly parse out (like lambdas). FormatTok->BlockKind = BK_BracedInit; + nextToken(); parseBracedList(); break; case tok::semi: @@ -1459,8 +1469,10 @@ void UnwrappedLineParser::parseParens() { break; case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_class: if (Style.Language == FormatStyle::LK_JavaScript) @@ -1508,8 +1520,10 @@ void UnwrappedLineParser::parseSquare() { } case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; default: nextToken(); @@ -1836,6 +1850,7 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. + nextToken(); bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true); if (HasError) { if (FormatTok->is(tok::semi)) @@ -1870,6 +1885,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { FormatTok = Tokens->setPosition(StoredPosition); if (IsSimple) { + nextToken(); parseBracedList(); addUnwrappedLine(); return; @@ -2081,6 +2097,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { } if (FormatTok->is(tok::l_brace)) { FormatTok->BlockKind = BK_Block; + nextToken(); parseBracedList(); } else { nextToken(); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 0fbcc1c7399e..d42400183a43 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -163,6 +163,16 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } +bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( + CompilerInstance &CI) { + if (!CI.getLangOpts().Modules) { + CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules); + return false; + } + + return GenerateModuleAction::BeginSourceFileAction(CI); +} + std::unique_ptr<raw_pwrite_stream> GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 83290a6fbc28..38be684cec86 100644 --- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -146,7 +146,7 @@ namespace { llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; llvm::DenseMap<ObjCInterfaceDecl *, - llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars; + llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars; // ivar bitfield grouping containers llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups; @@ -1013,7 +1013,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, Setr = "\nextern \"C\" __declspec(dllimport) " "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; } - + RewriteObjCMethodDecl(OID->getContainingInterface(), PD->getSetterMethodDecl(), Setr); Setr += "{ "; @@ -3965,10 +3965,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, std::string &Result) { // write out ivar offset symbols which have been referenced in an ivar // access expression. - llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + if (Ivars.empty()) return; - + llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput; for (ObjCIvarDecl *IvarDecl : Ivars) { const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface(); @@ -6068,7 +6069,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp index 7d809c610c86..5a1e001d65b8 100644 --- a/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -5052,7 +5052,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { diff --git a/lib/Frontend/SerializedDiagnosticReader.cpp b/lib/Frontend/SerializedDiagnosticReader.cpp index 8a8161488f44..08b7087fbad6 100644 --- a/lib/Frontend/SerializedDiagnosticReader.cpp +++ b/lib/Frontend/SerializedDiagnosticReader.cpp @@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { llvm::BitstreamCursor Stream(**Buffer); Optional<llvm::BitstreamBlockInfo> BlockInfo; + if (Stream.AtEndOfStream()) + return SDError::InvalidSignature; + // Sniff for the signature. if (Stream.Read(8) != 'D' || Stream.Read(8) != 'I' || diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 1e12ea5e597a..6a72b00c602b 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -1052,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R, std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); } -static std::string buildFixItInsertionLine(unsigned LineNo, +static std::string buildFixItInsertionLine(FileID FID, + unsigned LineNo, const SourceColumnMap &map, ArrayRef<FixItHint> Hints, const SourceManager &SM, @@ -1069,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo, // code contains no newlines and is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + if (FID == HintLocInfo.first && + LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { // Insert the new code into the line just below the code // that the user wrote. @@ -1105,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo, PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert); - } else { - FixItInsertionLine.clear(); - break; } } } @@ -1222,7 +1221,7 @@ void TextDiagnostic::emitSnippetAndCaret( } std::string FixItInsertionLine = buildFixItInsertionLine( - LineNo, sourceColMap, Hints, SM, DiagOpts.get()); + FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get()); // If the source line is too long for our terminal, select only the // "interesting" source region within that line. diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h index 361e5f720ea1..e812a1632b91 100644 --- a/lib/Headers/bmiintrin.h +++ b/lib/Headers/bmiintrin.h @@ -318,7 +318,7 @@ __blsi_u64(unsigned long long __X) /// /// \param __X /// An unsigned 64-bit integer used to create the mask. -/// \returns A unsigned 64-bit integer containing the newly created mask. +/// \returns An unsigned 64-bit integer containing the newly created mask. static __inline__ unsigned long long __DEFAULT_FN_ATTRS __blsmsk_u64(unsigned long long __X) { diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h index 400dcfacd552..2dd0add236b8 100644 --- a/lib/Headers/cpuid.h +++ b/lib/Headers/cpuid.h @@ -79,7 +79,7 @@ #define signature_VORTEX_edx 0x36387865 #define signature_VORTEX_ecx 0x436f5320 -/* Features in %ecx for level 1 */ +/* Features in %ecx for leaf 1 */ #define bit_SSE3 0x00000001 #define bit_PCLMULQDQ 0x00000002 #define bit_PCLMUL bit_PCLMULQDQ /* for gcc compat */ @@ -114,7 +114,7 @@ #define bit_F16C 0x20000000 #define bit_RDRND 0x40000000 -/* Features in %edx for level 1 */ +/* Features in %edx for leaf 1 */ #define bit_FPU 0x00000001 #define bit_VME 0x00000002 #define bit_DE 0x00000004 @@ -147,44 +147,95 @@ #define bit_TM 0x20000000 #define bit_PBE 0x80000000 -/* Features in %ebx for level 7 sub-leaf 0 */ +/* Features in %ebx for leaf 7 sub-leaf 0 */ #define bit_FSGSBASE 0x00000001 +#define bit_SGX 0x00000004 +#define bit_BMI 0x00000008 +#define bit_HLE 0x00000010 +#define bit_AVX2 0x00000020 #define bit_SMEP 0x00000080 +#define bit_BMI2 0x00000100 #define bit_ENH_MOVSB 0x00000200 +#define bit_RTM 0x00000800 +#define bit_MPX 0x00004000 +#define bit_AVX512F 0x00010000 +#define bit_AVX512DQ 0x00020000 +#define bit_RDSEED 0x00040000 +#define bit_ADX 0x00080000 +#define bit_AVX512IFMA 0x00200000 +#define bit_CLFLUSHOPT 0x00800000 +#define bit_CLWB 0x01000000 +#define bit_AVX512PF 0x04000000 +#define bit_AVX51SER 0x08000000 +#define bit_AVX512CD 0x10000000 +#define bit_SHA 0x20000000 +#define bit_AVX512BW 0x40000000 +#define bit_AVX512VL 0x80000000 + +/* Features in %ecx for leaf 7 sub-leaf 0 */ +#define bit_PREFTCHWT1 0x00000001 +#define bit_AVX512VBMI 0x00000002 +#define bit_PKU 0x00000004 +#define bit_OSPKE 0x00000010 +#define bit_AVX512VPOPCNTDQ 0x00004000 +#define bit_RDPID 0x00400000 + +/* Features in %edx for leaf 7 sub-leaf 0 */ +#define bit_AVX5124VNNIW 0x00000004 +#define bit_AVX5124FMAPS 0x00000008 + +/* Features in %eax for leaf 13 sub-leaf 1 */ +#define bit_XSAVEOPT 0x00000001 +#define bit_XSAVEC 0x00000002 +#define bit_XSAVES 0x00000008 + +/* Features in %ecx for leaf 0x80000001 */ +#define bit_LAHF_LM 0x00000001 +#define bit_ABM 0x00000020 +#define bit_SSE4a 0x00000040 +#define bit_PRFCHW 0x00000100 +#define bit_XOP 0x00000800 +#define bit_LWP 0x00008000 +#define bit_FMA4 0x00010000 +#define bit_TBM 0x00200000 +#define bit_MWAITX 0x20000000 + +/* Features in %edx for leaf 0x80000001 */ +#define bit_MMXEXT 0x00400000 +#define bit_LM 0x20000000 +#define bit_3DNOWP 0x40000000 +#define bit_3DNOW 0x80000000 + +/* Features in %ebx for leaf 0x80000001 */ +#define bit_CLZERO 0x00000001 + #if __i386__ -#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ +#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level)) + : "0"(__leaf)) -#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ +#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level), "2"(__count)) + : "0"(__leaf), "2"(__count)) #else /* x86-64 uses %rbx as the base register, so preserve it. */ -#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ +#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \ __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level)) + : "0"(__leaf)) -#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ +#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level), "2"(__count)) + : "0"(__leaf), "2"(__count)) #endif -static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax, - unsigned int *__ebx, unsigned int *__ecx, - unsigned int *__edx) { - __cpuid(__level, *__eax, *__ebx, *__ecx, *__edx); - return 1; -} - -static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig) +static __inline int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig) { unsigned int __eax, __ebx, __ecx, __edx; #if __i386__ @@ -208,8 +259,35 @@ static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig) return 0; #endif - __cpuid(__level, __eax, __ebx, __ecx, __edx); + __cpuid(__leaf, __eax, __ebx, __ecx, __edx); if (__sig) *__sig = __ebx; return __eax; } + +static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax, + unsigned int *__ebx, unsigned int *__ecx, + unsigned int *__edx) +{ + unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0); + + if (__max_leaf == 0 || __max_leaf < __leaf) + return 0; + + __cpuid(__leaf, *__eax, *__ebx, *__ecx, *__edx); + return 1; +} + +static __inline int __get_cpuid_count (unsigned int __leaf, + unsigned int __subleaf, + unsigned int *__eax, unsigned int *__ebx, + unsigned int *__ecx, unsigned int *__edx) +{ + unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0); + + if (__max_leaf == 0 || __max_leaf < __leaf) + return 0; + + __cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx); + return 1; +} diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h index e22dd231427d..c5f25bfcb5c1 100644 --- a/lib/Headers/immintrin.h +++ b/lib/Headers/immintrin.h @@ -212,6 +212,15 @@ _rdrand32_step(unsigned int *__p) return __builtin_ia32_rdrand32_step(__p); } +#ifdef __x86_64__ +static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd"))) +_rdrand64_step(unsigned long long *__p) +{ + return __builtin_ia32_rdrand64_step(__p); +} +#endif +#endif /* __RDRND__ */ + /* __bit_scan_forward */ static __inline__ int __attribute__((__always_inline__, __nodebug__)) _bit_scan_forward(int __A) { @@ -224,15 +233,6 @@ _bit_scan_reverse(int __A) { return 31 - __builtin_clz(__A); } -#ifdef __x86_64__ -static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd"))) -_rdrand64_step(unsigned long long *__p) -{ - return __builtin_ia32_rdrand64_step(__p); -} -#endif -#endif /* __RDRND__ */ - #if !defined(_MSC_VER) || __has_feature(modules) || defined(__FSGSBASE__) #ifdef __x86_64__ static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __target__("fsgsbase"))) diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h index 5a7968bec842..4b38d51713d8 100644 --- a/lib/Headers/mmintrin.h +++ b/lib/Headers/mmintrin.h @@ -1289,7 +1289,7 @@ _mm_cmpgt_pi32(__m64 __m1, __m64 __m2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the the <c> VXORPS / XORPS </c> instruction. +/// This intrinsic corresponds to the <c> VXORPS / XORPS </c> instruction. /// /// \returns An initialized 64-bit integer vector with all elements set to zero. static __inline__ __m64 __DEFAULT_FN_ATTRS diff --git a/lib/Index/IndexBody.cpp b/lib/Index/IndexBody.cpp index d3632b8b9b15..6bbd38102509 100644 --- a/lib/Index/IndexBody.cpp +++ b/lib/Index/IndexBody.cpp @@ -230,7 +230,31 @@ public: SmallVector<SymbolRelation, 2> Relations; addCallRole(Roles, Relations); Stmt *Containing = getParentStmt(); - if (E->isImplicit() || (Containing && isa<PseudoObjectExpr>(Containing))) + + auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool { + const auto *E = POE->getSyntacticForm(); + if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) + E = BinOp->getLHS(); + const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E); + if (!PRE) + return false; + if (PRE->isExplicitProperty()) + return false; + if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) { + // Class properties that are explicitly defined using @property + // declarations are represented implicitly as there is no ivar for + // class properties. + if (Getter->isClassMethod() && + Getter->getCanonicalDecl()->findPropertyDecl()) + return false; + } + return true; + }; + bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing); + // Implicit property message sends are not 'implicit'. + if ((E->isImplicit() || IsPropCall) && + !(IsPropCall && + IsImplicitProperty(cast<PseudoObjectExpr>(Containing)))) Roles |= (unsigned)SymbolRole::Implicit; if (isDynamic(E)) { diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index d1127722c8ca..c5230c0f9acf 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -618,6 +618,8 @@ public: Template.is<ClassTemplateDecl *>() ? (Decl *)Template.get<ClassTemplateDecl *>() : Template.get<ClassTemplatePartialSpecializationDecl *>(); + if (!D->isThisDeclarationADefinition()) + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); IndexCtx.indexTagDecl( D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), SpecializationOf)); diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index bf358a372149..0dc3720208ca 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -69,11 +69,13 @@ bool index::isFunctionLocalSymbol(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { switch (ND->getFormalLinkage()) { case NoLinkage: - case VisibleNoLinkage: case InternalLinkage: return true; + case VisibleNoLinkage: case UniqueExternalLinkage: + case ModuleInternalLinkage: llvm_unreachable("Not a sema linkage"); + case ModuleLinkage: case ExternalLinkage: return false; } diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp index 754bc84ff4b2..c4aa51d62f02 100644 --- a/lib/Index/IndexingContext.cpp +++ b/lib/Index/IndexingContext.cpp @@ -229,6 +229,12 @@ static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, AST return false; } +/// Whether the given NamedDecl should be skipped because it has no name. +static bool shouldSkipNamelessDecl(const NamedDecl *ND) { + return ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && + !isa<ObjCCategoryDecl>(ND); +} + static const Decl *adjustParent(const Decl *Parent) { if (!Parent) return nullptr; @@ -243,8 +249,8 @@ static const Decl *adjustParent(const Decl *Parent) { } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { if (RD->isAnonymousStructOrUnion()) continue; - } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { - if (FD->getDeclName().isEmpty()) + } else if (auto ND = dyn_cast<NamedDecl>(Parent)) { + if (shouldSkipNamelessDecl(ND)) continue; } return Parent; @@ -315,9 +321,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, const DeclContext *ContainerDC) { if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) return true; - if (!isa<NamedDecl>(D) || - (cast<NamedDecl>(D)->getDeclName().isEmpty() && - !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) + if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D))) return true; SourceManager &SM = Ctx->getSourceManager(); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 012189aa6f9f..61bcef8cb760 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -2550,7 +2550,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { return true; } - if (PP->isRecordingPreamble() && !PP->isInMainFile()) { + if (PP->isRecordingPreamble() && PP->isInPrimaryFile()) { PP->setRecordedPreambleConditionalStack(ConditionalStack); ConditionalStack.clear(); } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 1c0cd5636835..5a589d6a17b3 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -46,12 +46,6 @@ bool Preprocessor::isInPrimaryFile() const { }); } -bool Preprocessor::isInMainFile() const { - if (IsFileLexer()) - return IncludeMacroStack.size() == 0; - return true; -} - /// getCurrentLexer - Return the current file lexer being lexed from. Note /// that this ignores any potentially active macro expansions and _Pragma /// expansions going on at the time. diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index f9a399cd7fd7..63f39524d12a 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -535,7 +535,9 @@ void Preprocessor::EnterMainSourceFile() { // Start parsing the predefines. EnterSourceFile(FID, nullptr, SourceLocation()); +} +void Preprocessor::replayPreambleConditionalStack() { // Restore the conditional stack from the preamble, if there is one. if (PreambleConditionalStack.isReplaying()) { CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack()); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index cc1e8850a523..b68559485a5e 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -889,7 +889,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { // If the opening brace is not preceded by one of these tokens, we are // missing the mem-initializer-id. In order to recover better, we need // to use heuristics to determine if this '{' is most likely the - // begining of a brace-init-list or the function body. + // beginning of a brace-init-list or the function body. // Check the token after the corresponding '}'. TentativeParsingAction PA(*this); if (SkipUntil(tok::r_brace) && diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 07054546f42f..a4610698c46d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6650,7 +6650,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } - // If we get here, the operand to the typeof was an expresion. + // If we get here, the operand to the typeof was an expression. if (Operand.isInvalid()) { DS.SetTypeSpecError(); return; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index aacb00e8be64..44b87af01abd 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1866,7 +1866,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, } } - // If we get here, the operand to the typeof/sizeof/alignof was an expresion. + // If we get here, the operand to the typeof/sizeof/alignof was an expression. isCastExpr = false; return Operand; } @@ -1972,7 +1972,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo(); - // If we get here, the operand to the sizeof/alignof was an expresion. + // If we get here, the operand to the sizeof/alignof was an expression. if (!Operand.isInvalid()) Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index caa6323d3209..f7410b8a092a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2255,7 +2255,7 @@ Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { assert(!Finished); - P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); + P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin()); for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i], true/*Methods*/); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index af29b5e9c673..4aa9a5971929 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -516,6 +516,8 @@ void Parser::Initialize() { // Prime the lexer look-ahead. ConsumeToken(); + + PP.replayPreambleConditionalStack(); } void Parser::LateTemplateParserCleanupCallback(void *P) { @@ -526,6 +528,8 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { } bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { + Actions.ActOnStartOfTranslationUnit(); + // C11 6.9p1 says translation units must have at least one top-level // declaration. C++ doesn't have this restriction. We also don't want to // complain if we have a precompiled header, although technically if the PCH diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index fd2d07957c2b..f83baa790b49 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -394,15 +394,21 @@ static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD) { - if (!S.getSourceManager().isInSystemHeader(OpLoc)) { + if (!S.getSourceManager().isInSystemHeader(OpLoc) && + FD->getTypeSourceInfo()) { S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; if (S.getLangOpts().CPlusPlus11 && (isa<CXXDestructorDecl>(FD) || FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || - FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) - S.Diag(FD->getLocation(), diag::note_throw_in_dtor); - else - S.Diag(FD->getLocation(), diag::note_throw_in_function); + FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { + if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> + getAs<FunctionProtoType>()) + S.Diag(FD->getLocation(), diag::note_throw_in_dtor) + << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() + << FD->getExceptionSpecSourceRange(); + } else + S.Diag(FD->getLocation(), diag::note_throw_in_function) + << FD->getExceptionSpecSourceRange(); } } @@ -420,8 +426,7 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (FPT->getExceptionSpecType() != EST_None && - FPT->isNothrow(FD->getASTContext())) + if (FPT->isNothrow(FD->getASTContext())) return true; return false; } diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index 2fa5718d4e9b..3d321d561e60 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -22,7 +22,8 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeAvailability(AvailabilityResult AR, SourceLocation Loc, - const NamedDecl *D, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, @@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR, DD.Kind = Availability; DD.Triggered = false; DD.Loc = Loc; - DD.AvailabilityData.Decl = D; + DD.AvailabilityData.ReferringDecl = ReferringDecl; + DD.AvailabilityData.OffendingDecl = OffendingDecl; DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 34f5e26be810..dc9f977d41ac 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -705,6 +705,18 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() { UnusedLocalTypedefNameCandidates.clear(); } +/// This is called before the very first declaration in the translation unit +/// is parsed. Note that the ASTContext may have already injected some +/// declarations. +void Sema::ActOnStartOfTranslationUnit() { + if (getLangOpts().ModulesTS) { + // We start in the global module; all those declarations are implicitly + // module-private (though they do not have module linkage). + Context.getTranslationUnitDecl()->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ModulePrivate); + } +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 7d534263f468..ba2049d8a606 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -143,6 +143,9 @@ namespace { }; } +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType); + // The Try functions attempt a specific way of casting. If they succeed, they // return TC_Success. If their way of casting is not appropriate for the given // arguments, they return TC_NotApplicable and *may* set diag to a diagnostic @@ -427,6 +430,10 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, /// the same kind of pointer (plain or to-member). Unlike the Sema function, /// this one doesn't care if the two pointers-to-member don't point into the /// same class. This is because CastsAwayConstness doesn't care. +/// And additionally, it handles C++ references. If both the types are +/// references, then their pointee types are returned, +/// else if only one of them is reference, it's pointee type is returned, +/// and the other type is returned as-is. static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { const PointerType *T1PtrType = T1->getAs<PointerType>(), *T2PtrType = T2->getAs<PointerType>(); @@ -475,6 +482,26 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { return true; } + const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(), + *T2RefType = T2->getAs<LValueReferenceType>(); + if (T1RefType && T2RefType) { + T1 = T1RefType->getPointeeType(); + T2 = T2RefType->getPointeeType(); + return true; + } + + if (T1RefType) { + T1 = T1RefType->getPointeeType(); + // T2 = T2; + return true; + } + + if (T2RefType) { + // T1 = T1; + T2 = T2RefType->getPointeeType(); + return true; + } + return false; } @@ -503,11 +530,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, // the rules are non-trivial. So first we construct Tcv *...cv* as described // in C++ 5.2.11p8. assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || - SrcType->isBlockPointerType()) && + SrcType->isBlockPointerType() || + DestType->isLValueReferenceType()) && "Source type is not pointer or pointer to member."); assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || - DestType->isBlockPointerType()) && - "Destination type is not pointer or pointer to member."); + DestType->isBlockPointerType() || + DestType->isLValueReferenceType()) && + "Destination type is not pointer or pointer to member, or reference."); QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); @@ -2177,6 +2206,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { + assert(Self.getLangOpts().CPlusPlus); + // Handle placeholders. if (isPlaceholder()) { // C-style casts can resolve __unknown_any types. @@ -2580,30 +2611,42 @@ void CastOperation::CheckCStyleCast() { if (Kind == CK_BitCast) checkCastAlign(); +} + +/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either +/// const, volatile or both. +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + if (SrcExpr.isInvalid()) + return; + + QualType SrcType = SrcExpr.get()->getType(); + if (!((SrcType->isAnyPointerType() && DestType->isAnyPointerType()) || + DestType->isLValueReferenceType())) + return; - // -Wcast-qual QualType TheOffendingSrcType, TheOffendingDestType; Qualifiers CastAwayQualifiers; - if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() && - CastsAwayConstness(Self, SrcType, DestType, true, false, - &TheOffendingSrcType, &TheOffendingDestType, - &CastAwayQualifiers)) { - int qualifiers = -1; - if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { - qualifiers = 0; - } else if (CastAwayQualifiers.hasConst()) { - qualifiers = 1; - } else if (CastAwayQualifiers.hasVolatile()) { - qualifiers = 2; - } - // This is a variant of int **x; const int **y = (const int **)x; - if (qualifiers == -1) - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) << - SrcType << DestType; - else - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) << - TheOffendingSrcType << TheOffendingDestType << qualifiers; - } + if (!CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers)) + return; + + int qualifiers = -1; + if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { + qualifiers = 0; + } else if (CastAwayQualifiers.hasConst()) { + qualifiers = 1; + } else if (CastAwayQualifiers.hasVolatile()) { + qualifiers = 2; + } + // This is a variant of int **x; const int **y = (const int **)x; + if (qualifiers == -1) + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) + << SrcType << DestType; + else + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) + << TheOffendingSrcType << TheOffendingDestType << qualifiers; } ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, @@ -2624,6 +2667,9 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, if (Op.SrcExpr.isInvalid()) return ExprError(); + // -Wcast-qual + DiagnoseCastQual(Op.Self, Op.SrcExpr, Op.DestType); + return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), &Op.BasePath, CastTypeInfo, LPLoc, RPLoc)); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 845c4bf61b7a..8446601334ee 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -309,7 +309,8 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { Expr *BlockArg = TheCall->getArg(0); if (!isBlockPointer(BlockArg)) { S.Diag(BlockArg->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) << "block"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } return checkOpenCLBlockArgs(S, BlockArg); @@ -394,24 +395,24 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // First argument always needs to be a queue_t type. if (!Arg0->getType()->isQueueT()) { S.Diag(TheCall->getArg(0)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << S.Context.OCLQueueTy; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.OCLQueueTy; return true; } // Second argument always needs to be a kernel_enqueue_flags_t enum value. if (!Arg1->getType()->isIntegerType()) { S.Diag(TheCall->getArg(1)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "'kernel_enqueue_flags_t' (i.e. uint)"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)"; return true; } // Third argument is always an ndrange_t type. if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") { S.Diag(TheCall->getArg(2)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "'ndrange_t'"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; return true; } @@ -420,8 +421,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { if (NumArgs == 4) { // check that the last argument is the right block type. if (!isBlockPointer(Arg3)) { - S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) - << "block"; + S.Diag(Arg3->getLocStart(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } // we have a block type, check the prototype @@ -443,8 +444,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // check common block argument. Expr *Arg6 = TheCall->getArg(6); if (!isBlockPointer(Arg6)) { - S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) - << "block"; + S.Diag(Arg6->getLocStart(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } if (checkOpenCLBlockArgs(S, Arg6)) @@ -453,8 +454,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // Forth argument has to be any integer type. if (!Arg3->getType()->isIntegerType()) { S.Diag(TheCall->getArg(3)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "integer"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "integer"; return true; } // check remaining common arguments. @@ -466,7 +467,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { Expr::NPC_ValueDependentIsNotNull) && !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { S.Diag(TheCall->getArg(4)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } @@ -477,7 +479,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { !(Arg5->getType()->isPointerType() && Arg5->getType()->getPointeeType()->isClkEventT())) { S.Diag(TheCall->getArg(5)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } @@ -12094,6 +12097,8 @@ void Sema::RefersToMemberWithReducedAlignment( if (ME->isArrow()) BaseType = BaseType->getPointeeType(); RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + if (RD->isInvalidDecl()) + return; ValueDecl *MD = ME->getMemberDecl(); auto *FD = dyn_cast<FieldDecl>(MD); diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index b05c0998d3dd..dc7d8e4e9cec 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -43,9 +43,10 @@ static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, /// Look up the std::coroutine_traits<...>::promise_type for the given /// function type. -static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, - SourceLocation KwLoc, - SourceLocation FuncLoc) { +static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, + SourceLocation KwLoc) { + const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>(); + const SourceLocation FuncLoc = FD->getLocation(); // FIXME: Cache std::coroutine_traits once we've found it. NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); if (!StdExp) { @@ -71,16 +72,35 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, return QualType(); } - // Form template argument list for coroutine_traits<R, P1, P2, ...>. + // Form template argument list for coroutine_traits<R, P1, P2, ...> according + // to [dcl.fct.def.coroutine]3 TemplateArgumentListInfo Args(KwLoc, KwLoc); - Args.addArgument(TemplateArgumentLoc( - TemplateArgument(FnType->getReturnType()), - S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc))); - // FIXME: If the function is a non-static member function, add the type - // of the implicit object parameter before the formal parameters. - for (QualType T : FnType->getParamTypes()) + auto AddArg = [&](QualType T) { Args.addArgument(TemplateArgumentLoc( TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc))); + }; + AddArg(FnType->getReturnType()); + // If the function is a non-static member function, add the type + // of the implicit object parameter before the formal parameters. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isInstance()) { + // [over.match.funcs]4 + // For non-static member functions, the type of the implicit object + // parameter is + // -- "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // -- "rvalue reference to cv X" for functions declared with the && + // ref-qualifier + QualType T = + MD->getThisType(S.Context)->getAs<PointerType>()->getPointeeType(); + T = FnType->getRefQualifier() == RQ_RValue + ? S.Context.getRValueReferenceType(T) + : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true); + AddArg(T); + } + } + for (QualType T : FnType->getParamTypes()) + AddArg(T); // Build the template-id. QualType CoroTrait = @@ -424,12 +444,16 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise, VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { assert(isa<FunctionDecl>(CurContext) && "not in a function scope"); auto *FD = cast<FunctionDecl>(CurContext); + bool IsThisDependentType = [&] { + if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD)) + return MD->isInstance() && MD->getThisType(Context)->isDependentType(); + else + return false; + }(); - QualType T = - FD->getType()->isDependentType() - ? Context.DependentTy - : lookupPromiseType(*this, FD->getType()->castAs<FunctionProtoType>(), - Loc, FD->getLocation()); + QualType T = FD->getType()->isDependentType() || IsThisDependentType + ? Context.DependentTy + : lookupPromiseType(*this, FD, Loc); if (T.isNull()) return nullptr; @@ -721,8 +745,6 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) { return nullptr; } - // FIXME: Mark the variable as ODR used. This currently does not work - // likely due to the scope at in which this function is called. auto *VD = Result.getAsSingle<VarDecl>(); if (!VD) { Result.suppressDiagnostics(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ef8a408f90de..31b24f91c1d9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1998,8 +1998,7 @@ static void filterNonConflictingPreviousTypedefDecls(Sema &S, // If both declarations give a tag declaration a typedef name for linkage // purposes, then they declare the same entity. - if (S.getLangOpts().CPlusPlus && - OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) && + if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) && Decl->getAnonDeclWithTypedefName()) continue; } @@ -2117,7 +2116,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true); auto *NewTag = New->getAnonDeclWithTypedefName(); NamedDecl *Hidden = nullptr; - if (getLangOpts().CPlusPlus && OldTag && NewTag && + if (OldTag && NewTag && OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() && !hasVisibleDefinition(OldTag, &Hidden)) { // There is a definition of this tag, but it is not visible. Use it @@ -16055,8 +16054,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, return nullptr; } - // FIXME: Create a ModuleDecl and return it. - // FIXME: Most of this work should be done by the preprocessor rather than // here, in order to support macro import. @@ -16070,6 +16067,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, ModuleName += Piece.first->getName(); } + // FIXME: If we've already seen a module-declaration, report an error. + // If a module name was explicitly specified on the command line, it must be // correct. if (!getLangOpts().CurrentModule.empty() && @@ -16082,6 +16081,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *Mod; switch (MDK) { case ModuleDeclKind::Module: { @@ -16100,12 +16100,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, } // Create a Module for the module that we're defining. - Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); assert(Mod && "module creation should not fail"); - - // Enter the semantic scope of the module. - ActOnModuleBegin(ModuleLoc, Mod); - return nullptr; + break; } case ModuleDeclKind::Partition: @@ -16115,14 +16112,26 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, case ModuleDeclKind::Implementation: std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( PP.getIdentifierInfo(ModuleName), Path[0].second); - - DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc); - if (Import.isInvalid()) + Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible, + /*IsIncludeDirective=*/false); + if (!Mod) return nullptr; - return ConvertDeclToDeclGroup(Import.get()); + break; } - llvm_unreachable("unexpected module decl kind"); + // Enter the semantic scope of the module. + ModuleScopes.push_back({}); + ModuleScopes.back().Module = Mod; + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + VisibleModules.setVisible(Mod, ModuleLoc); + + // From now on, we have an owning module for all declarations we see. + // However, those declarations are module-private unless explicitly + // exported. + Context.getTranslationUnitDecl()->setLocalOwningModule(Mod); + + // FIXME: Create a ModuleDecl. + return nullptr; } DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, @@ -16311,6 +16320,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, CurContext->addDecl(D); PushDeclContext(S, D); + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); return D; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1929bc539188..5fb79a6bf630 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -6929,8 +6929,34 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, DeclVersion >= ForceAvailabilityFromVersion; } +static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { + for (Decl *Ctx = OrigCtx; Ctx; + Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) { + if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx)) + return cast<NamedDecl>(Ctx); + if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) { + if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx)) + return Imp->getClassInterface(); + return CD; + } + } + + return dyn_cast<NamedDecl>(OrigCtx); +} + +/// Actually emit an availability diagnostic for a reference to an unavailable +/// decl. +/// +/// \param Ctx The context that the reference occurred in +/// \param ReferringDecl The exact declaration that was referenced. +/// \param OffendingDecl A related decl to \c ReferringDecl that has an +/// availability attribute corrisponding to \c K attached to it. Note that this +/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and +/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl +/// and OffendingDecl is the EnumDecl. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, - Decl *Ctx, const NamedDecl *D, + Decl *Ctx, const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, @@ -6938,7 +6964,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; unsigned diag_available_here = diag::note_availability_specified_here; - SourceLocation NoteLocation = D->getLocation(); + SourceLocation NoteLocation = OffendingDecl->getLocation(); // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -6947,7 +6973,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, unsigned available_here_select_kind; VersionTuple DeclVersion; - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D)) + if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) DeclVersion = AA->getIntroduced(); if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) @@ -6961,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *attr = D->getAttr<DeprecatedAttr>()) + if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>()) NoteLocation = attr->getLocation(); break; @@ -6973,13 +6999,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto attr = D->getAttr<UnavailableAttr>()) { + if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) { if (attr->isImplicit() && attr->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { if (S.getLangOpts().ObjCAutoRefCount && - S.getSourceManager().isInSystemHeader(D->getLocation())) + S.getSourceManager().isInSystemHeader( + OffendingDecl->getLocation())) diag = diag::err_unavailable_in_arc; }; @@ -7022,7 +7049,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or // later. - const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D); + const AvailabilityAttr *AA = + getAttrForPlatform(S.getASTContext(), OffendingDecl); VersionTuple Introduced = AA->getIntroduced(); bool NewWarning = shouldDiagnoseAvailabilityByDefault( S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), @@ -7045,9 +7073,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, CharSourceRange UseRange; StringRef Replacement; if (K == AR_Deprecated) { - if (auto attr = D->getAttr<DeprecatedAttr>()) + if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>()) Replacement = attr->getReplacement(); - if (auto attr = getAttrForPlatform(S.Context, D)) + if (auto attr = getAttrForPlatform(S.Context, OffendingDecl)) Replacement = attr->getReplacement(); if (!Replacement.empty()) @@ -7056,21 +7084,21 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } if (!Message.empty()) { - S.Diag(Loc, diag_message) << D << Message + S.Diag(Loc, diag_message) << ReferringDecl << Message << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << D + S.Diag(Loc, diag) << ReferringDecl << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << D + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); @@ -7078,16 +7106,16 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // The declaration can have multiple availability attributes, we are looking // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, D); + const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); if (A && A->isInherited()) { - for (const Decl *Redecl = D->getMostRecentDecl(); Redecl; + for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; Redecl = Redecl->getPreviousDecl()) { const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, Redecl); if (AForRedecl && !AForRedecl->isInherited()) { // If D is a declaration with inherited attributes, the note should // point to the declaration with actual attributes. - S.Diag(Redecl->getLocation(), diag_available_here) << D + S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl << available_here_select_kind; break; } @@ -7095,10 +7123,19 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } else S.Diag(NoteLocation, diag_available_here) - << D << available_here_select_kind; + << OffendingDecl << available_here_select_kind; if (K == AR_NotYetIntroduced) - S.Diag(Loc, diag::note_partial_availability_silence) << D; + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { + if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (TD->getDeclName().isEmpty()) { + S.Diag(TD->getLocation(), diag::note_partial_availability_silence) + << /*Anonymous*/1 << TD->getKindName(); + return; + } + S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence) + << /*Named*/0 << Enclosing; + } } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, @@ -7108,9 +7145,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( - S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(), - DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(), - DD.getObjCProperty(), false); + S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, + DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7169,22 +7206,25 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { } void Sema::EmitAvailabilityWarning(AvailabilityResult AR, - NamedDecl *D, StringRef Message, - SourceLocation Loc, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, + StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { - DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( - AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, - ObjCPropertyAccess)); + DelayedDiagnostics.add( + DelayedDiagnostic::makeAvailability( + AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, - ObjCProperty, ObjCPropertyAccess); + DoEmitAvailabilityWarning(*this, AR, Ctx, ReferringDecl, OffendingDecl, + Message, Loc, UnknownObjCClass, ObjCProperty, + ObjCPropertyAccess); } namespace { @@ -7336,19 +7376,21 @@ public: void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( NamedDecl *D, SourceRange Range) { - - VersionTuple ContextVersion = AvailabilityStack.back(); - if (AvailabilityResult Result = - SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) { + AvailabilityResult Result; + const NamedDecl *OffendingDecl; + std::tie(Result, OffendingDecl) = + SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr); + if (Result != AR_Available) { // All other diagnostic kinds have already been handled in // DiagnoseAvailabilityOfDecl. if (Result != AR_NotYetIntroduced) return; - const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D); + const AvailabilityAttr *AA = + getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); VersionTuple Introduced = AA->getIntroduced(); - if (ContextVersion >= Introduced) + if (AvailabilityStack.back() >= Introduced) return; // If the context of this function is less available than D, we should not @@ -7373,8 +7415,9 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SemaRef.getASTContext().getTargetInfo().getPlatformName()) << Introduced.getAsString(); - SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here) - << D << /* partial */ 3; + SemaRef.Diag(OffendingDecl->getLocation(), + diag::note_availability_specified_here) + << OffendingDecl << /* partial */ 3; auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 2c8080dbf02b..778b8062f68c 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -458,7 +458,10 @@ static void diagnoseUseOfProtocols(Sema &TheSema, // Diagnose availability in the context of the ObjC container. Sema::ContextRAII SavedContext(TheSema, CD); for (unsigned i = 0; i < NumProtoRefs; ++i) { - (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]); + (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i], + /*UnknownObjCClass=*/nullptr, + /*ObjCPropertyAccess=*/false, + /*AvoidPartialAvailabilityChecks=*/true); } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f49df6b3216d..8016bf99889f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -87,24 +87,9 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { } } -static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { - const auto *OMD = dyn_cast<ObjCMethodDecl>(D); - if (!OMD) - return false; - const ObjCInterfaceDecl *OID = OMD->getClassInterface(); - if (!OID) - return false; - - for (const ObjCCategoryDecl *Cat : OID->visible_categories()) - if (ObjCMethodDecl *CatMeth = - Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) - if (!CatMeth->hasAttr<AvailabilityAttr>()) - return true; - return false; -} - -AvailabilityResult -Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { +std::pair<AvailabilityResult, const NamedDecl *> +Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, + std::string *Message) { AvailabilityResult Result = D->getAvailability(Message); // For typedefs, if the typedef declaration appears available look @@ -121,78 +106,61 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { } // Forward class declarations get their attributes from their definition. - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); Result = D->getAvailability(Message); } } - if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) + if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); - if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) + if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) { Result = TheEnumDecl->getAvailability(Message); + D = TheEnumDecl; + } } - if (Result == AR_NotYetIntroduced) { - // Don't do this for enums, they can't be redeclared. - if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) - return AR_Available; - - bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); - // Objective-C method declarations in categories are not modelled as - // redeclarations, so manually look for a redeclaration in a category - // if necessary. - if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) - Warn = false; - // In general, D will point to the most recent redeclaration. However, - // for `@class A;` decls, this isn't true -- manually go through the - // redecl chain in that case. - if (Warn && isa<ObjCInterfaceDecl>(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr<AvailabilityAttr>() || - Redecl->getAttr<AvailabilityAttr>()->isInherited()) - Warn = false; - - return Warn ? AR_NotYetIntroduced : AR_Available; - } - - return Result; + return {Result, D}; } static void DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks = false) { std::string Message; + AvailabilityResult Result; + const NamedDecl* OffendingDecl; // See if this declaration is unavailable, deprecated, or partial. - if (AvailabilityResult Result = - S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) { + std::tie(Result, OffendingDecl) = S.ShouldDiagnoseAvailabilityOfDecl(D, &Message); + if (Result == AR_Available) + return; - if (Result == AR_NotYetIntroduced) { - if (S.getCurFunctionOrMethodDecl()) { - S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; - return; - } else if (S.getCurBlock() || S.getCurLambda()) { - S.getCurFunction()->HasPotentialAvailabilityViolations = true; - return; - } + if (Result == AR_NotYetIntroduced) { + if (AvoidPartialAvailabilityChecks) + return; + if (S.getCurFunctionOrMethodDecl()) { + S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + return; + } else if (S.getCurBlock() || S.getCurLambda()) { + S.getCurFunction()->HasPotentialAvailabilityViolations = true; + return; } + } - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); - if (PDeclResult == Result) - ObjCPDecl = PD; - } + const ObjCPropertyDecl *ObjCPDecl = nullptr; + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { + AvailabilityResult PDeclResult = PD->getAvailability(nullptr); + if (PDeclResult == Result) + ObjCPDecl = PD; } - - S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, - ObjCPDecl, ObjCPropertyAccess); } + + S.EmitAvailabilityWarning(Result, D, OffendingDecl, Message, Loc, + UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } /// \brief Emit a note explaining that this function is deleted. @@ -310,7 +278,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks) { if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -395,7 +364,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, - ObjCPropertyAccess); + ObjCPropertyAccess, + AvoidPartialAvailabilityChecks); DiagnoseUnusedOfDecl(*this, D, Loc); @@ -14695,24 +14665,24 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, ME->performsVirtualDispatch(SemaRef.getLangOpts()); if (!IsVirtualCall) return; - const Expr *Base = ME->getBase(); - const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); - if (!MostDerivedClassDecl) - return; - CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); - if (!DM || DM->isPure()) - return; - SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); + + // If it's possible to devirtualize the call, mark the called function + // referenced. + CXXMethodDecl *DM = MD->getDevirtualizedMethod( + ME->getBase(), SemaRef.getLangOpts().AppleKext); + if (DM) + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. -void Sema::MarkDeclRefReferenced(DeclRefExpr *E) { +void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even // if it's a qualified reference. bool OdrUse = true; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) - if (Method->isVirtual()) + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) + if (Method->isVirtual() && + !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index b18de7e94686..c3d0e2db76b6 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1842,10 +1842,6 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, FoundDecl, Field); if (Base.isInvalid()) return ExprError(); - MemberExpr *ME = - BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, - /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, - MemberNameInfo, MemberType, VK, OK); // Build a reference to a private copy for non-static data members in // non-static member functions, privatized by OpenMP constructs. @@ -1855,7 +1851,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); } - return ME; + + return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, + /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, + MemberNameInfo, MemberType, VK, OK); } /// Builds an implicit member access expression. The current context diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index d6b70610d461..46f2ba376006 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1595,7 +1595,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ContainsUnexpandedParameterPack); // If the lambda expression's call operator is not explicitly marked constexpr // and we are not in a dependent context, analyze the call operator to infer - // its constexpr-ness, supressing diagnostics while doing so. + // its constexpr-ness, suppressing diagnostics while doing so. if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && !CallOperator->isConstexpr() && !isa<CoroutineBodyStmt>(CallOperator->getBody()) && diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 2e7fb875a276..85596ed52e9d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1395,6 +1395,20 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { return false; } +bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) { + // FIXME: When not in local visibility mode, we can't tell the difference + // between a declaration being visible because we merged a local copy of + // the same declaration into it, and it being visible because its owning + // module is visible. + if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible && + getLangOpts().ModulesLocalVisibility) + return true; + for (Module *Merged : Context.getModulesWithMergedDefinition(Def)) + if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule) + return true; + return false; +} + template<typename ParmDecl> static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D, @@ -1495,23 +1509,40 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(D->isHidden() && "should not call this: not in slow case"); Module *DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl not from a module"); - - // If the owning module is visible, and the decl is not module private, - // then the decl is visible too. (Module private is ignored within the same - // top-level module.) - // FIXME: Check the owning module for module-private declarations rather than - // assuming "same AST file" is the same thing as "same module". - if ((!D->isFromASTFile() || !D->isModulePrivate()) && - (SemaRef.isModuleVisible(DeclModule) || - SemaRef.hasVisibleMergedDefinition(D))) - return true; + if (!DeclModule) { + // A module-private declaration with no owning module means this is in the + // global module in the C++ Modules TS. This is visible within the same + // translation unit only. + // FIXME: Don't assume that "same translation unit" means the same thing + // as "not from an AST file". + assert(D->isModulePrivate() && "hidden decl has no module"); + if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D)) + return true; + } else { + // If the owning module is visible, and the decl is not module private, + // then the decl is visible too. (Module private is ignored within the same + // top-level module.) + if (D->isModulePrivate() + ? DeclModule->getTopLevelModuleName() == + SemaRef.getLangOpts().CurrentModule || + SemaRef.hasMergedDefinitionInCurrentModule(D) + : SemaRef.isModuleVisible(DeclModule) || + SemaRef.hasVisibleMergedDefinition(D)) + return true; + } + + // Determine whether a decl context is a file context for the purpose of + // visibility. This looks through some (export and linkage spec) transparent + // contexts, but not others (enums). + auto IsEffectivelyFileContext = [](const DeclContext *DC) { + return DC->isFileContext() || isa<LinkageSpecDecl>(DC) || + isa<ExportDecl>(DC); + }; - // If this declaration is not at namespace scope nor module-private, + // If this declaration is not at namespace scope // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); - if (!D->isModulePrivate() && DC && !DC->isFileContext() && - !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) { + if (DC && !IsEffectivelyFileContext(DC)) { // For a parameter, check whether our current template declaration's // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. @@ -1519,32 +1550,45 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // In C++ we need to check for a visible definition due to ODR merging, // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. - if ((D->isTemplateParameter() || isa<ParmVarDecl>(D) - || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) - ? isVisible(SemaRef, cast<NamedDecl>(DC)) - : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) { - if (SemaRef.CodeSynthesisContexts.empty() && - // FIXME: Do something better in this case. - !SemaRef.getLangOpts().ModulesLocalVisibility) { - // Cache the fact that this declaration is implicitly visible because - // its parent has a visible definition. - D->setVisibleDespiteOwningModule(); - } - return true; + bool VisibleWithinParent; + if (D->isTemplateParameter() || isa<ParmVarDecl>(D) || + (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); + else if (D->isModulePrivate()) { + // A module-private declaration is only visible if an enclosing lexical + // parent was merged with another definition in the current module. + VisibleWithinParent = false; + do { + if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) { + VisibleWithinParent = true; + break; + } + DC = DC->getLexicalParent(); + } while (!IsEffectivelyFileContext(DC)); + } else { + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); } - return false; + + if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() && + // FIXME: Do something better in this case. + !SemaRef.getLangOpts().ModulesLocalVisibility) { + // Cache the fact that this declaration is implicitly visible because + // its parent has a visible definition. + D->setVisibleDespiteOwningModule(); + } + return VisibleWithinParent; } + // FIXME: All uses of DeclModule below this point should also check merged + // modules. + if (!DeclModule) + return false; + // Find the extra places where we need to look. llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules(); if (LookupModules.empty()) return false; - if (!DeclModule) { - DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl not from a module"); - } - // If our lookup set contains the decl's module, it's visible. if (LookupModules.count(DeclModule)) return true; diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 6c5716454874..62a771bcffa0 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1676,8 +1676,9 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl, /// \brief Default synthesizes all properties which must be synthesized /// in class's \@implementation. -void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl) { +void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, + ObjCInterfaceDecl *IDecl, + SourceLocation AtEnd) { ObjCInterfaceDecl::PropertyMap PropMap; ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder; IDecl->collectPropertiesToImplement(PropMap, PropertyOrder); @@ -1725,6 +1726,10 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, diag::warn_auto_synthesizing_protocol_property) << Prop << Proto; Diag(Prop->getLocation(), diag::note_property_declare); + std::string FixIt = + (Twine("@synthesize ") + Prop->getName() + ";\n\n").str(); + Diag(AtEnd, diag::note_add_synthesize_directive) + << FixItHint::CreateInsertion(AtEnd, FixIt); } continue; } @@ -1764,7 +1769,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, } } -void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { +void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D, + SourceLocation AtEnd) { if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile()) return; ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D); @@ -1772,7 +1778,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { return; if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) if (!IDecl->isObjCRequiresPropertyDefs()) - DefaultSynthesizeProperties(S, IC, IDecl); + DefaultSynthesizeProperties(S, IC, IDecl, AtEnd); } static void DiagnoseUnimplementedAccessor( diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 49da0e499771..1e0b6c158348 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -6106,6 +6106,33 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, return ErrorFound; } +static bool checkReductionClauseWithNogroup(Sema &S, + ArrayRef<OMPClause *> Clauses) { + OMPClause *ReductionClause = nullptr; + OMPClause *NogroupClause = nullptr; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_reduction) { + ReductionClause = C; + if (NogroupClause) + break; + continue; + } + if (C->getClauseKind() == OMPC_nogroup) { + NogroupClause = C; + if (ReductionClause) + break; + continue; + } + } + if (ReductionClause && NogroupClause) { + S.Diag(ReductionClause->getLocStart(), diag::err_omp_reduction_with_nogroup) + << SourceRange(NogroupClause->getLocStart(), + NogroupClause->getLocEnd()); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, @@ -6132,6 +6159,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, @@ -6175,6 +6207,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, @@ -9399,6 +9436,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( SimpleRefExpr, RefRes.get()); if (!PostUpdateRes.isUsable()) continue; + if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { + Diag(RefExpr->getExprLoc(), + diag::err_omp_reduction_non_addressable_expression) + << RefExpr->getSourceRange(); + continue; + } ExprPostUpdates.push_back( IgnoredValueConversions(PostUpdateRes.get()).get()); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5cc13f391d11..36f24fd9c463 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -48,7 +48,7 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { /// A convenience routine for creating a decayed reference to a function. static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, - bool HadMultipleCandidates, + const Expr *Base, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ if (S.DiagnoseUseOfDecl(FoundDecl, Loc)) @@ -68,7 +68,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); - S.MarkDeclRefReferenced(DRE); + S.MarkDeclRefReferenced(DRE, Base); return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()), CK_FunctionToPointerDecay); } @@ -9830,6 +9830,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } + // We found a specific requirement that disabled the enable_if. + if (PDiag && PDiag->second.getDiagID() == + diag::err_typename_nested_not_found_requirement) { + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_disabled_by_requirement) + << PDiag->second.getStringArg(0) << TemplateArgString; + return; + } + // Format the SFINAE diagnostic into the argument string. // FIXME: Add a general mechanism to include a PartialDiagnostic *'s // formatted message in another diagnostic. @@ -11937,6 +11946,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, FunctionDecl *FnDecl = Best->Function; if (FnDecl) { + Expr *Base = nullptr; // We matched an overloaded operator. Build a call to that // operator. @@ -11949,7 +11959,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Best->FoundDecl, Method); if (InputRes.isInvalid()) return ExprError(); - Input = InputRes.get(); + Base = Input = InputRes.get(); } else { // Convert the arguments. ExprResult InputInit @@ -11965,7 +11975,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl, - HadMultipleCandidates, OpLoc); + Base, HadMultipleCandidates, + OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -12150,6 +12161,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, FunctionDecl *FnDecl = Best->Function; if (FnDecl) { + Expr *Base = nullptr; // We matched an overloaded operator. Build a call to that // operator. @@ -12171,7 +12183,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Best->FoundDecl, Method); if (Arg0.isInvalid()) return ExprError(); - Args[0] = Arg0.getAs<Expr>(); + Base = Args[0] = Arg0.getAs<Expr>(); Args[1] = RHS = Arg1.getAs<Expr>(); } else { // Convert the arguments. @@ -12195,7 +12207,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, - Best->FoundDecl, + Best->FoundDecl, Base, HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -12417,6 +12429,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl, + Base, HadMultipleCandidates, OpLocInfo.getLoc(), OpLocInfo.getInfo()); @@ -12975,7 +12988,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc); OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc)); ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, - HadMultipleCandidates, + Obj, HadMultipleCandidates, OpLocInfo.getLoc(), OpLocInfo.getInfo()); if (NewFn.isInvalid()) @@ -13166,7 +13179,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, // Build the operator call. ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, - HadMultipleCandidates, OpLoc); + Base, HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -13225,7 +13238,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, FunctionDecl *FD = Best->Function; ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl, - HadMultipleCandidates, + nullptr, HadMultipleCandidates, SuffixInfo.getLoc(), SuffixInfo.getInfo()); if (Fn.isInvalid()) diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b6b429d1f25c..d159172a6990 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -1176,8 +1176,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType, true /*instance*/); - bool receiverIdType = (BaseT->isObjCIdType() || - BaseT->isObjCQualifiedIdType()); if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), @@ -1203,7 +1201,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { } if (!AtIndexGetter) { - if (!receiverIdType) { + if (!BaseT->isObjCIdType()) { S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) << BaseExpr->getType() << 0 << arrayRef; return false; @@ -1284,9 +1282,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { } AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, true /*instance*/); - - bool receiverIdType = (BaseT->isObjCIdType() || - BaseT->isObjCQualifiedIdType()); if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) { TypeSourceInfo *ReturnTInfo = nullptr; @@ -1321,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { } if (!AtIndexSetter) { - if (!receiverIdType) { + if (!BaseT->isObjCIdType()) { S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) << BaseExpr->getType() << 1 << arrayRef; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index eed10b077eb8..2a38a1f8e1d8 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1544,23 +1544,78 @@ namespace { // A visitor to determine if a continue or break statement is a // subexpression. - class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> { + class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> { SourceLocation BreakLoc; SourceLocation ContinueLoc; + bool InSwitch = false; + public: - BreakContinueFinder(Sema &S, Stmt* Body) : + BreakContinueFinder(Sema &S, const Stmt* Body) : Inherited(S.Context) { Visit(Body); } - typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited; + typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited; - void VisitContinueStmt(ContinueStmt* E) { + void VisitContinueStmt(const ContinueStmt* E) { ContinueLoc = E->getContinueLoc(); } - void VisitBreakStmt(BreakStmt* E) { - BreakLoc = E->getBreakLoc(); + void VisitBreakStmt(const BreakStmt* E) { + if (!InSwitch) + BreakLoc = E->getBreakLoc(); + } + + void VisitSwitchStmt(const SwitchStmt* S) { + if (const Stmt *Init = S->getInit()) + Visit(Init); + if (const Stmt *CondVar = S->getConditionVariableDeclStmt()) + Visit(CondVar); + if (const Stmt *Cond = S->getCond()) + Visit(Cond); + + // Don't return break statements from the body of a switch. + InSwitch = true; + if (const Stmt *Body = S->getBody()) + Visit(Body); + InSwitch = false; + } + + void VisitForStmt(const ForStmt *S) { + // Only visit the init statement of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Init = S->getInit()) + Visit(Init); + } + + void VisitWhileStmt(const WhileStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitDoStmt(const DoStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Range = S->getRangeStmt()) + Visit(Range); + if (const Stmt *Begin = S->getBeginStmt()) + Visit(Begin); + if (const Stmt *End = S->getEndStmt()) + Visit(End); + } + + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Element = S->getElement()) + Visit(Element); + if (const Stmt *Collection = S->getCollection()) + Visit(Collection); } bool ContinueFound() { return ContinueLoc.isValid(); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a8923ce9e27d..e9b38551683c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2806,6 +2806,101 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, llvm_unreachable("unexpected BuiltinTemplateDecl!"); } +/// Determine whether this alias template is "enable_if_t". +static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) { + return AliasTemplate->getName().equals("enable_if_t"); +} + +/// Collect all of the separable terms in the given condition, which +/// might be a conjunction. +/// +/// FIXME: The right answer is to convert the logical expression into +/// disjunctive normal form, so we can find the first failed term +/// within each possible clause. +static void collectConjunctionTerms(Expr *Clause, + SmallVectorImpl<Expr *> &Terms) { + if (auto BinOp = dyn_cast<BinaryOperator>(Clause->IgnoreParenImpCasts())) { + if (BinOp->getOpcode() == BO_LAnd) { + collectConjunctionTerms(BinOp->getLHS(), Terms); + collectConjunctionTerms(BinOp->getRHS(), Terms); + } + + return; + } + + Terms.push_back(Clause); +} + +// The ranges-v3 library uses an odd pattern of a top-level "||" with +// a left-hand side that is value-dependent but never true. Identify +// the idiom and ignore that term. +static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) { + // Top-level '||'. + auto *BinOp = dyn_cast<BinaryOperator>(Cond->IgnoreParenImpCasts()); + if (!BinOp) return Cond; + + if (BinOp->getOpcode() != BO_LOr) return Cond; + + // With an inner '==' that has a literal on the right-hand side. + Expr *LHS = BinOp->getLHS(); + auto *InnerBinOp = dyn_cast<BinaryOperator>(LHS->IgnoreParenImpCasts()); + if (!InnerBinOp) return Cond; + + if (InnerBinOp->getOpcode() != BO_EQ || + !isa<IntegerLiteral>(InnerBinOp->getRHS())) + return Cond; + + // If the inner binary operation came from a macro expansion named + // CONCEPT_REQUIRES or CONCEPT_REQUIRES_, return the right-hand side + // of the '||', which is the real, user-provided condition. + SourceLocation Loc = InnerBinOp->getExprLoc(); + if (!Loc.isMacroID()) return Cond; + + StringRef MacroName = PP.getImmediateMacroName(Loc); + if (MacroName == "CONCEPT_REQUIRES" || MacroName == "CONCEPT_REQUIRES_") + return BinOp->getRHS(); + + return Cond; +} + +/// Find the failed subexpression within enable_if, and describe it +/// with a string. +static std::pair<Expr *, std::string> +findFailedEnableIfCondition(Sema &S, Expr *Cond) { + Cond = lookThroughRangesV3Condition(S.PP, Cond); + + // Separate out all of the terms in a conjunction. + SmallVector<Expr *, 4> Terms; + collectConjunctionTerms(Cond, Terms); + + // Determine which term failed. + Expr *FailedCond = nullptr; + for (Expr *Term : Terms) { + // The initialization of the parameter from the argument is + // a constant-evaluated context. + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + bool Succeeded; + if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) && + !Succeeded) { + FailedCond = Term->IgnoreParenImpCasts(); + break; + } + } + + if (!FailedCond) + FailedCond = Cond->IgnoreParenImpCasts(); + + std::string Description; + { + llvm::raw_string_ostream Out(Description); + FailedCond->printPretty(Out, nullptr, + PrintingPolicy(S.Context.getLangOpts())); + } + return { FailedCond, Description }; +} + QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -2852,12 +2947,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Pattern->isInvalidDecl()) return QualType(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted); + TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, + Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); for (unsigned I = 0; I < Depth; ++I) TemplateArgLists.addOuterTemplateArguments(None); @@ -2870,8 +2965,42 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = SubstType(Pattern->getUnderlyingType(), TemplateArgLists, AliasTemplate->getLocation(), AliasTemplate->getDeclName()); - if (CanonType.isNull()) + if (CanonType.isNull()) { + // If this was enable_if and we failed to find the nested type + // within enable_if in a SFINAE context, dig out the specific + // enable_if condition that failed and present that instead. + if (isEnableIfAliasTemplate(AliasTemplate)) { + if (auto DeductionInfo = isSFINAEContext()) { + if (*DeductionInfo && + (*DeductionInfo)->hasSFINAEDiagnostic() && + (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() == + diag::err_typename_nested_not_found_enable_if && + TemplateArgs[0].getArgument().getKind() + == TemplateArgument::Expression) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition( + *this, TemplateArgs[0].getSourceExpression()); + + // Remove the old SFINAE diagnostic. + PartialDiagnosticAt OldDiag = + {SourceLocation(), PartialDiagnostic::NullDiagnostic()}; + (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag); + + // Add a new SFINAE diagnostic specifying which condition + // failed. + (*DeductionInfo)->addSFINAEDiagnostic( + OldDiag.first, + PDiag(diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange()); + } + } + } + return QualType(); + } } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, InstantiationDependent)) { @@ -5190,10 +5319,16 @@ enum NullPointerValueKind { /// value of the appropriate type. static NullPointerValueKind isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, - QualType ParamType, Expr *Arg) { + QualType ParamType, Expr *Arg, + Decl *Entity = nullptr) { if (Arg->isValueDependent() || Arg->isTypeDependent()) return NPV_NotNullPointer; + // dllimport'd entities aren't constant but are available inside of template + // arguments. + if (Entity && Entity->hasAttr<DLLImportAttr>()) + return NPV_NotNullPointer; + if (!S.isCompleteType(Arg->getExprLoc(), ParamType)) llvm_unreachable( "Incomplete parameter type in isNullPointerValueTemplateArgument!"); @@ -5437,14 +5572,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // If our parameter has pointer type, check for a null template value. if (ParamType->isPointerType() || ParamType->isNullPtrType()) { - NullPointerValueKind NPV; - // dllimport'd entities aren't constant but are available inside of template - // arguments. - if (Entity && Entity->hasAttr<DLLImportAttr>()) - NPV = NPV_NotNullPointer; - else - NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn); - switch (NPV) { + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn, + Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), @@ -5636,39 +5765,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, TemplateArgument &Converted) { bool Invalid = false; - // Check for a null pointer value. Expr *Arg = ResultArg; - switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) { - case NPV_Error: - return true; - case NPV_NullPointer: - S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); - return false; - case NPV_NotNullPointer: - break; - } - bool ObjCLifetimeConversion; - if (S.IsQualificationConversion(Arg->getType(), - ParamType.getNonReferenceType(), - false, ObjCLifetimeConversion)) { - Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp, - Arg->getValueKind()).get(); - ResultArg = Arg; - } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(), - ParamType.getNonReferenceType())) { - // We can't perform this conversion. - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) - << Arg->getType() << ParamType << Arg->getSourceRange(); - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - // See through any implicit casts we added to fix the type. - while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = Cast->getSubExpr(); // C++ [temp.arg.nontype]p1: // @@ -5725,6 +5823,37 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, DRE = nullptr; } + ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr; + + // Check for a null pointer value. + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ResultArg, + Entity)) { + case NPV_Error: + return true; + case NPV_NullPointer: + S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); + Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr*/true); + return false; + case NPV_NotNullPointer: + break; + } + + if (S.IsQualificationConversion(ResultArg->getType(), + ParamType.getNonReferenceType(), false, + ObjCLifetimeConversion)) { + ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp, + ResultArg->getValueKind()) + .get(); + } else if (!S.Context.hasSameUnqualifiedType( + ResultArg->getType(), ParamType.getNonReferenceType())) { + // We can't perform this conversion. + S.Diag(ResultArg->getLocStart(), diag::err_template_arg_not_convertible) + << ResultArg->getType() << ParamType << ResultArg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + if (!DRE) return S.Diag(Arg->getLocStart(), diag::err_template_arg_not_pointer_to_member_form) @@ -9290,7 +9419,7 @@ Sema::ActOnTypenameType(Scope *S, /// Determine whether this failed name lookup should be treated as being /// disabled by a usage of std::enable_if. static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, - SourceRange &CondRange) { + SourceRange &CondRange, Expr *&Cond) { // We must be looking for a ::type... if (!II.isStr("type")) return false; @@ -9320,6 +9449,19 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, // Assume the first template argument is the condition. CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange(); + + // Dig out the condition. + Cond = nullptr; + if (EnableIfTSTLoc.getArgLoc(0).getArgument().getKind() + != TemplateArgument::Expression) + return true; + + Cond = EnableIfTSTLoc.getArgLoc(0).getSourceExpression(); + + // Ignore Boolean literals; they add no value. + if (isa<CXXBoolLiteralExpr>(Cond->IgnoreParenCasts())) + Cond = nullptr; + return true; } @@ -9363,9 +9505,25 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we're looking up 'type' within a template named 'enable_if', produce // a more specific diagnostic. SourceRange CondRange; - if (isEnableIf(QualifierLoc, II, CondRange)) { + Expr *Cond = nullptr; + if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + // If we have a condition, narrow it down to the specific failed + // condition. + if (Cond) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition(*this, Cond); + + Diag(FailedCond->getExprLoc(), + diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange(); + return QualType(); + } + Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) - << Ctx << CondRange; + << Ctx << CondRange; return QualType(); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3aee3c04001d..678ecfc9a3d9 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -9314,6 +9314,7 @@ void ASTReader::diagnoseOdrViolations() { TypeAlias, TypeDef, Var, + Friend, Other } FirstDiffType = Other, SecondDiffType = Other; @@ -9347,6 +9348,8 @@ void ASTReader::diagnoseOdrViolations() { return TypeDef; case Decl::Var: return Var; + case Decl::Friend: + return Friend; } }; @@ -9463,6 +9466,9 @@ void ASTReader::diagnoseOdrViolations() { VarSingleInitializer, VarDifferentInitializer, VarConstexpr, + FriendTypeFunction, + FriendType, + FriendFunction, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9973,6 +9979,53 @@ void ASTReader::diagnoseOdrViolations() { } break; } + case Friend: { + FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); + FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); + + NamedDecl *FirstND = FirstFriend->getFriendDecl(); + NamedDecl *SecondND = SecondFriend->getFriendDecl(); + + TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); + TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); + + if (FirstND && SecondND) { + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendFunction) + << FirstND; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendFunction) + << SecondND; + + Diagnosed = true; + break; + } + + if (FirstTSI && SecondTSI) { + QualType FirstFriendType = FirstTSI->getType(); + QualType SecondFriendType = SecondTSI->getType(); + assert(ComputeQualTypeODRHash(FirstFriendType) != + ComputeQualTypeODRHash(SecondFriendType)); + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendType) + << FirstFriendType; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendType) + << SecondFriendType; + Diagnosed = true; + break; + } + + ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), + FriendTypeFunction) + << (FirstTSI == nullptr); + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendTypeFunction) + << (SecondTSI == nullptr); + + Diagnosed = true; + break; + } } if (Diagnosed == true) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 4d9ddd2ff506..abed2586561a 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -573,6 +573,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { else Reader.HiddenNamesMap[Owner].push_back(D); } + } else if (ModulePrivate) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index c6129d326cb6..f7a49e41009d 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1462,7 +1462,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, } // Module map file - if (WritingModule) { + if (WritingModule && WritingModule->Kind == Module::ModuleMapModule) { Record.clear(); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 2d648cb103cb..ec21ca2276c1 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -2233,8 +2233,18 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { Writer->ClearSwitchCaseIDs(); assert(FD->doesThisDeclarationHaveABody()); - bool ModulesCodegen = Writer->Context->getLangOpts().ModulesCodegen && - Writer->WritingModule && !FD->isDependentContext(); + bool ModulesCodegen = false; + if (Writer->WritingModule && !FD->isDependentContext()) { + // Under -fmodules-codegen, codegen is performed for all defined functions. + // When building a C++ Modules TS module interface unit, a strong definition + // in the module interface is provided by the compilation of that module + // interface unit, not by its users. (Inline functions are still emitted + // in module users.) + ModulesCodegen = + Writer->Context->getLangOpts().ModulesCodegen || + (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit && + Writer->Context->GetGVALinkageForFunction(FD) == GVA_StrongExternal); + } Record->push_back(ModulesCodegen); if (ModulesCodegen) Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 54634fdffeb5..83e67662e614 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -23,9 +23,10 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnalyzerOptions &Options, CodeInjector *injector) : AnaCtxMgr(Options.UnoptimizedCFG, - /*AddImplicitDtors=*/true, + Options.includeImplicitDtorsInCFG(), /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), + Options.includeLifetimeInCFG(), Options.shouldSynthesizeBodies(), Options.shouldConditionalizeStaticInitializers(), /*addCXXNewAllocator=*/true, diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 11b9f8c4f725..6f48fcb9e20c 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -172,6 +172,17 @@ bool AnalyzerOptions::includeTemporaryDtorsInCFG() { /* Default = */ false); } +bool AnalyzerOptions::includeImplicitDtorsInCFG() { + return getBooleanOption(IncludeImplicitDtorsInCFG, + "cfg-implicit-dtors", + /* Default = */ true); +} + +bool AnalyzerOptions::includeLifetimeInCFG() { + return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime", + /* Default = */ false); +} + bool AnalyzerOptions::mayInlineCXXStandardLibrary() { return getBooleanOption(InlineCXXStandardLibrary, "c++-stdlib-inlining", diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index f84c0ee800a3..eee5400fe177 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -362,6 +362,8 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::TemporaryDtor: ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred); return; + case CFGElement::LifetimeEnds: + return; } } diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 6aa6da560e60..d91786f74919 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -578,6 +578,7 @@ getLocationForCaller(const StackFrameContext *SFC, } case CFGElement::TemporaryDtor: case CFGElement::NewAllocator: + case CFGElement::LifetimeEnds: llvm_unreachable("not yet implemented!"); } diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 9c28457b2139..f09f9696f5ad 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -71,18 +71,15 @@ SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) { } SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { - bool isLocType = Loc::isLocType(castTy); - if (val.getAs<nonloc::PointerToMember>()) return val; if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) { if (isLocType) return LI->getLoc(); - // FIXME: Correctly support promotions/truncations. - unsigned castSize = Context.getTypeSize(castTy); + unsigned castSize = Context.getIntWidth(castTy); if (castSize == LI->getNumBits()) return val; return makeLocAsInteger(LI->getLoc(), castSize); @@ -173,7 +170,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { } if (castTy->isIntegralOrEnumerationType()) { - unsigned BitWidth = Context.getTypeSize(castTy); + unsigned BitWidth = Context.getIntWidth(castTy); if (!val.getAs<loc::ConcreteInt>()) return makeLocAsInteger(val, BitWidth); diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp index 48b925c698a7..ac9fd3c5cade 100644 --- a/lib/Tooling/ArgumentsAdjusters.cpp +++ b/lib/Tooling/ArgumentsAdjusters.cpp @@ -42,7 +42,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { AdjustedArgs.push_back(Args[i]); if (Arg == "-o") { - // Output is specified as -o foo. Skip the next argument also. + // Output is specified as -o foo. Skip the next argument too. ++i; } // Else, the output is specified as -ofoo. Just do nothing. @@ -51,6 +51,26 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { }; } +ArgumentsAdjuster getClangStripDependencyFileAdjuster() { + return [](const CommandLineArguments &Args, StringRef /*unused*/) { + CommandLineArguments AdjustedArgs; + for (size_t i = 0, e = Args.size(); i < e; ++i) { + StringRef Arg = Args[i]; + // All dependency-file options begin with -M. These include -MM, + // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD. + if (!Arg.startswith("-M")) + AdjustedArgs.push_back(Args[i]); + + if ((Arg == "-MF") || (Arg == "-MT") || (Arg == "-MQ") || + (Arg == "-MD") || (Arg == "-MMD")) { + // Output is specified as -MX foo. Skip the next argument also. + ++i; + } + } + return AdjustedArgs; + }; +} + ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, ArgumentInsertPosition Pos) { return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { @@ -83,4 +103,3 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, } // end namespace tooling } // end namespace clang - diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp index 3bbc2b901e38..9e4833f2eff4 100644 --- a/lib/Tooling/Core/Diagnostic.cpp +++ b/lib/Tooling/Core/Diagnostic.cpp @@ -35,9 +35,9 @@ Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, BuildDirectory(BuildDirectory) {} Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, - DiagnosticMessage &Message, - llvm::StringMap<Replacements> &Fix, - SmallVector<DiagnosticMessage, 1> &Notes, + const DiagnosticMessage &Message, + const llvm::StringMap<Replacements> &Fix, + const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, llvm::StringRef BuildDirectory) : DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes), DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {} diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index 2e093dd9afc8..c84fbf473753 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -100,7 +100,6 @@ clang::CompilerInvocation *newInvocation( *Diagnostics); Invocation->getFrontendOpts().DisableFree = false; Invocation->getCodeGenOpts().DisableFree = false; - Invocation->getDependencyOutputOpts() = DependencyOutputOptions(); return Invocation; } @@ -140,9 +139,11 @@ bool runToolOnCodeWithArgs( OverlayFileSystem->pushOverlay(InMemoryFileSystem); llvm::IntrusiveRefCntPtr<FileManager> Files( new FileManager(FileSystemOptions(), OverlayFileSystem)); - ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef), - ToolAction, Files.get(), - std::move(PCHContainerOps)); + ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(); + ToolInvocation Invocation( + getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), + ToolAction, Files.get(), + std::move(PCHContainerOps)); SmallString<1024> CodeStorage; InMemoryFileSystem->addFile(FileNameRef, 0, @@ -510,7 +511,8 @@ buildASTFromCode(const Twine &Code, const Twine &FileName, std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( const Twine &Code, const std::vector<std::string> &Args, const Twine &FileName, const Twine &ToolName, - std::shared_ptr<PCHContainerOperations> PCHContainerOps) { + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + ArgumentsAdjuster Adjuster) { SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); @@ -523,8 +525,10 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( OverlayFileSystem->pushOverlay(InMemoryFileSystem); llvm::IntrusiveRefCntPtr<FileManager> Files( new FileManager(FileSystemOptions(), OverlayFileSystem)); - ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef), - &Action, Files.get(), std::move(PCHContainerOps)); + + ToolInvocation Invocation( + getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), + &Action, Files.get(), std::move(PCHContainerOps)); SmallString<1024> CodeStorage; InMemoryFileSystem->addFile(FileNameRef, 0, diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c index 70521c63fbad..0d8d34fbf6b0 100644 --- a/test/Analysis/analyzer-config.c +++ b/test/Analysis/analyzer-config.c @@ -12,6 +12,8 @@ void foo() { // CHECK: [config] // CHECK-NEXT: cfg-conditional-static-initializers = true +// CHECK-NEXT: cfg-implicit-dtors = true +// CHECK-NEXT: cfg-lifetime = false // CHECK-NEXT: cfg-temporary-dtors = false // CHECK-NEXT: faux-bodies = true // CHECK-NEXT: graph-trim-interval = 1000 @@ -27,5 +29,4 @@ void foo() { // CHECK-NEXT: region-store-small-struct-limit = 2 // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 15 - +// CHECK-NEXT: num-entries = 17 diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp index 60c03c1e497b..4166a730cf53 100644 --- a/test/Analysis/analyzer-config.cpp +++ b/test/Analysis/analyzer-config.cpp @@ -23,6 +23,8 @@ public: // CHECK-NEXT: c++-stdlib-inlining = true // CHECK-NEXT: c++-template-inlining = true // CHECK-NEXT: cfg-conditional-static-initializers = true +// CHECK-NEXT: cfg-implicit-dtors = true +// CHECK-NEXT: cfg-lifetime = false // CHECK-NEXT: cfg-temporary-dtors = false // CHECK-NEXT: faux-bodies = true // CHECK-NEXT: graph-trim-interval = 1000 @@ -38,4 +40,4 @@ public: // CHECK-NEXT: region-store-small-struct-limit = 2 // CHECK-NEXT: widen-loops = false // CHECK-NEXT: [stats] -// CHECK-NEXT: num-entries = 20 +// CHECK-NEXT: num-entries = 22 diff --git a/test/Analysis/enum.cpp b/test/Analysis/enum.cpp index b561e65ac86e..96408473cede 100644 --- a/test/Analysis/enum.cpp +++ b/test/Analysis/enum.cpp @@ -37,3 +37,33 @@ bool testNoCrashOnSwitchEnumBool(EnumBool E) { } return true; } + +bool testNoCrashOnSwitchEnumBoolConstant() { + EnumBool E = EnumBool::F; + switch (E) { + case EnumBool::F: + return false; + } + return true; +} + +typedef __INTPTR_TYPE__ intptr_t; +bool testNoCrashOnSwitchEnumBoolConstantCastedFromNullptr() { + EnumBool E = static_cast<EnumBool>((intptr_t)nullptr); + switch (E) { + case EnumBool::F: + return false; + } + return true; +} + +bool testNoCrashOnSwitchEnumBoolConstantCastedFromPtr() { + int X; + intptr_t P = (intptr_t)&X; + EnumBool E = static_cast<EnumBool>(P); + switch (E) { + case EnumBool::F: + return false; + } + return true; +} diff --git a/test/Analysis/lifetime-cfg-output.cpp b/test/Analysis/lifetime-cfg-output.cpp new file mode 100644 index 000000000000..1e6f56df6a47 --- /dev/null +++ b/test/Analysis/lifetime-cfg-output.cpp @@ -0,0 +1,783 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-lifetime=true -analyzer-config cfg-implicit-dtors=false %s > %t 2>&1 +// RUN: FileCheck --input-file=%t %s + +extern bool UV; +class A { +public: + // CHECK: [B2 (ENTRY)] + // CHECK-NEXT: Succs (1): B1 + // CHECK: [B1] + // CHECK-NEXT: 1: true + // CHECK-NEXT: 2: UV + // CHECK-NEXT: 3: [B1.2] = [B1.1] + // CHECK-NEXT: Preds (1): B2 + // CHECK-NEXT: Succs (1): B0 + // CHECK: [B0 (EXIT)] + // CHECK-NEXT: Preds (1): B1 + A() { + UV = true; + } + // CHECK: [B3 (ENTRY)] + // CHECK-NEXT: Succs (1): B2 + // CHECK: [B1] + // CHECK-NEXT: 1: 0 + // CHECK-NEXT: 2: this + // CHECK-NEXT: 3: [B1.2]->p + // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, LValueToRValue, int *) + // CHECK-NEXT: 5: *[B1.4] + // CHECK-NEXT: 6: [B1.5] = [B1.1] + // CHECK-NEXT: Preds (1): B2 + // CHECK-NEXT: Succs (1): B0 + // CHECK: [B2] + // CHECK-NEXT: 1: this + // CHECK-NEXT: 2: [B2.1]->p + // CHECK-NEXT: 3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *) + // CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, PointerToBoolean, _Bool) + // CHECK-NEXT: T: if [B2.4] + // CHECK-NEXT: Preds (1): B3 + // CHECK-NEXT: Succs (2): B1 B0 + // CHECK: [B0 (EXIT)] + // CHECK-NEXT: Preds (2): B1 B2 + ~A() { + if (p) + *p = 0; + } + // CHECK: [B2 (ENTRY)] + // CHECK-NEXT: Succs (1): B1 + // CHECK: [B1] + // CHECK-NEXT: 1: 1 + // CHECK-NEXT: 2: return [B1.1]; + // CHECK-NEXT: Preds (1): B2 + // CHECK-NEXT: Succs (1): B0 + // CHECK: [B0 (EXIT)] + // CHECK-NEXT: Preds (1): B1 + operator int() const { return 1; } + int *p; +}; + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: a +// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 5: const A &b = a; +// CHECK-NEXT: 6: A() (CXXConstructExpr, class A) +// CHECK-NEXT: 7: [B1.6] (BindTemporary) +// CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 9: [B1.8] +// CHECK-NEXT: 10: const A &c = A(); +// CHECK-NEXT: 11: [B1.10] (Lifetime ends) +// CHECK-NEXT: 12: [B1.2] (Lifetime ends) +// CHECK-NEXT: 13: [B1.5] (Lifetime ends) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_const_ref() { + A a; + const A &b = a; + const A &c = A(); +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A [2]) +// CHECK-NEXT: 2: A a[2]; +// CHECK-NEXT: 3: (CXXConstructExpr, class A [0]) +// CHECK-NEXT: 4: A b[0]; +// lifetime of a ends when its destructors are run +// CHECK-NEXT: 5: [B1.2] (Lifetime ends) +// lifetime of b ends when its storage duration ends +// CHECK-NEXT: 6: [B1.4] (Lifetime ends) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_array() { + A a[2]; + A b[0]; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A c; +// CHECK-NEXT: 5: (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A d; +// CHECK-NEXT: 7: [B1.6] (Lifetime ends) +// CHECK-NEXT: 8: [B1.4] (Lifetime ends) +// CHECK-NEXT: 9: (CXXConstructExpr, class A) +// CHECK-NEXT: 10: A b; +// CHECK-NEXT: 11: [B1.10] (Lifetime ends) +// CHECK-NEXT: 12: [B1.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_scope() { + A a; + { + A c; + A d; + } + A b; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B1.2] (Lifetime ends) +// CHECK-NEXT: 4: [B3.4] (Lifetime ends) +// CHECK-NEXT: 5: [B3.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B3.4] (Lifetime ends) +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A b; +// CHECK-NEXT: 5: UV +// CHECK-NEXT: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B3.6] +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (2): B2 B1 + +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (2): B1 B2 +void test_return() { + A a; + A b; + if (UV) + return; + A c; +} + +// CHECK: [B5 (ENTRY)] +// CHECK-NEXT: Succs (1): B4 +// CHECK: [B1] +// CHECK-NEXT: 1: [B4.6] (Lifetime ends) +// CHECK-NEXT: 2: [B4.2] (Lifetime ends) +// CHECK-NEXT: Preds (2): B2 B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B2.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B4] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: a +// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 5: [B4.4] (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A b = a; +// CHECK-NEXT: 7: b +// CHECK-NEXT: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 9: [B4.8].operator int +// CHECK-NEXT: 10: [B4.8] +// CHECK-NEXT: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: if [B4.12] +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (2): B3 B2 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_if_implicit_scope() { + A a; + if (A b = a) + A c; + else + A c; +} + +// CHECK: [B9 (ENTRY)] +// CHECK-NEXT: Succs (1): B8 +// CHECK: [B1] +// CHECK-NEXT: 1: [B8.6] (Lifetime ends) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A e; +// CHECK-NEXT: 4: [B1.3] (Lifetime ends) +// CHECK-NEXT: 5: [B8.2] (Lifetime ends) +// CHECK-NEXT: Preds (2): B2 B5 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A d; +// CHECK-NEXT: 3: [B2.2] (Lifetime ends) +// CHECK-NEXT: 4: [B4.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B3] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B4.2] (Lifetime ends) +// CHECK-NEXT: 3: [B8.6] (Lifetime ends) +// CHECK-NEXT: 4: [B8.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B4] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: UV +// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B4.4] +// CHECK-NEXT: Preds (1): B8 +// CHECK-NEXT: Succs (2): B3 B2 +// CHECK: [B5] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A d; +// CHECK-NEXT: 3: [B5.2] (Lifetime ends) +// CHECK-NEXT: 4: [B7.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B6] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B7.2] (Lifetime ends) +// CHECK-NEXT: 3: [B8.6] (Lifetime ends) +// CHECK-NEXT: 4: [B8.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B7] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: UV +// CHECK-NEXT: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B7.4] +// CHECK-NEXT: Preds (1): B8 +// CHECK-NEXT: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: a +// CHECK-NEXT: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 5: [B8.4] (CXXConstructExpr, class A) +// CHECK-NEXT: 6: A b = a; +// CHECK-NEXT: 7: b +// CHECK-NEXT: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 9: [B8.8].operator int +// CHECK-NEXT: 10: [B8.8] +// CHECK-NEXT: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: if [B8.12] +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (2): B7 B4 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (3): B1 B3 B6 +void test_if_jumps() { + A a; + if (A b = a) { + A c; + if (UV) + return; + A d; + } else { + A c; + if (UV) + return; + A d; + } + A e; +} + +// CHECK: [B6 (ENTRY)] +// CHECK-NEXT: Succs (1): B5 +// CHECK: [B1] +// CHECK-NEXT: 1: [B4.4] (Lifetime ends) +// CHECK-NEXT: 2: [B5.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B4 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: 4: [B4.4] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: a +// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A b = a; +// CHECK-NEXT: 5: b +// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 7: [B4.6].operator int +// CHECK-NEXT: 8: [B4.6] +// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: while [B4.10] +// CHECK-NEXT: Preds (2): B2 B5 +// CHECK-NEXT: Succs (2): B3 B1 +// CHECK: [B5] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: Preds (1): B6 +// CHECK-NEXT: Succs (1): B4 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_while_implicit_scope() { + A a; + while (A b = a) + A c; +} + +// CHECK: [B12 (ENTRY)] +// CHECK-NEXT: Succs (1): B11 +// CHECK: [B1] +// CHECK-NEXT: 1: [B10.4] (Lifetime ends) +// CHECK-NEXT: 2: (CXXConstructExpr, class A) +// CHECK-NEXT: 3: A e; +// CHECK-NEXT: 4: [B1.3] (Lifetime ends) +// CHECK-NEXT: 5: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (2): B8 B10 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: Preds (2): B3 B6 +// CHECK-NEXT: Succs (1): B10 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A d; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: 4: [B9.2] (Lifetime ends) +// CHECK-NEXT: 5: [B10.4] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B9.2] (Lifetime ends) +// CHECK-NEXT: 3: [B10.4] (Lifetime ends) +// CHECK-NEXT: 4: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B5] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B5.2] +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (2): B4 B3 +// CHECK: [B6] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: 2: [B10.4] (Lifetime ends) +// CHECK-NEXT: T: continue; +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B7] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B7.2] +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: T: break; +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B9] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: UV +// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B9.4] +// CHECK-NEXT: Preds (1): B10 +// CHECK-NEXT: Succs (2): B8 B7 +// CHECK: [B10] +// CHECK-NEXT: 1: a +// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A b = a; +// CHECK-NEXT: 5: b +// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 7: [B10.6].operator int +// CHECK-NEXT: 8: [B10.6] +// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: while [B10.10] +// CHECK-NEXT: Preds (2): B2 B11 +// CHECK-NEXT: Succs (2): B9 B1 +// CHECK: [B11] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: Preds (1): B12 +// CHECK-NEXT: Succs (1): B10 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (2): B1 B4 +void test_while_jumps() { + A a; + while (A b = a) { + A c; + if (UV) + break; + if (UV) + continue; + if (UV) + return; + A d; + } + A e; +} + +// CHECK: [B12 (ENTRY)] +// CHECK-NEXT: Succs (1): B11 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A d; +// CHECK-NEXT: 3: [B1.2] (Lifetime ends) +// CHECK-NEXT: 4: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (2): B8 B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: do ... while [B2.2] +// CHECK-NEXT: Preds (2): B3 B6 +// CHECK-NEXT: Succs (2): B10 B1 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: 4: [B9.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B9.2] (Lifetime ends) +// CHECK-NEXT: 3: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B5] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B5.2] +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (2): B4 B3 +// CHECK: [B6] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: T: continue; +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B7] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B7.2] +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: T: break; +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B9] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A b; +// CHECK-NEXT: 3: UV +// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B9.4] +// CHECK-NEXT: Preds (2): B10 B11 +// CHECK-NEXT: Succs (2): B8 B7 +// CHECK: [B10] +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B9 +// CHECK: [B11] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: Preds (1): B12 +// CHECK-NEXT: Succs (1): B9 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (2): B1 B4 +void test_do_jumps() { + A a; + do { + A b; + if (UV) + break; + if (UV) + continue; + if (UV) + return; + A c; + } while (UV); + A d; +} + +// CHECK: [B6 (ENTRY)] +// CHECK-NEXT: Succs (1): B5 +// CHECK: [B1] +// CHECK-NEXT: 1: [B4.4] (Lifetime ends) +// CHECK-NEXT: 2: [B5.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: Preds (1): B3 +// CHECK-NEXT: Succs (1): B4 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A c; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: 4: [B4.4] (Lifetime ends) +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: a +// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A b = a; +// CHECK-NEXT: 5: b +// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 7: [B4.6].operator int +// CHECK-NEXT: 8: [B4.6] +// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: for (...; [B4.10]; ) +// CHECK-NEXT: Preds (2): B2 B5 +// CHECK-NEXT: Succs (2): B3 B1 +// CHECK: [B5] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: Preds (1): B6 +// CHECK-NEXT: Succs (1): B4 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_for_implicit_scope() { + for (A a; A b = a;) + A c; +} + +// CHECK: [B12 (ENTRY)] +// CHECK-NEXT: Succs (1): B11 +// CHECK: [B1] +// CHECK-NEXT: 1: [B10.4] (Lifetime ends) +// CHECK-NEXT: 2: [B11.4] (Lifetime ends) +// CHECK-NEXT: 3: (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A f; +// CHECK-NEXT: 5: [B1.4] (Lifetime ends) +// CHECK-NEXT: 6: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (2): B8 B10 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: Preds (2): B3 B6 +// CHECK-NEXT: Succs (1): B10 +// CHECK: [B3] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A e; +// CHECK-NEXT: 3: [B3.2] (Lifetime ends) +// CHECK-NEXT: 4: [B9.2] (Lifetime ends) +// CHECK-NEXT: 5: [B10.4] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B4] +// CHECK-NEXT: 1: return; +// CHECK-NEXT: 2: [B9.2] (Lifetime ends) +// CHECK-NEXT: 3: [B10.4] (Lifetime ends) +// CHECK-NEXT: 4: [B11.4] (Lifetime ends) +// CHECK-NEXT: 5: [B11.2] (Lifetime ends) +// CHECK-NEXT: Preds (1): B5 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B5] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B5.2] +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (2): B4 B3 +// CHECK: [B6] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: T: continue; +// CHECK-NEXT: Preds (1): B7 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B7] +// CHECK-NEXT: 1: UV +// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B7.2] +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (2): B6 B5 +// CHECK: [B8] +// CHECK-NEXT: 1: [B9.2] (Lifetime ends) +// CHECK-NEXT: T: break; +// CHECK-NEXT: Preds (1): B9 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B9] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A d; +// CHECK-NEXT: 3: UV +// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool) +// CHECK-NEXT: T: if [B9.4] +// CHECK-NEXT: Preds (1): B10 +// CHECK-NEXT: Succs (2): B8 B7 +// CHECK: [B10] +// CHECK-NEXT: 1: b +// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A c = b; +// CHECK-NEXT: 5: c +// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A) +// CHECK-NEXT: 7: [B10.6].operator int +// CHECK-NEXT: 8: [B10.6] +// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int) +// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool) +// CHECK-NEXT: T: for (...; [B10.10]; ) +// CHECK-NEXT: Preds (2): B2 B11 +// CHECK-NEXT: Succs (2): B9 B1 +// CHECK: [B11] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: (CXXConstructExpr, class A) +// CHECK-NEXT: 4: A b; +// CHECK-NEXT: Preds (1): B12 +// CHECK-NEXT: Succs (1): B10 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (2): B1 B4 +void test_for_jumps() { + A a; + for (A b; A c = b;) { + A d; + if (UV) + break; + if (UV) + continue; + if (UV) + return; + A e; + } + A f; +} + +// CHECK: [B2 (ENTRY)] +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B1] +// CHECK-NEXT: 1: (CXXConstructExpr, class A) +// CHECK-NEXT: 2: A a; +// CHECK-NEXT: 3: int n; +// CHECK-NEXT: 4: n +// CHECK-NEXT: 5: &[B1.4] +// CHECK-NEXT: 6: a +// CHECK-NEXT: 7: [B1.6].p +// CHECK-NEXT: 8: [B1.7] = [B1.5] +// CHECK-NEXT: 9: [B1.2] (Lifetime ends) +// CHECK-NEXT: 10: [B1.3] (Lifetime ends) +// CHECK-NEXT: Preds (1): B2 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void test_trivial_vs_non_trivial_order() { + A a; + int n; + a.p = &n; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: a: +// CHECK-NEXT: 1: 1 +// CHECK-NEXT: 2: i +// CHECK-NEXT: 3: [B1.2] = [B1.1] +// CHECK-NEXT: 4: [B2.1] (Lifetime ends) +// CHECK-NEXT: Preds (2): B2 B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: int i; +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B3] +// CHECK-NEXT: T: goto a; +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void goto_past_declaration() { + goto a; + int i; +a: + i = 1; +} + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: a: +// CHECK-NEXT: 1: 1 +// CHECK-NEXT: 2: k +// CHECK-NEXT: 3: [B1.2] = [B1.1] +// CHECK-NEXT: 4: [B2.4] (Lifetime ends) +// CHECK-NEXT: Preds (2): B2 B3 +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: 1: int j; +// CHECK-NEXT: 2: [B2.1] (Lifetime ends) +// CHECK-NEXT: 3: [B3.1] (Lifetime ends) +// CHECK-NEXT: 4: int k; +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B3] +// CHECK-NEXT: 1: int i; +// CHECK-NEXT: 2: [B3.1] (Lifetime ends) +// CHECK-NEXT: T: goto a; +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B1 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +void goto_past_declaration2() { + { + int i; + goto a; + int j; + } + { + int k; + a: + k = 1; + } +} + +struct B { + ~B(); +}; + +// CHECK: [B4 (ENTRY)] +// CHECK-NEXT: Succs (1): B3 +// CHECK: [B1] +// CHECK-NEXT: 1: i +// CHECK-NEXT: 2: [B1.1]++ +// CHECK-NEXT: 3: [B2.2] (Lifetime ends) +// CHECK-NEXT: 4: [B3.1] (Lifetime ends) +// CHECK-NEXT: Succs (1): B0 +// CHECK: [B2] +// CHECK-NEXT: label: +// CHECK-NEXT: 1: (CXXConstructExpr, struct B) +// CHECK-NEXT: 2: B b; +// CHECK-NEXT: 3: [B2.2] (Lifetime ends) +// CHECK-NEXT: T: goto label; +// CHECK-NEXT: Preds (2): B3 B2 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B3] +// CHECK-NEXT: 1: int i; +// CHECK-NEXT: Preds (1): B4 +// CHECK-NEXT: Succs (1): B2 +// CHECK: [B0 (EXIT)] +// CHECK-NEXT: Preds (1): B1 +int backpatched_goto() { + int i; +label: + B b; + goto label; + i++; +} diff --git a/test/CXX/except/except.spec/p11.cpp b/test/CXX/except/except.spec/p11.cpp index 196f84c557ea..b7b9fcb23144 100644 --- a/test/CXX/except/except.spec/p11.cpp +++ b/test/CXX/except/except.spec/p11.cpp @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -std=c++11 -fexceptions -fcxx-exceptions -fsyntax-only -verify %s // This is the "let the user shoot themselves in the foot" clause. -void f() noexcept { // expected-note {{non-throwing function declare here}} +void f() noexcept { // expected-note {{function declared non-throwing here}} throw 0; // expected-warning {{has a non-throwing exception specification but}} } -void g() throw() { // expected-note {{non-throwing function declare here}} +void g() throw() { // expected-note {{function declared non-throwing here}} throw 0; // expected-warning {{has a non-throwing exception specification but}} } void h() throw(int) { diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp new file mode 100644 index 000000000000..dc6a3635a8ee --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t +// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module + +// CHECK-DAG: @extern_var_exported = external global +// FIXME: Should this be 'external global'? +// CHECK-DAG: @inline_var_exported = linkonce_odr global +// CHECK-DAG: @_ZL19static_var_exported = external global +// CHECK-DAG: @const_var_exported = external constant +// +// FIXME: The module name should be mangled into all of these. +// CHECK-DAG: @extern_var_module_linkage = external global +// FIXME: Should this be 'external global'? +// CHECK-DAG: @inline_var_module_linkage = linkonce_odr global +// CHECK-DAG: @_ZL25static_var_module_linkage = external global +// CHECK-DAG: @_ZL24const_var_module_linkage = external constant + +module Module; + +void use() { + // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv + used_inline_exported(); + // CHECK: declare {{.*}}@_Z18noninline_exportedv + noninline_exported(); + + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; // FIXME: Should not be exported. + (void)&const_var_exported; + + // FIXME: This symbol should not be visible here. + // CHECK: declare {{.*}}@_ZL26used_static_module_linkagev + used_static_module_linkage(); + + // FIXME: The module name should be mangled into the name of this function. + // CHECK: define linkonce_odr {{.*}}@_Z26used_inline_module_linkagev + used_inline_module_linkage(); + + // FIXME: The module name should be mangled into the name of this function. + // CHECK: declare {{.*}}@_Z24noninline_module_linkagev + noninline_module_linkage(); + + (void)&extern_var_module_linkage; + (void)&inline_var_module_linkage; + (void)&static_var_module_linkage; // FIXME: Should not be visible here. + (void)&const_var_module_linkage; +} diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm new file mode 100644 index 000000000000..d452f741a0fb --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/module.cppm @@ -0,0 +1,118 @@ +// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s --implicit-check-not unused_inline --implicit-check-not unused_stastic_global_module + +// CHECK-DAG: @extern_var_global_module = external global +// CHECK-DAG: @inline_var_global_module = linkonce_odr global +// CHECK-DAG: @_ZL24static_var_global_module = internal global +// CHECK-DAG: @_ZL23const_var_global_module = internal constant +// +// For ABI compatibility, these symbols do not include the module name. +// CHECK-DAG: @extern_var_exported = external global +// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we +// can discard this global and its initializer (if any), and other TUs are not +// permitted to run the initializer for this variable. +// CHECK-DAG: @inline_var_exported = linkonce_odr global +// CHECK-DAG: @_ZL19static_var_exported = global +// CHECK-DAG: @const_var_exported = constant +// +// FIXME: The module name should be mangled into all of these. +// CHECK-DAG: @extern_var_module_linkage = external global +// FIXME: Should this be 'weak_odr global'? Presumably it must be, since we +// can discard this global and its initializer (if any), and other TUs are not +// permitted to run the initializer for this variable. +// CHECK-DAG: @inline_var_module_linkage = linkonce_odr global +// CHECK-DAG: @_ZL25static_var_module_linkage = global +// CHECK-DAG: @_ZL24const_var_module_linkage = constant + +static void unused_static_global_module() {} +static void used_static_global_module() {} + +inline void unused_inline_global_module() {} +inline void used_inline_global_module() {} + +extern int extern_var_global_module; +inline int inline_var_global_module; +static int static_var_global_module; +const int const_var_global_module = 3; + +// CHECK: define void {{.*}}@_Z23noninline_global_modulev +void noninline_global_module() { + // FIXME: This should be promoted to module linkage and given a + // module-mangled name, if it's called from an inline function within + // the module interface. + // (We should try to avoid this when it's not reachable from outside + // the module interface unit.) + // CHECK: define internal {{.*}}@_ZL25used_static_global_modulev + used_static_global_module(); + // CHECK: define linkonce_odr {{.*}}@_Z25used_inline_global_modulev + used_inline_global_module(); + + (void)&extern_var_global_module; + (void)&inline_var_global_module; + (void)&static_var_global_module; + (void)&const_var_global_module; +} + +export module Module; + +export { + // FIXME: These should be ill-formed: you can't export an internal linkage + // symbol, per [dcl.module.interface]p2. + // CHECK: define void {{.*}}@_ZL22unused_static_exportedv + static void unused_static_exported() {} + // CHECK: define void {{.*}}@_ZL20used_static_exportedv + static void used_static_exported() {} + + inline void unused_inline_exported() {} + inline void used_inline_exported() {} + + extern int extern_var_exported; + inline int inline_var_exported; + // FIXME: This should be ill-formed: you can't export an internal linkage + // symbol. + static int static_var_exported; + const int const_var_exported = 3; + + // CHECK: define void {{.*}}@_Z18noninline_exportedv + void noninline_exported() { + used_static_exported(); + // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv + used_inline_exported(); + + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; + (void)&const_var_exported; + } +} + +// FIXME: Ideally we wouldn't emit this as its name is not visible outside this +// TU, but this module interface might contain a template that can use this +// function so we conservatively emit it for now. +// FIXME: The module name should be mangled into the name of this function. +// CHECK: define void {{.*}}@_ZL28unused_static_module_linkagev +static void unused_static_module_linkage() {} +// FIXME: The module name should be mangled into the name of this function. +// CHECK: define void {{.*}}@_ZL26used_static_module_linkagev +static void used_static_module_linkage() {} + +inline void unused_inline_module_linkage() {} +inline void used_inline_module_linkage() {} + +extern int extern_var_module_linkage; +inline int inline_var_module_linkage; +static int static_var_module_linkage; +const int const_var_module_linkage = 3; + +// FIXME: The module name should be mangled into the name of this function. +// CHECK: define void {{.*}}@_Z24noninline_module_linkagev +void noninline_module_linkage() { + used_static_module_linkage(); + // FIXME: The module name should be mangled into the name of this function. + // CHECK: define linkonce_odr {{.*}}@_Z26used_inline_module_linkagev + used_inline_module_linkage(); + + (void)&extern_var_module_linkage; + (void)&inline_var_module_linkage; + (void)&static_var_module_linkage; + (void)&const_var_module_linkage; +} diff --git a/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp new file mode 100644 index 000000000000..f6e0238c6b4b --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.def.odr/p4/user.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -fmodules-ts %S/module.cppm -triple %itanium_abi_triple -emit-module-interface -o %t +// RUN: %clang_cc1 -fmodules-ts %s -triple %itanium_abi_triple -fmodule-file=%t -emit-llvm -o - | FileCheck %s --implicit-check-not=unused --implicit-check-not=global_module + +// CHECK-DAG: @extern_var_exported = external global +// FIXME: Should this be 'external global'? +// CHECK-DAG: @inline_var_exported = linkonce_odr global +// FIXME: These should be 'extern global' and 'extern constant'. +// CHECK-DAG: @_ZL19static_var_exported = global +// CHECK-DAG: @const_var_exported = constant + +import Module; + +void use() { + // CHECK: define linkonce_odr {{.*}}@_Z20used_inline_exportedv + used_inline_exported(); + // CHECK: declare {{.*}}@_Z18noninline_exportedv + noninline_exported(); + + (void)&extern_var_exported; + (void)&inline_var_exported; + (void)&static_var_exported; + (void)&const_var_exported; + + // Module-linkage declarations are not visible here. +} diff --git a/test/CXX/modules-ts/basic/basic.link/p2/module.cpp b/test/CXX/modules-ts/basic/basic.link/p2/module.cpp new file mode 100644 index 000000000000..3fc6044d8e94 --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.link/p2/module.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++1z -fmodules-ts %S/module.cppm -emit-module-interface -o %t +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify +// expected-no-diagnostics +module M; + +// FIXME: Use of internal linkage entities should be rejected. +void use_from_module_impl() { + external_linkage_fn(); + module_linkage_fn(); + internal_linkage_fn(); + (void)external_linkage_class{}; + (void)module_linkage_class{}; + (void)internal_linkage_class{}; + (void)external_linkage_var; + (void)module_linkage_var; + (void)internal_linkage_var; +} diff --git a/test/CXX/modules-ts/basic/basic.link/p2/module.cppm b/test/CXX/modules-ts/basic/basic.link/p2/module.cppm new file mode 100644 index 000000000000..bb261700db84 --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.link/p2/module.cppm @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=c++1z -fmodules-ts %s -verify +// expected-no-diagnostics +export module M; + +export int external_linkage_var; +int module_linkage_var; +static int internal_linkage_var; + +export void external_linkage_fn() {} +void module_linkage_fn() {} +static void internal_linkage_fn() {} + +export struct external_linkage_class {}; +struct module_linkage_class {}; +namespace { + struct internal_linkage_class {}; +} + +void use() { + external_linkage_fn(); + module_linkage_fn(); + internal_linkage_fn(); + (void)external_linkage_class{}; + (void)module_linkage_class{}; + (void)internal_linkage_class{}; + (void)external_linkage_var; + (void)module_linkage_var; + (void)internal_linkage_var; +} diff --git a/test/CXX/modules-ts/basic/basic.link/p2/other.cpp b/test/CXX/modules-ts/basic/basic.link/p2/other.cpp new file mode 100644 index 000000000000..8370777e7ed4 --- /dev/null +++ b/test/CXX/modules-ts/basic/basic.link/p2/other.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -std=c++1z -fmodules-ts %S/module.cppm -emit-module-interface -o %t +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify +import M; + +void use_from_module_impl() { + external_linkage_fn(); + module_linkage_fn(); // expected-error {{undeclared identifier}} + internal_linkage_fn(); // expected-error {{undeclared identifier}} + (void)external_linkage_class{}; + (void)module_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} + (void)internal_linkage_class{}; // expected-error {{undeclared identifier}} expected-error 0+{{}} + // expected-note@module.cppm:9 {{here}} + (void)external_linkage_var; + (void)module_linkage_var; // expected-error {{undeclared identifier}} + (void)internal_linkage_var; // expected-error {{undeclared identifier}} +} diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp index aaf43d6584a4..aad31b4b46d1 100644 --- a/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp +++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp @@ -1,7 +1,7 @@ // RUN: rm -rf %t // RUN: mkdir -p %t -// RUN: echo 'export module x; int a, b;' > %t/x.cppm -// RUN: echo 'export module x.y; int c;' > %t/x.y.cppm +// RUN: echo 'export module x; export int a, b;' > %t/x.cppm +// RUN: echo 'export module x.y; export int c;' > %t/x.y.cppm // // RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %t/x.cppm -o %t/x.pcm // RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface -fmodule-file=%t/x.pcm %t/x.y.cppm -o %t/x.y.pcm diff --git a/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp b/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp new file mode 100644 index 000000000000..734b89173df9 --- /dev/null +++ b/test/CXX/modules-ts/dcl.dcl/dcl.module/p5.cpp @@ -0,0 +1,33 @@ +// RUN: rm -f %t +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -emit-module-interface %s -o %t -DINTERFACE +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DIMPLEMENTATION +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DEARLY_IMPLEMENTATION +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -fmodule-file=%t %s -verify -DUSER + +// expected-no-diagnostics + +#ifdef USER +import Foo; +#endif + +#ifdef EARLY_IMPLEMENTATION +module Foo; +#endif + +template<typename T> struct type_template { + typedef T type; + void f(type); +}; + +template<typename T> void type_template<T>::f(type) {} + +template<int = 0, typename = int, template<typename> class = type_template> +struct default_template_args {}; + +#ifdef INTERFACE +export module Foo; +#endif + +#ifdef IMPLEMENTATION +module Foo; +#endif diff --git a/test/CodeGen/aarch64-neon-intrinsics.c b/test/CodeGen/aarch64-neon-intrinsics.c index cbc2e72fcbac..bcb680c4b518 100644 --- a/test/CodeGen/aarch64-neon-intrinsics.c +++ b/test/CodeGen/aarch64-neon-intrinsics.c @@ -9037,9 +9037,10 @@ int64x2_t test_vld1q_s64(int64_t const *a) { // CHECK-LABEL: @test_vld1q_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>* -// CHECK: [[TMP2:%.*]] = load <8 x half>, <8 x half>* [[TMP1]] -// CHECK: ret <8 x half> [[TMP2]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x i16>* +// CHECK: [[TMP2:%.*]] = load <8 x i16>, <8 x i16>* [[TMP1]] +// CHECK: [[TMP3:%.*]] = bitcast <8 x i16> [[TMP2]] to <8 x half> +// CHECK: ret <8 x half> [[TMP3]] float16x8_t test_vld1q_f16(float16_t const *a) { return vld1q_f16(a); } @@ -9151,9 +9152,10 @@ int64x1_t test_vld1_s64(int64_t const *a) { // CHECK-LABEL: @test_vld1_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>* -// CHECK: [[TMP2:%.*]] = load <4 x half>, <4 x half>* [[TMP1]] -// CHECK: ret <4 x half> [[TMP2]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x i16>* +// CHECK: [[TMP2:%.*]] = load <4 x i16>, <4 x i16>* [[TMP1]] +// CHECK: [[TMP3:%.*]] = bitcast <4 x i16> [[TMP2]] to <4 x half> +// CHECK: ret <4 x half> [[TMP3]] float16x4_t test_vld1_f16(float16_t const *a) { return vld1_f16(a); } @@ -9340,10 +9342,10 @@ int64x2x2_t test_vld2q_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>* -// CHECK: [[VLD2:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2.v8f16.p0v8f16(<8 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half> } [[VLD2]], { <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>* +// CHECK: [[VLD2:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2.v8i16.p0v8i16(<8 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2]], { <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false) @@ -9571,10 +9573,10 @@ int64x1x2_t test_vld2_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>* -// CHECK: [[VLD2:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2.v4f16.p0v4f16(<4 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half> } [[VLD2]], { <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>* +// CHECK: [[VLD2:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0v4i16(<4 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2]], { <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false) @@ -9802,10 +9804,10 @@ int64x2x3_t test_vld3q_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>* -// CHECK: [[VLD3:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3.v8f16.p0v8f16(<8 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>* +// CHECK: [[VLD3:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3.v8i16.p0v8i16(<8 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false) @@ -10033,10 +10035,10 @@ int64x1x3_t test_vld3_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>* -// CHECK: [[VLD3:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3.v4f16.p0v4f16(<4 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>* +// CHECK: [[VLD3:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0v4i16(<4 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false) @@ -10264,10 +10266,10 @@ int64x2x4_t test_vld4q_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x half>* -// CHECK: [[VLD4:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4.v8f16.p0v8f16(<8 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <8 x i16>* +// CHECK: [[VLD4:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4.v8i16.p0v8i16(<8 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false) @@ -10495,10 +10497,10 @@ int64x1x4_t test_vld4_s64(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x half>* -// CHECK: [[VLD4:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4.v4f16.p0v4f16(<4 x half>* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to <4 x i16>* +// CHECK: [[VLD4:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0v4i16(<4 x i16>* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false) @@ -10664,9 +10666,9 @@ void test_vst1q_s64(int64_t *a, int64x2_t b) { // CHECK-LABEL: @test_vst1q_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <8 x half>* -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: store <8 x half> [[TMP3]], <8 x half>* [[TMP2]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <8 x i16>* +// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: store <8 x i16> [[TMP3]], <8 x i16>* [[TMP2]] // CHECK: ret void void test_vst1q_f16(float16_t *a, float16x8_t b) { vst1q_f16(a, b); @@ -10798,9 +10800,9 @@ void test_vst1_s64(int64_t *a, int64x1_t b) { // CHECK-LABEL: @test_vst1_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <4 x half>* -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: store <4 x half> [[TMP3]], <4 x half>* [[TMP2]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP0]] to <4 x i16>* +// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: store <4 x i16> [[TMP3]], <4 x i16>* [[TMP2]] // CHECK: ret void void test_vst1_f16(float16_t *a, float16x4_t b) { vst1_f16(a, b); @@ -11054,9 +11056,9 @@ void test_vst2q_s64(int64_t *a, int64x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st2.v8f16.p0i8(<8 x half> [[TMP7]], <8 x half> [[TMP8]], i8* [[TMP2]]) +// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st2.v8i16.p0i8(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i8* [[TMP2]]) // CHECK: ret void void test_vst2q_f16(float16_t *a, float16x8x2_t b) { vst2q_f16(a, b); @@ -11364,9 +11366,9 @@ void test_vst2_s64(int64_t *a, int64x1x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st2.v4f16.p0i8(<4 x half> [[TMP7]], <4 x half> [[TMP8]], i8* [[TMP2]]) +// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st2.v4i16.p0i8(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i8* [[TMP2]]) // CHECK: ret void void test_vst2_f16(float16_t *a, float16x4x2_t b) { vst2_f16(a, b); @@ -11714,10 +11716,10 @@ void test_vst3q_s64(int64_t *a, int64x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st3.v8f16.p0i8(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], i8* [[TMP2]]) +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st3.v8i16.p0i8(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i8* [[TMP2]]) // CHECK: ret void void test_vst3q_f16(float16_t *a, float16x8x3_t b) { vst3q_f16(a, b); @@ -12083,10 +12085,10 @@ void test_vst3_s64(int64_t *a, int64x1x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st3.v4f16.p0i8(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], i8* [[TMP2]]) +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st3.v4i16.p0i8(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i8* [[TMP2]]) // CHECK: ret void void test_vst3_f16(float16_t *a, float16x4x3_t b) { vst3_f16(a, b); @@ -12492,11 +12494,11 @@ void test_vst4q_s64(int64_t *a, int64x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st4.v8f16.p0i8(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], i8* [[TMP2]]) +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st4.v8i16.p0i8(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i8* [[TMP2]]) // CHECK: ret void void test_vst4q_f16(float16_t *a, float16x8x4_t b) { vst4q_f16(a, b); @@ -12920,11 +12922,11 @@ void test_vst4_s64(int64_t *a, int64x1x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st4.v4f16.p0i8(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], i8* [[TMP2]]) +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st4.v4i16.p0i8(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i8* [[TMP2]]) // CHECK: ret void void test_vst4_f16(float16_t *a, float16x4x4_t b) { vst4_f16(a, b); @@ -13206,10 +13208,10 @@ int64x2x2_t test_vld1q_s64_x2(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x2.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x2.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false) @@ -13452,10 +13454,10 @@ int64x1x2_t test_vld1_s64_x2(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x2.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x2.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false) @@ -13698,10 +13700,10 @@ int64x2x3_t test_vld1q_s64_x3(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x3.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x3.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false) @@ -13944,10 +13946,10 @@ int64x1x3_t test_vld1_s64_x3(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x3.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x3.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false) @@ -14190,10 +14192,10 @@ int64x2x4_t test_vld1q_s64_x4(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld1x4.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD1XN]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld1x4.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD1XN]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false) @@ -14436,10 +14438,10 @@ int64x1x4_t test_vld1_s64_x4(int64_t const *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD1XN:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld1x4.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD1XN]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD1XN:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x4.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD1XN]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false) @@ -14750,10 +14752,10 @@ void test_vst1q_s64_x2(int64_t *a, int64x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x2.v8f16.p0f16(<8 x half> [[TMP7]], <8 x half> [[TMP8]], half* [[TMP9]]) +// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x2.v8i16.p0i16(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i16* [[TMP9]]) // CHECK: ret void void test_vst1q_f16_x2(float16_t *a, float16x8x2_t b) { vst1q_f16_x2(a, b); @@ -15096,10 +15098,10 @@ void test_vst1_s64_x2(int64_t *a, int64x1x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x2.v4f16.p0f16(<4 x half> [[TMP7]], <4 x half> [[TMP8]], half* [[TMP9]]) +// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP9:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x2.v4i16.p0i16(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i16* [[TMP9]]) // CHECK: ret void void test_vst1_f16_x2(float16_t *a, float16x4x2_t b) { vst1_f16_x2(a, b); @@ -15482,11 +15484,11 @@ void test_vst1q_s64_x3(int64_t *a, int64x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x3.v8f16.p0f16(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], half* [[TMP12]]) +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x3.v8i16.p0i16(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i16* [[TMP12]]) // CHECK: ret void void test_vst1q_f16_x3(float16_t *a, float16x8x3_t b) { vst1q_f16_x3(a, b); @@ -15892,11 +15894,11 @@ void test_vst1_s64_x3(int64_t *a, int64x1x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x3.v4f16.p0f16(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], half* [[TMP12]]) +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x3.v4i16.p0i16(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i16* [[TMP12]]) // CHECK: ret void void test_vst1_f16_x3(float16_t *a, float16x4x3_t b) { vst1_f16_x3(a, b); @@ -16342,12 +16344,12 @@ void test_vst1q_s64_x4(int64_t *a, int64x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half> -// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x4.v8f16.p0f16(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], half* [[TMP15]]) +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16> +// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x4.v8i16.p0i16(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i16* [[TMP15]]) // CHECK: ret void void test_vst1q_f16_x4(float16_t *a, float16x8x4_t b) { vst1q_f16_x4(a, b); @@ -16816,12 +16818,12 @@ void test_vst1_s64_x4(int64_t *a, int64x1x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half> -// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to half* -// CHECK: call void @llvm.aarch64.neon.st1x4.v4f16.p0f16(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], half* [[TMP15]]) +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> +// CHECK: [[TMP15:%.*]] = bitcast i8* [[TMP2]] to i16* +// CHECK: call void @llvm.aarch64.neon.st1x4.v4i16.p0i16(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i16* [[TMP15]]) // CHECK: ret void void test_vst1_f16_x4(float16_t *a, float16x4x4_t b) { vst1_f16_x4(a, b); diff --git a/test/CodeGen/aarch64-neon-ldst-one.c b/test/CodeGen/aarch64-neon-ldst-one.c index a3c5b140a0d2..9bd9ab1cb61b 100644 --- a/test/CodeGen/aarch64-neon-ldst-one.c +++ b/test/CodeGen/aarch64-neon-ldst-one.c @@ -90,11 +90,12 @@ int64x2_t test_vld1q_dup_s64(int64_t *a) { // CHECK-LABEL: define <8 x half> @test_vld1q_dup_f16(half* %a) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]] -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> undef, half [[TMP2]], i32 0 -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP3]], <8 x half> [[TMP3]], <8 x i32> zeroinitializer -// CHECK: ret <8 x half> [[LANE]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]] +// CHECK: [[TMP3:%.*]] = insertelement <8 x i16> undef, i16 [[TMP2]], i32 0 +// CHECK: [[LANE:%.*]] = shufflevector <8 x i16> [[TMP3]], <8 x i16> [[TMP3]], <8 x i32> zeroinitializer +// CHECK: [[TMP4:%.*]] = bitcast <8 x i16> [[LANE]] to <8 x half> +// CHECK: ret <8 x half> [[TMP4]] float16x8_t test_vld1q_dup_f16(float16_t *a) { return vld1q_dup_f16(a); } @@ -238,11 +239,12 @@ int64x1_t test_vld1_dup_s64(int64_t *a) { // CHECK-LABEL: define <4 x half> @test_vld1_dup_f16(half* %a) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]] -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> undef, half [[TMP2]], i32 0 -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> zeroinitializer -// CHECK: ret <4 x half> [[LANE]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]] +// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[TMP2]], i32 0 +// CHECK: [[LANE:%.*]] = shufflevector <4 x i16> [[TMP3]], <4 x i16> [[TMP3]], <4 x i32> zeroinitializer +// CHECK: [[TMP4:%.*]] = bitcast <4 x i16> [[LANE]] to <4 x half> +// CHECK: ret <4 x half> [[TMP4]] float16x4_t test_vld1_dup_f16(float16_t *a) { return vld1_dup_f16(a); } @@ -445,10 +447,10 @@ int64x2x2_t test_vld2q_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD2:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2r.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half> } [[VLD2]], { <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD2:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2r.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2]], { <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 16, i1 false) @@ -691,10 +693,10 @@ int64x1x2_t test_vld2_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD2:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2r.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half> } [[VLD2]], { <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD2:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2r.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2]], { <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 16, i32 8, i1 false) @@ -945,10 +947,10 @@ int64x2x3_t test_vld3q_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD3:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3r.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD3:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3r.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 48, i32 16, i1 false) @@ -1205,10 +1207,10 @@ int64x1x3_t test_vld3_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD3:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3r.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD3:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3r.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 24, i32 8, i1 false) @@ -1457,10 +1459,10 @@ int64x2x4_t test_vld4q_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD4:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4r.v8f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD4:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4r.v8i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 64, i32 16, i1 false) @@ -1703,10 +1705,10 @@ int64x1x4_t test_vld4_dup_s64(int64_t *a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to half* -// CHECK: [[VLD4:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4r.v4f16.p0f16(half* [[TMP2]]) -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP3]] +// CHECK: [[TMP2:%.*]] = bitcast i8* [[TMP1]] to i16* +// CHECK: [[VLD4:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4r.v4i16.p0i16(i16* [[TMP2]]) +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP3]] // CHECK: [[TMP4:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8* // CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP4]], i8* [[TMP5]], i64 32, i32 8, i1 false) @@ -1895,11 +1897,12 @@ int64x2_t test_vld1q_lane_s64(int64_t *a, int64x2_t b) { // CHECK-LABEL: define <8 x half> @test_vld1q_lane_f16(half* %a, <8 x half> %b) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]] -// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x half> [[TMP2]], half [[TMP4]], i32 7 -// CHECK: ret <8 x half> [[VLD1_LANE]] +// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]] +// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x i16> [[TMP2]], i16 [[TMP4]], i32 7 +// CHECK: [[TMP5:%.*]] = bitcast <8 x i16> [[VLD1_LANE]] to <8 x half> +// CHECK: ret <8 x half> [[TMP5]] float16x8_t test_vld1q_lane_f16(float16_t *a, float16x8_t b) { return vld1q_lane_f16(a, b, 7); } @@ -2051,11 +2054,12 @@ int64x1_t test_vld1_lane_s64(int64_t *a, int64x1_t b) { // CHECK-LABEL: define <4 x half> @test_vld1_lane_f16(half* %a, <4 x half> %b) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]] -// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x half> [[TMP2]], half [[TMP4]], i32 3 -// CHECK: ret <4 x half> [[VLD1_LANE]] +// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]] +// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x i16> [[TMP2]], i16 [[TMP4]], i32 3 +// CHECK: [[TMP5:%.*]] = bitcast <4 x i16> [[VLD1_LANE]] to <4 x half> +// CHECK: ret <4 x half> [[TMP5]] float16x4_t test_vld1_lane_f16(float16_t *a, float16x4_t b) { return vld1_lane_f16(a, b, 3); } @@ -2491,11 +2495,11 @@ int64x2x2_t test_vld2q_lane_s64(int64_t *a, int64x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[VLD2_LANE:%.*]] = call { <8 x half>, <8 x half> } @llvm.aarch64.neon.ld2lane.v8f16.p0i8(<8 x half> [[TMP8]], <8 x half> [[TMP9]], i64 7, i8* [[TMP3]]) -// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half> } [[VLD2_LANE]], { <8 x half>, <8 x half> }* [[TMP10]] +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[VLD2_LANE:%.*]] = call { <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld2lane.v8i16.p0i8(<8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i64 7, i8* [[TMP3]]) +// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16> } [[VLD2_LANE]], { <8 x i16>, <8 x i16> }* [[TMP10]] // CHECK: [[TMP11:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* // CHECK: [[TMP12:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP11]], i8* [[TMP12]], i64 32, i32 16, i1 false) @@ -2923,11 +2927,11 @@ int64x1x2_t test_vld2_lane_s64(int64_t *a, int64x1x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[VLD2_LANE:%.*]] = call { <4 x half>, <4 x half> } @llvm.aarch64.neon.ld2lane.v4f16.p0i8(<4 x half> [[TMP8]], <4 x half> [[TMP9]], i64 3, i8* [[TMP3]]) -// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half> } [[VLD2_LANE]], { <4 x half>, <4 x half> }* [[TMP10]] +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[VLD2_LANE:%.*]] = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2lane.v4i16.p0i8(<4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i64 3, i8* [[TMP3]]) +// CHECK: [[TMP10:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16> } [[VLD2_LANE]], { <4 x i16>, <4 x i16> }* [[TMP10]] // CHECK: [[TMP11:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* // CHECK: [[TMP12:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP11]], i8* [[TMP12]], i64 16, i32 8, i1 false) @@ -3360,12 +3364,12 @@ int64x2x3_t test_vld3q_lane_s64(int64_t *a, int64x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: [[VLD3_LANE:%.*]] = call { <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld3lane.v8f16.p0i8(<8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i64 7, i8* [[TMP3]]) -// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half> } [[VLD3_LANE]], { <8 x half>, <8 x half>, <8 x half> }* [[TMP13]] +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: [[VLD3_LANE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld3lane.v8i16.p0i8(<8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i64 7, i8* [[TMP3]]) +// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16> } [[VLD3_LANE]], { <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP13]] // CHECK: [[TMP14:%.*]] = bitcast %struct.float16x8x3_t* [[RETVAL]] to i8* // CHECK: [[TMP15:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP14]], i8* [[TMP15]], i64 48, i32 16, i1 false) @@ -3885,12 +3889,12 @@ int64x1x3_t test_vld3_lane_s64(int64_t *a, int64x1x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: [[VLD3_LANE:%.*]] = call { <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld3lane.v4f16.p0i8(<4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i64 3, i8* [[TMP3]]) -// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half> } [[VLD3_LANE]], { <4 x half>, <4 x half>, <4 x half> }* [[TMP13]] +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: [[VLD3_LANE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3lane.v4i16.p0i8(<4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i64 3, i8* [[TMP3]]) +// CHECK: [[TMP13:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16> } [[VLD3_LANE]], { <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP13]] // CHECK: [[TMP14:%.*]] = bitcast %struct.float16x4x3_t* [[RETVAL]] to i8* // CHECK: [[TMP15:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP14]], i8* [[TMP15]], i64 24, i32 8, i1 false) @@ -4450,13 +4454,13 @@ int64x2x4_t test_vld4q_lane_s64(int64_t *a, int64x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half> -// CHECK: [[VLD4_LANE:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.aarch64.neon.ld4lane.v8f16.p0i8(<8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i64 7, i8* [[TMP3]]) -// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* -// CHECK: store { <8 x half>, <8 x half>, <8 x half>, <8 x half> } [[VLD4_LANE]], { <8 x half>, <8 x half>, <8 x half>, <8 x half> }* [[TMP16]] +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16> +// CHECK: [[VLD4_LANE:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.aarch64.neon.ld4lane.v8i16.p0i8(<8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i64 7, i8* [[TMP3]]) +// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* +// CHECK: store { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } [[VLD4_LANE]], { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> }* [[TMP16]] // CHECK: [[TMP17:%.*]] = bitcast %struct.float16x8x4_t* [[RETVAL]] to i8* // CHECK: [[TMP18:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP17]], i8* [[TMP18]], i64 64, i32 16, i1 false) @@ -5039,13 +5043,13 @@ int64x1x4_t test_vld4_lane_s64(int64_t *a, int64x1x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half> -// CHECK: [[VLD4_LANE:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> } @llvm.aarch64.neon.ld4lane.v4f16.p0i8(<4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i64 3, i8* [[TMP3]]) -// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* -// CHECK: store { <4 x half>, <4 x half>, <4 x half>, <4 x half> } [[VLD4_LANE]], { <4 x half>, <4 x half>, <4 x half>, <4 x half> }* [[TMP16]] +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16> +// CHECK: [[VLD4_LANE:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4lane.v4i16.p0i8(<4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i64 3, i8* [[TMP3]]) +// CHECK: [[TMP16:%.*]] = bitcast i8* [[TMP2]] to { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* +// CHECK: store { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } [[VLD4_LANE]], { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> }* [[TMP16]] // CHECK: [[TMP17:%.*]] = bitcast %struct.float16x4x4_t* [[RETVAL]] to i8* // CHECK: [[TMP18:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP17]], i8* [[TMP18]], i64 32, i32 8, i1 false) @@ -5357,10 +5361,10 @@ void test_vst1q_lane_s64(int64_t *a, int64x2_t b) { // CHECK-LABEL: define void @test_vst1q_lane_f16(half* %a, <8 x half> %b) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP3:%.*]] = extractelement <8 x half> [[TMP2]], i32 7 -// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: store half [[TMP3]], half* [[TMP4]] +// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: [[TMP3:%.*]] = extractelement <8 x i16> [[TMP2]], i32 7 +// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: store i16 [[TMP3]], i16* [[TMP4]] // CHECK: ret void void test_vst1q_lane_f16(float16_t *a, float16x8_t b) { vst1q_lane_f16(a, b, 7); @@ -5513,10 +5517,10 @@ void test_vst1_lane_s64(int64_t *a, int64x1_t b) { // CHECK-LABEL: define void @test_vst1_lane_f16(half* %a, <4 x half> %b) #0 { // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP3:%.*]] = extractelement <4 x half> [[TMP2]], i32 3 -// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: store half [[TMP3]], half* [[TMP4]] +// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: [[TMP3:%.*]] = extractelement <4 x i16> [[TMP2]], i32 3 +// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: store i16 [[TMP3]], i16* [[TMP4]] // CHECK: ret void void test_vst1_lane_f16(float16_t *a, float16x4_t b) { vst1_lane_f16(a, b, 3); @@ -5785,9 +5789,9 @@ void test_vst2q_lane_s64(int64_t *a, int64x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP6:%.*]] = bitcast <8 x half> [[TMP5]] to <16 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st2lane.v8f16.p0i8(<8 x half> [[TMP7]], <8 x half> [[TMP8]], i64 7, i8* [[TMP2]]) +// CHECK: [[TMP7:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st2lane.v8i16.p0i8(<8 x i16> [[TMP7]], <8 x i16> [[TMP8]], i64 7, i8* [[TMP2]]) // CHECK: ret void void test_vst2q_lane_f16(float16_t *a, float16x8x2_t b) { vst2q_lane_f16(a, b, 7); @@ -6120,9 +6124,9 @@ void test_vst2_lane_s64(int64_t *a, int64x1x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i64 0, i64 1 // CHECK: [[TMP5:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP6:%.*]] = bitcast <4 x half> [[TMP5]] to <8 x i8> -// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st2lane.v4f16.p0i8(<4 x half> [[TMP7]], <4 x half> [[TMP8]], i64 3, i8* [[TMP2]]) +// CHECK: [[TMP7:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st2lane.v4i16.p0i8(<4 x i16> [[TMP7]], <4 x i16> [[TMP8]], i64 3, i8* [[TMP2]]) // CHECK: ret void void test_vst2_lane_f16(float16_t *a, float16x4x2_t b) { vst2_lane_f16(a, b, 3); @@ -6495,10 +6499,10 @@ void test_vst3q_lane_s64(int64_t *a, int64x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st3lane.v8f16.p0i8(<8 x half> [[TMP9]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], i64 7, i8* [[TMP2]]) +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st3lane.v8i16.p0i8(<8 x i16> [[TMP9]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], i64 7, i8* [[TMP2]]) // CHECK: ret void void test_vst3q_lane_f16(float16_t *a, float16x8x3_t b) { vst3q_lane_f16(a, b, 7); @@ -6894,10 +6898,10 @@ void test_vst3_lane_s64(int64_t *a, int64x1x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i64 0, i64 2 // CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st3lane.v4f16.p0i8(<4 x half> [[TMP9]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], i64 3, i8* [[TMP2]]) +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st3lane.v4i16.p0i8(<4 x i16> [[TMP9]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], i64 3, i8* [[TMP2]]) // CHECK: ret void void test_vst3_lane_f16(float16_t *a, float16x4x3_t b) { vst3_lane_f16(a, b, 3); @@ -7333,11 +7337,11 @@ void test_vst4q_lane_s64(int64_t *a, int64x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half> -// CHECK: call void @llvm.aarch64.neon.st4lane.v8f16.p0i8(<8 x half> [[TMP11]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], i64 7, i8* [[TMP2]]) +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP4]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16> +// CHECK: call void @llvm.aarch64.neon.st4lane.v8i16.p0i8(<8 x i16> [[TMP11]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], i64 7, i8* [[TMP2]]) // CHECK: ret void void test_vst4q_lane_f16(float16_t *a, float16x8x4_t b) { vst4q_lane_f16(a, b, 7); @@ -7796,11 +7800,11 @@ void test_vst4_lane_s64(int64_t *a, int64x1x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i64 0, i64 3 // CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half> -// CHECK: call void @llvm.aarch64.neon.st4lane.v4f16.p0i8(<4 x half> [[TMP11]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], i64 3, i8* [[TMP2]]) +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP4]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> +// CHECK: call void @llvm.aarch64.neon.st4lane.v4i16.p0i8(<4 x i16> [[TMP11]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], i64 3, i8* [[TMP2]]) // CHECK: ret void void test_vst4_lane_f16(float16_t *a, float16x4x4_t b) { vst4_lane_f16(a, b, 3); diff --git a/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c b/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c deleted file mode 100644 index 3f61238b64fb..000000000000 --- a/test/CodeGen/aarch64-v8.2a-neon-intrinsics.c +++ /dev/null @@ -1,1633 +0,0 @@ -// RUN: %clang_cc1 -triple arm64-none-linux-gnu -target-feature +neon -target-feature +fullfp16 -target-feature +v8.2a\ -// RUN: -fallow-half-arguments-and-returns -S -disable-O0-optnone -emit-llvm -o - %s \ -// RUN: | opt -S -mem2reg \ -// RUN: | FileCheck %s - -// REQUIRES: aarch64-registered-target - -#include <arm_neon.h> - -// CHECK-LABEL: test_vabs_f16 -// CHECK: [[ABS:%.*]] = call <4 x half> @llvm.fabs.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[ABS]] -float16x4_t test_vabs_f16(float16x4_t a) { - return vabs_f16(a); -} - -// CHECK-LABEL: test_vabsq_f16 -// CHECK: [[ABS:%.*]] = call <8 x half> @llvm.fabs.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[ABS]] -float16x8_t test_vabsq_f16(float16x8_t a) { - return vabsq_f16(a); -} - -// CHECK-LABEL: test_vceqz_f16 -// CHECK: [[TMP1:%.*]] = fcmp oeq <4 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vceqz_f16(float16x4_t a) { - return vceqz_f16(a); -} - -// CHECK-LABEL: test_vceqzq_f16 -// CHECK: [[TMP1:%.*]] = fcmp oeq <8 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vceqzq_f16(float16x8_t a) { - return vceqzq_f16(a); -} - -// CHECK-LABEL: test_vcgez_f16 -// CHECK: [[TMP1:%.*]] = fcmp oge <4 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcgez_f16(float16x4_t a) { - return vcgez_f16(a); -} - -// CHECK-LABEL: test_vcgezq_f16 -// CHECK: [[TMP1:%.*]] = fcmp oge <8 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcgezq_f16(float16x8_t a) { - return vcgezq_f16(a); -} - -// CHECK-LABEL: test_vcgtz_f16 -// CHECK: [[TMP1:%.*]] = fcmp ogt <4 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcgtz_f16(float16x4_t a) { - return vcgtz_f16(a); -} - -// CHECK-LABEL: test_vcgtzq_f16 -// CHECK: [[TMP1:%.*]] = fcmp ogt <8 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcgtzq_f16(float16x8_t a) { - return vcgtzq_f16(a); -} - -// CHECK-LABEL: test_vclez_f16 -// CHECK: [[TMP1:%.*]] = fcmp ole <4 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vclez_f16(float16x4_t a) { - return vclez_f16(a); -} - -// CHECK-LABEL: test_vclezq_f16 -// CHECK: [[TMP1:%.*]] = fcmp ole <8 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vclezq_f16(float16x8_t a) { - return vclezq_f16(a); -} - -// CHECK-LABEL: test_vcltz_f16 -// CHECK: [[TMP1:%.*]] = fcmp olt <4 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcltz_f16(float16x4_t a) { - return vcltz_f16(a); -} - -// CHECK-LABEL: test_vcltzq_f16 -// CHECK: [[TMP1:%.*]] = fcmp olt <8 x half> %a, zeroinitializer -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcltzq_f16(float16x8_t a) { - return vcltzq_f16(a); -} - -// CHECK-LABEL: test_vcvt_f16_s16 -// CHECK: [[VCVT:%.*]] = sitofp <4 x i16> %a to <4 x half> -// CHECK: ret <4 x half> [[VCVT]] -float16x4_t test_vcvt_f16_s16 (int16x4_t a) { - return vcvt_f16_s16(a); -} - -// CHECK-LABEL: test_vcvtq_f16_s16 -// CHECK: [[VCVT:%.*]] = sitofp <8 x i16> %a to <8 x half> -// CHECK: ret <8 x half> [[VCVT]] -float16x8_t test_vcvtq_f16_s16 (int16x8_t a) { - return vcvtq_f16_s16(a); -} - -// CHECK-LABEL: test_vcvt_f16_u16 -// CHECK: [[VCVT:%.*]] = uitofp <4 x i16> %a to <4 x half> -// CHECK: ret <4 x half> [[VCVT]] -float16x4_t test_vcvt_f16_u16 (uint16x4_t a) { - return vcvt_f16_u16(a); -} - -// CHECK-LABEL: test_vcvtq_f16_u16 -// CHECK: [[VCVT:%.*]] = uitofp <8 x i16> %a to <8 x half> -// CHECK: ret <8 x half> [[VCVT]] -float16x8_t test_vcvtq_f16_u16 (uint16x8_t a) { - return vcvtq_f16_u16(a); -} - -// CHECK-LABEL: test_vcvt_s16_f16 -// CHECK: [[VCVT:%.*]] = fptosi <4 x half> %a to <4 x i16> -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvt_s16_f16 (float16x4_t a) { - return vcvt_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtq_s16_f16 -// CHECK: [[VCVT:%.*]] = fptosi <8 x half> %a to <8 x i16> -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtq_s16_f16 (float16x8_t a) { - return vcvtq_s16_f16(a); -} - -// CHECK-LABEL: test_vcvt_u16_f16 -// CHECK: [[VCVT:%.*]] = fptoui <4 x half> %a to <4 x i16> -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvt_u16_f16 (float16x4_t a) { - return vcvt_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtq_u16_f16 -// CHECK: [[VCVT:%.*]] = fptoui <8 x half> %a to <8 x i16> -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtq_u16_f16 (float16x8_t a) { - return vcvtq_u16_f16(a); -} - -// CHECK-LABEL: test_vcvta_s16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtas.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvta_s16_f16 (float16x4_t a) { - return vcvta_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtaq_s16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtas.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtaq_s16_f16 (float16x8_t a) { - return vcvtaq_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtm_s16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtms.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvtm_s16_f16 (float16x4_t a) { - return vcvtm_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtmq_s16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtms.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtmq_s16_f16 (float16x8_t a) { - return vcvtmq_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtm_u16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtmu.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -uint16x4_t test_vcvtm_u16_f16 (float16x4_t a) { - return vcvtm_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtmq_u16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtmu.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -uint16x8_t test_vcvtmq_u16_f16 (float16x8_t a) { - return vcvtmq_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtn_s16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtns.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvtn_s16_f16 (float16x4_t a) { - return vcvtn_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtnq_s16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtns.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtnq_s16_f16 (float16x8_t a) { - return vcvtnq_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtn_u16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtnu.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -uint16x4_t test_vcvtn_u16_f16 (float16x4_t a) { - return vcvtn_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtnq_u16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtnu.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -uint16x8_t test_vcvtnq_u16_f16 (float16x8_t a) { - return vcvtnq_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtp_s16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtps.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -int16x4_t test_vcvtp_s16_f16 (float16x4_t a) { - return vcvtp_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtpq_s16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtps.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -int16x8_t test_vcvtpq_s16_f16 (float16x8_t a) { - return vcvtpq_s16_f16(a); -} - -// CHECK-LABEL: test_vcvtp_u16_f16 -// CHECK: [[VCVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.fcvtpu.v4i16.v4f16(<4 x half> %a) -// CHECK: ret <4 x i16> [[VCVT]] -uint16x4_t test_vcvtp_u16_f16 (float16x4_t a) { - return vcvtp_u16_f16(a); -} - -// CHECK-LABEL: test_vcvtpq_u16_f16 -// CHECK: [[VCVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.fcvtpu.v8i16.v8f16(<8 x half> %a) -// CHECK: ret <8 x i16> [[VCVT]] -uint16x8_t test_vcvtpq_u16_f16 (float16x8_t a) { - return vcvtpq_u16_f16(a); -} - -// FIXME: Fix the zero constant when fp16 non-storage-only type becomes available. -// CHECK-LABEL: test_vneg_f16 -// CHECK: [[NEG:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %a -// CHECK: ret <4 x half> [[NEG]] -float16x4_t test_vneg_f16(float16x4_t a) { - return vneg_f16(a); -} - -// CHECK-LABEL: test_vnegq_f16 -// CHECK: [[NEG:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %a -// CHECK: ret <8 x half> [[NEG]] -float16x8_t test_vnegq_f16(float16x8_t a) { - return vnegq_f16(a); -} - -// CHECK-LABEL: test_vrecpe_f16 -// CHECK: [[RCP:%.*]] = call <4 x half> @llvm.aarch64.neon.frecpe.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RCP]] -float16x4_t test_vrecpe_f16(float16x4_t a) { - return vrecpe_f16(a); -} - -// CHECK-LABEL: test_vrecpeq_f16 -// CHECK: [[RCP:%.*]] = call <8 x half> @llvm.aarch64.neon.frecpe.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RCP]] -float16x8_t test_vrecpeq_f16(float16x8_t a) { - return vrecpeq_f16(a); -} - -// CHECK-LABEL: test_vrnd_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.trunc.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrnd_f16(float16x4_t a) { - return vrnd_f16(a); -} - -// CHECK-LABEL: test_vrndq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.trunc.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndq_f16(float16x8_t a) { - return vrndq_f16(a); -} - -// CHECK-LABEL: test_vrnda_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.round.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrnda_f16(float16x4_t a) { - return vrnda_f16(a); -} - -// CHECK-LABEL: test_vrndaq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.round.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndaq_f16(float16x8_t a) { - return vrndaq_f16(a); -} - -// CHECK-LABEL: test_vrndi_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.nearbyint.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrndi_f16(float16x4_t a) { - return vrndi_f16(a); -} - -// CHECK-LABEL: test_vrndiq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.nearbyint.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndiq_f16(float16x8_t a) { - return vrndiq_f16(a); -} - -// CHECK-LABEL: test_vrndm_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.floor.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrndm_f16(float16x4_t a) { - return vrndm_f16(a); -} - -// CHECK-LABEL: test_vrndmq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.floor.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndmq_f16(float16x8_t a) { - return vrndmq_f16(a); -} - -// CHECK-LABEL: test_vrndn_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.aarch64.neon.frintn.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrndn_f16(float16x4_t a) { - return vrndn_f16(a); -} - -// CHECK-LABEL: test_vrndnq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.aarch64.neon.frintn.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndnq_f16(float16x8_t a) { - return vrndnq_f16(a); -} - -// CHECK-LABEL: test_vrndp_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.ceil.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrndp_f16(float16x4_t a) { - return vrndp_f16(a); -} - -// CHECK-LABEL: test_vrndpq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.ceil.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndpq_f16(float16x8_t a) { - return vrndpq_f16(a); -} - -// CHECK-LABEL: test_vrndx_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.rint.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrndx_f16(float16x4_t a) { - return vrndx_f16(a); -} - -// CHECK-LABEL: test_vrndxq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.rint.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrndxq_f16(float16x8_t a) { - return vrndxq_f16(a); -} - -// CHECK-LABEL: test_vrsqrte_f16 -// CHECK: [[RND:%.*]] = call <4 x half> @llvm.aarch64.neon.frsqrte.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[RND]] -float16x4_t test_vrsqrte_f16(float16x4_t a) { - return vrsqrte_f16(a); -} - -// CHECK-LABEL: test_vrsqrteq_f16 -// CHECK: [[RND:%.*]] = call <8 x half> @llvm.aarch64.neon.frsqrte.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[RND]] -float16x8_t test_vrsqrteq_f16(float16x8_t a) { - return vrsqrteq_f16(a); -} - -// CHECK-LABEL: test_vsqrt_f16 -// CHECK: [[SQR:%.*]] = call <4 x half> @llvm.sqrt.v4f16(<4 x half> %a) -// CHECK: ret <4 x half> [[SQR]] -float16x4_t test_vsqrt_f16(float16x4_t a) { - return vsqrt_f16(a); -} - -// CHECK-LABEL: test_vsqrtq_f16 -// CHECK: [[SQR:%.*]] = call <8 x half> @llvm.sqrt.v8f16(<8 x half> %a) -// CHECK: ret <8 x half> [[SQR]] -float16x8_t test_vsqrtq_f16(float16x8_t a) { - return vsqrtq_f16(a); -} - -// CHECK-LABEL: test_vadd_f16 -// CHECK: [[ADD:%.*]] = fadd <4 x half> %a, %b -// CHECK: ret <4 x half> [[ADD]] -float16x4_t test_vadd_f16(float16x4_t a, float16x4_t b) { - return vadd_f16(a, b); -} - -// CHECK-LABEL: test_vaddq_f16 -// CHECK: [[ADD:%.*]] = fadd <8 x half> %a, %b -// CHECK: ret <8 x half> [[ADD]] -float16x8_t test_vaddq_f16(float16x8_t a, float16x8_t b) { - return vaddq_f16(a, b); -} - -// CHECK-LABEL: test_vabd_f16 -// CHECK: [[ABD:%.*]] = call <4 x half> @llvm.aarch64.neon.fabd.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[ABD]] -float16x4_t test_vabd_f16(float16x4_t a, float16x4_t b) { - return vabd_f16(a, b); -} - -// CHECK-LABEL: test_vabdq_f16 -// CHECK: [[ABD:%.*]] = call <8 x half> @llvm.aarch64.neon.fabd.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[ABD]] -float16x8_t test_vabdq_f16(float16x8_t a, float16x8_t b) { - return vabdq_f16(a, b); -} - -// CHECK-LABEL: test_vcage_f16 -// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facge.v4i16.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x i16> [[ABS]] -uint16x4_t test_vcage_f16(float16x4_t a, float16x4_t b) { - return vcage_f16(a, b); -} - -// CHECK-LABEL: test_vcageq_f16 -// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facge.v8i16.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x i16> [[ABS]] -uint16x8_t test_vcageq_f16(float16x8_t a, float16x8_t b) { - return vcageq_f16(a, b); -} - -// CHECK-LABEL: test_vcagt_f16 -// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facgt.v4i16.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x i16> [[ABS]] -uint16x4_t test_vcagt_f16(float16x4_t a, float16x4_t b) { - return vcagt_f16(a, b); -} - -// CHECK-LABEL: test_vcagtq_f16 -// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facgt.v8i16.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x i16> [[ABS]] -uint16x8_t test_vcagtq_f16(float16x8_t a, float16x8_t b) { - return vcagtq_f16(a, b); -} - -// CHECK-LABEL: test_vcale_f16 -// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facge.v4i16.v4f16(<4 x half> %b, <4 x half> %a) -// CHECK: ret <4 x i16> [[ABS]] -uint16x4_t test_vcale_f16(float16x4_t a, float16x4_t b) { - return vcale_f16(a, b); -} - -// CHECK-LABEL: test_vcaleq_f16 -// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facge.v8i16.v8f16(<8 x half> %b, <8 x half> %a) -// CHECK: ret <8 x i16> [[ABS]] -uint16x8_t test_vcaleq_f16(float16x8_t a, float16x8_t b) { - return vcaleq_f16(a, b); -} - -// CHECK-LABEL: test_vcalt_f16 -// CHECK: [[ABS:%.*]] = call <4 x i16> @llvm.aarch64.neon.facgt.v4i16.v4f16(<4 x half> %b, <4 x half> %a) -// CHECK: ret <4 x i16> [[ABS]] -uint16x4_t test_vcalt_f16(float16x4_t a, float16x4_t b) { - return vcalt_f16(a, b); -} - -// CHECK-LABEL: test_vcaltq_f16 -// CHECK: [[ABS:%.*]] = call <8 x i16> @llvm.aarch64.neon.facgt.v8i16.v8f16(<8 x half> %b, <8 x half> %a) -// CHECK: ret <8 x i16> [[ABS]] -uint16x8_t test_vcaltq_f16(float16x8_t a, float16x8_t b) { - return vcaltq_f16(a, b); -} - -// CHECK-LABEL: test_vceq_f16 -// CHECK: [[TMP1:%.*]] = fcmp oeq <4 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vceq_f16(float16x4_t a, float16x4_t b) { - return vceq_f16(a, b); -} - -// CHECK-LABEL: test_vceqq_f16 -// CHECK: [[TMP1:%.*]] = fcmp oeq <8 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vceqq_f16(float16x8_t a, float16x8_t b) { - return vceqq_f16(a, b); -} - -// CHECK-LABEL: test_vcge_f16 -// CHECK: [[TMP1:%.*]] = fcmp oge <4 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcge_f16(float16x4_t a, float16x4_t b) { - return vcge_f16(a, b); -} - -// CHECK-LABEL: test_vcgeq_f16 -// CHECK: [[TMP1:%.*]] = fcmp oge <8 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcgeq_f16(float16x8_t a, float16x8_t b) { - return vcgeq_f16(a, b); -} - -// CHECK-LABEL: test_vcgt_f16 -// CHECK: [[TMP1:%.*]] = fcmp ogt <4 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcgt_f16(float16x4_t a, float16x4_t b) { - return vcgt_f16(a, b); -} - -// CHECK-LABEL: test_vcgtq_f16 -// CHECK: [[TMP1:%.*]] = fcmp ogt <8 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcgtq_f16(float16x8_t a, float16x8_t b) { - return vcgtq_f16(a, b); -} - -// CHECK-LABEL: test_vcle_f16 -// CHECK: [[TMP1:%.*]] = fcmp ole <4 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vcle_f16(float16x4_t a, float16x4_t b) { - return vcle_f16(a, b); -} - -// CHECK-LABEL: test_vcleq_f16 -// CHECK: [[TMP1:%.*]] = fcmp ole <8 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcleq_f16(float16x8_t a, float16x8_t b) { - return vcleq_f16(a, b); -} - -// CHECK-LABEL: test_vclt_f16 -// CHECK: [[TMP1:%.*]] = fcmp olt <4 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <4 x i1> [[TMP1]] to <4 x i16> -// CHECK: ret <4 x i16> [[TMP2]] -uint16x4_t test_vclt_f16(float16x4_t a, float16x4_t b) { - return vclt_f16(a, b); -} - -// CHECK-LABEL: test_vcltq_f16 -// CHECK: [[TMP1:%.*]] = fcmp olt <8 x half> %a, %b -// CHECK: [[TMP2:%.*]] = sext <8 x i1> [[TMP1:%.*]] to <8 x i16> -// CHECK: ret <8 x i16> [[TMP2]] -uint16x8_t test_vcltq_f16(float16x8_t a, float16x8_t b) { - return vcltq_f16(a, b); -} - -// CHECK-LABEL: test_vcvt_n_f16_s16 -// CHECK: [[CVT:%.*]] = call <4 x half> @llvm.aarch64.neon.vcvtfxs2fp.v4f16.v4i16(<4 x i16> %vcvt_n, i32 2) -// CHECK: ret <4 x half> [[CVT]] -float16x4_t test_vcvt_n_f16_s16(int16x4_t a) { - return vcvt_n_f16_s16(a, 2); -} - -// CHECK-LABEL: test_vcvtq_n_f16_s16 -// CHECK: [[CVT:%.*]] = call <8 x half> @llvm.aarch64.neon.vcvtfxs2fp.v8f16.v8i16(<8 x i16> %vcvt_n, i32 2) -// CHECK: ret <8 x half> [[CVT]] -float16x8_t test_vcvtq_n_f16_s16(int16x8_t a) { - return vcvtq_n_f16_s16(a, 2); -} - -// CHECK-LABEL: test_vcvt_n_f16_u16 -// CHECK: [[CVT:%.*]] = call <4 x half> @llvm.aarch64.neon.vcvtfxu2fp.v4f16.v4i16(<4 x i16> %vcvt_n, i32 2) -// CHECK: ret <4 x half> [[CVT]] -float16x4_t test_vcvt_n_f16_u16(uint16x4_t a) { - return vcvt_n_f16_u16(a, 2); -} - -// CHECK-LABEL: test_vcvtq_n_f16_u16 -// CHECK: [[CVT:%.*]] = call <8 x half> @llvm.aarch64.neon.vcvtfxu2fp.v8f16.v8i16(<8 x i16> %vcvt_n, i32 2) -// CHECK: ret <8 x half> [[CVT]] -float16x8_t test_vcvtq_n_f16_u16(uint16x8_t a) { - return vcvtq_n_f16_u16(a, 2); -} - -// CHECK-LABEL: test_vcvt_n_s16_f16 -// CHECK: [[CVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2fxs.v4i16.v4f16(<4 x half> %vcvt_n, i32 2) -// CHECK: ret <4 x i16> [[CVT]] -int16x4_t test_vcvt_n_s16_f16(float16x4_t a) { - return vcvt_n_s16_f16(a, 2); -} - -// CHECK-LABEL: test_vcvtq_n_s16_f16 -// CHECK: [[CVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.vcvtfp2fxs.v8i16.v8f16(<8 x half> %vcvt_n, i32 2) -// CHECK: ret <8 x i16> [[CVT]] -int16x8_t test_vcvtq_n_s16_f16(float16x8_t a) { - return vcvtq_n_s16_f16(a, 2); -} - -// CHECK-LABEL: test_vcvt_n_u16_f16 -// CHECK: [[CVT:%.*]] = call <4 x i16> @llvm.aarch64.neon.vcvtfp2fxu.v4i16.v4f16(<4 x half> %vcvt_n, i32 2) -// CHECK: ret <4 x i16> [[CVT]] -uint16x4_t test_vcvt_n_u16_f16(float16x4_t a) { - return vcvt_n_u16_f16(a, 2); -} - -// CHECK-LABEL: test_vcvtq_n_u16_f16 -// CHECK: [[CVT:%.*]] = call <8 x i16> @llvm.aarch64.neon.vcvtfp2fxu.v8i16.v8f16(<8 x half> %vcvt_n, i32 2) -// CHECK: ret <8 x i16> [[CVT]] -uint16x8_t test_vcvtq_n_u16_f16(float16x8_t a) { - return vcvtq_n_u16_f16(a, 2); -} - -// CHECK-LABEL: test_vdiv_f16 -// CHECK: [[DIV:%.*]] = fdiv <4 x half> %a, %b -// CHECK: ret <4 x half> [[DIV]] -float16x4_t test_vdiv_f16(float16x4_t a, float16x4_t b) { - return vdiv_f16(a, b); -} - -// CHECK-LABEL: test_vdivq_f16 -// CHECK: [[DIV:%.*]] = fdiv <8 x half> %a, %b -// CHECK: ret <8 x half> [[DIV]] -float16x8_t test_vdivq_f16(float16x8_t a, float16x8_t b) { - return vdivq_f16(a, b); -} - -// CHECK-LABEL: test_vmax_f16 -// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmax.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MAX]] -float16x4_t test_vmax_f16(float16x4_t a, float16x4_t b) { - return vmax_f16(a, b); -} - -// CHECK-LABEL: test_vmaxq_f16 -// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmax.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MAX]] -float16x8_t test_vmaxq_f16(float16x8_t a, float16x8_t b) { - return vmaxq_f16(a, b); -} - -// CHECK-LABEL: test_vmaxnm_f16 -// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxnm.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MAX]] -float16x4_t test_vmaxnm_f16(float16x4_t a, float16x4_t b) { - return vmaxnm_f16(a, b); -} - -// CHECK-LABEL: test_vmaxnmq_f16 -// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxnm.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MAX]] -float16x8_t test_vmaxnmq_f16(float16x8_t a, float16x8_t b) { - return vmaxnmq_f16(a, b); -} - -// CHECK-LABEL: test_vmin_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fmin.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vmin_f16(float16x4_t a, float16x4_t b) { - return vmin_f16(a, b); -} - -// CHECK-LABEL: test_vminq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fmin.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vminq_f16(float16x8_t a, float16x8_t b) { - return vminq_f16(a, b); -} - -// CHECK-LABEL: test_vminnm_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminnm.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vminnm_f16(float16x4_t a, float16x4_t b) { - return vminnm_f16(a, b); -} - -// CHECK-LABEL: test_vminnmq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminnm.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vminnmq_f16(float16x8_t a, float16x8_t b) { - return vminnmq_f16(a, b); -} - -// CHECK-LABEL: test_vmul_f16 -// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, %b -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmul_f16(float16x4_t a, float16x4_t b) { - return vmul_f16(a, b); -} - -// CHECK-LABEL: test_vmulq_f16 -// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, %b -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulq_f16(float16x8_t a, float16x8_t b) { - return vmulq_f16(a, b); -} - -// CHECK-LABEL: test_vmulx_f16 -// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmulx_f16(float16x4_t a, float16x4_t b) { - return vmulx_f16(a, b); -} - -// CHECK-LABEL: test_vmulxq_f16 -// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulxq_f16(float16x8_t a, float16x8_t b) { - return vmulxq_f16(a, b); -} - -// CHECK-LABEL: test_vpadd_f16 -// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.aarch64.neon.addp.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[ADD]] -float16x4_t test_vpadd_f16(float16x4_t a, float16x4_t b) { - return vpadd_f16(a, b); -} - -// CHECK-LABEL: test_vpaddq_f16 -// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.aarch64.neon.addp.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[ADD]] -float16x8_t test_vpaddq_f16(float16x8_t a, float16x8_t b) { - return vpaddq_f16(a, b); -} - -// CHECK-LABEL: test_vpmax_f16 -// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxp.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MAX]] -float16x4_t test_vpmax_f16(float16x4_t a, float16x4_t b) { - return vpmax_f16(a, b); -} - -// CHECK-LABEL: test_vpmaxq_f16 -// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxp.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MAX]] -float16x8_t test_vpmaxq_f16(float16x8_t a, float16x8_t b) { - return vpmaxq_f16(a, b); -} - -// CHECK-LABEL: test_vpmaxnm_f16 -// CHECK: [[MAX:%.*]] = call <4 x half> @llvm.aarch64.neon.fmaxnmp.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MAX]] -float16x4_t test_vpmaxnm_f16(float16x4_t a, float16x4_t b) { - return vpmaxnm_f16(a, b); -} - -// CHECK-LABEL: test_vpmaxnmq_f16 -// CHECK: [[MAX:%.*]] = call <8 x half> @llvm.aarch64.neon.fmaxnmp.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MAX]] -float16x8_t test_vpmaxnmq_f16(float16x8_t a, float16x8_t b) { - return vpmaxnmq_f16(a, b); -} - -// CHECK-LABEL: test_vpmin_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminp.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vpmin_f16(float16x4_t a, float16x4_t b) { - return vpmin_f16(a, b); -} - -// CHECK-LABEL: test_vpminq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminp.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vpminq_f16(float16x8_t a, float16x8_t b) { - return vpminq_f16(a, b); -} - -// CHECK-LABEL: test_vpminnm_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.fminnmp.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vpminnm_f16(float16x4_t a, float16x4_t b) { - return vpminnm_f16(a, b); -} - -// CHECK-LABEL: test_vpminnmq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.fminnmp.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vpminnmq_f16(float16x8_t a, float16x8_t b) { - return vpminnmq_f16(a, b); -} - -// CHECK-LABEL: test_vrecps_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.frecps.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vrecps_f16(float16x4_t a, float16x4_t b) { - return vrecps_f16(a, b); -} - -// CHECK-LABEL: test_vrecpsq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.frecps.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vrecpsq_f16(float16x8_t a, float16x8_t b) { - return vrecpsq_f16(a, b); -} - -// CHECK-LABEL: test_vrsqrts_f16 -// CHECK: [[MIN:%.*]] = call <4 x half> @llvm.aarch64.neon.frsqrts.v4f16(<4 x half> %a, <4 x half> %b) -// CHECK: ret <4 x half> [[MIN]] -float16x4_t test_vrsqrts_f16(float16x4_t a, float16x4_t b) { - return vrsqrts_f16(a, b); -} - -// CHECK-LABEL: test_vrsqrtsq_f16 -// CHECK: [[MIN:%.*]] = call <8 x half> @llvm.aarch64.neon.frsqrts.v8f16(<8 x half> %a, <8 x half> %b) -// CHECK: ret <8 x half> [[MIN]] -float16x8_t test_vrsqrtsq_f16(float16x8_t a, float16x8_t b) { - return vrsqrtsq_f16(a, b); -} - -// CHECK-LABEL: test_vsub_f16 -// CHECK: [[ADD:%.*]] = fsub <4 x half> %a, %b -// CHECK: ret <4 x half> [[ADD]] -float16x4_t test_vsub_f16(float16x4_t a, float16x4_t b) { - return vsub_f16(a, b); -} - -// CHECK-LABEL: test_vsubq_f16 -// CHECK: [[ADD:%.*]] = fsub <8 x half> %a, %b -// CHECK: ret <8 x half> [[ADD]] -float16x8_t test_vsubq_f16(float16x8_t a, float16x8_t b) { - return vsubq_f16(a, b); -} - -// CHECK-LABEL: test_vfma_f16 -// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> %b, <4 x half> %c, <4 x half> %a) -// CHECK: ret <4 x half> [[ADD]] -float16x4_t test_vfma_f16(float16x4_t a, float16x4_t b, float16x4_t c) { - return vfma_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmaq_f16 -// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> %b, <8 x half> %c, <8 x half> %a) -// CHECK: ret <8 x half> [[ADD]] -float16x8_t test_vfmaq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { - return vfmaq_f16(a, b, c); -} - -// CHECK-LABEL: test_vfms_f16 -// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[ADD:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[SUB]], <4 x half> %c, <4 x half> %a) -// CHECK: ret <4 x half> [[ADD]] -float16x4_t test_vfms_f16(float16x4_t a, float16x4_t b, float16x4_t c) { - return vfms_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmsq_f16 -// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[ADD:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[SUB]], <8 x half> %c, <8 x half> %a) -// CHECK: ret <8 x half> [[ADD]] -float16x8_t test_vfmsq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { - return vfmsq_f16(a, b, c); -} - -// CHECK-LABEL: test_vfma_lane_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half> -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> <i32 3, i32 3, i32 3, i32 3> -// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[TMP4]], <4 x half> [[LANE]], <4 x half> [[TMP5]]) -// CHECK: ret <4 x half> [[FMLA]] -float16x4_t test_vfma_lane_f16(float16x4_t a, float16x4_t b, float16x4_t c) { - return vfma_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfmaq_lane_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half> -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3> -// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[TMP4]], <8 x half> [[LANE]], <8 x half> [[TMP5]]) -// CHECK: ret <8 x half> [[FMLA]] -float16x8_t test_vfmaq_lane_f16(float16x8_t a, float16x8_t b, float16x4_t c) { - return vfmaq_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfma_laneq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half> -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <4 x i32> <i32 7, i32 7, i32 7, i32 7> -// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[LANE]], <4 x half> [[TMP4]], <4 x half> [[TMP3]]) -// CHECK: ret <4 x half> [[FMLA]] -float16x4_t test_vfma_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) { - return vfma_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vfmaq_laneq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half> -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[LANE]], <8 x half> [[TMP4]], <8 x half> [[TMP3]]) -// CHECK: ret <8 x half> [[FMLA]] -float16x8_t test_vfmaq_laneq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { - return vfmaq_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vfma_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %c, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %c, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %c, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %c, i32 3 -// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> %b, <4 x half> [[TMP3]], <4 x half> %a) -// CHECK: ret <4 x half> [[FMA]] -float16x4_t test_vfma_n_f16(float16x4_t a, float16x4_t b, float16_t c) { - return vfma_n_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmaq_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %c, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %c, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %c, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %c, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %c, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %c, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %c, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %c, i32 7 -// CHECK: [[FMA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> %b, <8 x half> [[TMP7]], <8 x half> %a) -// CHECK: ret <8 x half> [[FMA]] -float16x8_t test_vfmaq_n_f16(float16x8_t a, float16x8_t b, float16_t c) { - return vfmaq_n_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmah_lane_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[EXTR:%.*]] = extractelement <4 x half> [[TMP1]], i32 3 -// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half %b, half [[EXTR]], half %a) -// CHECK: ret half [[FMA]] -float16_t test_vfmah_lane_f16(float16_t a, float16_t b, float16x4_t c) { - return vfmah_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfmah_laneq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[EXTR:%.*]] = extractelement <8 x half> [[TMP1]], i32 7 -// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half %b, half [[EXTR]], half %a) -// CHECK: ret half [[FMA]] -float16_t test_vfmah_laneq_f16(float16_t a, float16_t b, float16x8_t c) { - return vfmah_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vfms_lane_f16 -// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> [[SUB]] to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half> -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> <i32 3, i32 3, i32 3, i32 3> -// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP5:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[TMP4]], <4 x half> [[LANE]], <4 x half> [[TMP5]]) -// CHECK: ret <4 x half> [[FMA]] -float16x4_t test_vfms_lane_f16(float16x4_t a, float16x4_t b, float16x4_t c) { - return vfms_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfmsq_lane_f16 -// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> [[SUB]] to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half> -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <8 x i32> <i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3, i32 3> -// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[TMP4]], <8 x half> [[LANE]], <8 x half> [[TMP5]]) -// CHECK: ret <8 x half> [[FMLA]] -float16x8_t test_vfmsq_lane_f16(float16x8_t a, float16x8_t b, float16x4_t c) { - return vfmsq_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfms_laneq_f16 -// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> [[SUB]] to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[TMP4:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half> -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <4 x i32> <i32 7, i32 7, i32 7, i32 7> -// CHECK: [[FMLA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[LANE]], <4 x half> [[TMP4]], <4 x half> [[TMP3]]) -// CHECK: ret <4 x half> [[FMLA]] -float16x4_t test_vfms_laneq_f16(float16x4_t a, float16x4_t b, float16x8_t c) { - return vfms_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vfmsq_laneq_f16 -// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> [[SUB]] to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[TMP4:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP5:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half> -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP5]], <8 x half> [[TMP5]], <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[FMLA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[LANE]], <8 x half> [[TMP4]], <8 x half> [[TMP3]]) -// CHECK: ret <8 x half> [[FMLA]] -float16x8_t test_vfmsq_laneq_f16(float16x8_t a, float16x8_t b, float16x8_t c) { - return vfmsq_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vfms_n_f16 -// CHECK: [[SUB:%.*]] = fsub <4 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %c, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %c, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %c, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %c, i32 3 -// CHECK: [[FMA:%.*]] = call <4 x half> @llvm.fma.v4f16(<4 x half> [[SUB]], <4 x half> [[TMP3]], <4 x half> %a) -// CHECK: ret <4 x half> [[FMA]] -float16x4_t test_vfms_n_f16(float16x4_t a, float16x4_t b, float16_t c) { - return vfms_n_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmsq_n_f16 -// CHECK: [[SUB:%.*]] = fsub <8 x half> <half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000, half 0xH8000>, %b -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %c, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %c, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %c, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %c, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %c, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %c, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %c, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %c, i32 7 -// CHECK: [[FMA:%.*]] = call <8 x half> @llvm.fma.v8f16(<8 x half> [[SUB]], <8 x half> [[TMP7]], <8 x half> %a) -// CHECK: ret <8 x half> [[FMA]] -float16x8_t test_vfmsq_n_f16(float16x8_t a, float16x8_t b, float16_t c) { - return vfmsq_n_f16(a, b, c); -} - -// CHECK-LABEL: test_vfmsh_lane_f16 -// CHECK: [[TMP0:%.*]] = fpext half %b to float -// CHECK: [[TMP1:%.*]] = fsub float -0.000000e+00, [[TMP0]] -// CHECK: [[SUB:%.*]] = fptrunc float [[TMP1]] to half -// CHECK: [[TMP2:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP2]] to <4 x half> -// CHECK: [[EXTR:%.*]] = extractelement <4 x half> [[TMP3]], i32 3 -// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half [[SUB]], half [[EXTR]], half %a) -// CHECK: ret half [[FMA]] -float16_t test_vfmsh_lane_f16(float16_t a, float16_t b, float16x4_t c) { - return vfmsh_lane_f16(a, b, c, 3); -} - -// CHECK-LABEL: test_vfmsh_laneq_f16 -// CHECK: [[TMP0:%.*]] = fpext half %b to float -// CHECK: [[TMP1:%.*]] = fsub float -0.000000e+00, [[TMP0]] -// CHECK: [[SUB:%.*]] = fptrunc float [[TMP1]] to half -// CHECK: [[TMP2:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP2]] to <8 x half> -// CHECK: [[EXTR:%.*]] = extractelement <8 x half> [[TMP3]], i32 7 -// CHECK: [[FMA:%.*]] = call half @llvm.fma.f16(half [[SUB]], half [[EXTR]], half %a) -// CHECK: ret half [[FMA]] -float16_t test_vfmsh_laneq_f16(float16_t a, float16_t b, float16x8_t c) { - return vfmsh_laneq_f16(a, b, c, 7); -} - -// CHECK-LABEL: test_vmul_lane_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3> -// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP0]] -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmul_lane_f16(float16x4_t a, float16x4_t b) { - return vmul_lane_f16(a, b, 3); -} - -// CHECK-LABEL: test_vmulq_lane_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP0]] -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulq_lane_f16(float16x8_t a, float16x4_t b) { - return vmulq_lane_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmul_laneq_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <4 x i32> <i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP0]] -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmul_laneq_f16(float16x4_t a, float16x8_t b) { - return vmul_laneq_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmulq_laneq_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP0]] -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulq_laneq_f16(float16x8_t a, float16x8_t b) { - return vmulq_laneq_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmul_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %b, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %b, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %b, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %b, i32 3 -// CHECK: [[MUL:%.*]] = fmul <4 x half> %a, [[TMP3]] -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmul_n_f16(float16x4_t a, float16_t b) { - return vmul_n_f16(a, b); -} - -// CHECK-LABEL: test_vmulq_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %b, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %b, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %b, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %b, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %b, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %b, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %b, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %b, i32 7 -// CHECK: [[MUL:%.*]] = fmul <8 x half> %a, [[TMP7]] -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulq_n_f16(float16x8_t a, float16_t b) { - return vmulq_n_f16(a, b); -} - -// FIXME: Fix it when fp16 non-storage-only type becomes available. -// CHECK-LABEL: test_vmulh_lane_f16 -// CHECK: [[CONV0:%.*]] = fpext half %a to float -// CHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float -// CHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]] -// CHECK: [[CONV3:%.*]] = fptrunc float %mul to half -// CHECK: ret half [[CONV3:%.*]] -float16_t test_vmulh_lane_f16(float16_t a, float16x4_t b) { - return vmulh_lane_f16(a, b, 3); -} - -// CHECK-LABEL: test_vmulh_laneq_f16 -// CHECK: [[CONV0:%.*]] = fpext half %a to float -// CHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float -// CHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]] -// CHECK: [[CONV3:%.*]] = fptrunc float %mul to half -// CHECK: ret half [[CONV3:%.*]] -float16_t test_vmulh_laneq_f16(float16_t a, float16x8_t b) { - return vmulh_laneq_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmulx_lane_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <4 x i32> <i32 3, i32 3, i32 3, i32 3> -// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP0]]) -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmulx_lane_f16(float16x4_t a, float16x4_t b) { - return vmulx_lane_f16(a, b, 3); -} - -// CHECK-LABEL: test_vmulxq_lane_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <4 x half> %b, <4 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP0]]) -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulxq_lane_f16(float16x8_t a, float16x4_t b) { - return vmulxq_lane_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmulx_laneq_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <4 x i32> <i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP0]]) -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmulx_laneq_f16(float16x4_t a, float16x8_t b) { - return vmulx_laneq_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmulxq_laneq_f16 -// CHECK: [[TMP0:%.*]] = shufflevector <8 x half> %b, <8 x half> %b, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP0]]) -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulxq_laneq_f16(float16x8_t a, float16x8_t b) { - return vmulxq_laneq_f16(a, b, 7); -} - -// CHECK-LABEL: test_vmulx_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %b, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %b, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %b, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %b, i32 3 -// CHECK: [[MUL:%.*]] = call <4 x half> @llvm.aarch64.neon.fmulx.v4f16(<4 x half> %a, <4 x half> [[TMP3]]) -// CHECK: ret <4 x half> [[MUL]] -float16x4_t test_vmulx_n_f16(float16x4_t a, float16_t b) { - return vmulx_n_f16(a, b); -} - -// CHECK-LABEL: test_vmulxq_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %b, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %b, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %b, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %b, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %b, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %b, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %b, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %b, i32 7 -// CHECK: [[MUL:%.*]] = call <8 x half> @llvm.aarch64.neon.fmulx.v8f16(<8 x half> %a, <8 x half> [[TMP7]]) -// CHECK: ret <8 x half> [[MUL]] -float16x8_t test_vmulxq_n_f16(float16x8_t a, float16_t b) { - return vmulxq_n_f16(a, b); -} - -/* TODO: Not implemented yet (needs scalar intrinsic from arm_fp16.h) -// CCHECK-LABEL: test_vmulxh_lane_f16 -// CCHECK: [[CONV0:%.*]] = fpext half %a to float -// CCHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float -// CCHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]] -// CCHECK: [[CONV3:%.*]] = fptrunc float %mul to half -// CCHECK: ret half [[CONV3:%.*]] -float16_t test_vmulxh_lane_f16(float16_t a, float16x4_t b) { - return vmulxh_lane_f16(a, b, 3); -} - -// CCHECK-LABEL: test_vmulxh_laneq_f16 -// CCHECK: [[CONV0:%.*]] = fpext half %a to float -// CCHECK: [[CONV1:%.*]] = fpext half %{{.*}} to float -// CCHECK: [[MUL:%.*]] = fmul float [[CONV0:%.*]], [[CONV0:%.*]] -// CCHECK: [[CONV3:%.*]] = fptrunc float %mul to half -// CCHECK: ret half [[CONV3:%.*]] -float16_t test_vmulxh_laneq_f16(float16_t a, float16x8_t b) { - return vmulxh_laneq_f16(a, b, 7); -} -*/ - -// CHECK-LABEL: test_vmaxv_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxv.f16.v4f16(<4 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vmaxv_f16(float16x4_t a) { - return vmaxv_f16(a); -} - -// CHECK-LABEL: test_vmaxvq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxv.f16.v8f16(<8 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vmaxvq_f16(float16x8_t a) { - return vmaxvq_f16(a); -} - -// CHECK-LABEL: test_vminv_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminv.f16.v4f16(<4 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vminv_f16(float16x4_t a) { - return vminv_f16(a); -} - -// CHECK-LABEL: test_vminvq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminv.f16.v8f16(<8 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vminvq_f16(float16x8_t a) { - return vminvq_f16(a); -} - -// CHECK-LABEL: test_vmaxnmv_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxnmv.f16.v4f16(<4 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vmaxnmv_f16(float16x4_t a) { - return vmaxnmv_f16(a); -} - -// CHECK-LABEL: test_vmaxnmvq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fmaxnmv.f16.v8f16(<8 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vmaxnmvq_f16(float16x8_t a) { - return vmaxnmvq_f16(a); -} - -// CHECK-LABEL: test_vminnmv_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminnmv.f16.v4f16(<4 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vminnmv_f16(float16x4_t a) { - return vminnmv_f16(a); -} - -// CHECK-LABEL: test_vminnmvq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[MAX:%.*]] = call half @llvm.aarch64.neon.fminnmv.f16.v8f16(<8 x half> [[TMP1]]) -// CHECK: ret half [[MAX]] -float16_t test_vminnmvq_f16(float16x8_t a) { - return vminnmvq_f16(a); -} - -// CHECK-LABEL: test_vbsl_f16 -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %c to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x i16> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> -// CHECK: [[TMP4:%.*]] = and <4 x i16> %a, [[TMP2]] -// CHECK: [[TMP5:%.*]] = xor <4 x i16> %a, <i16 -1, i16 -1, i16 -1, i16 -1> -// CHECK: [[TMP6:%.*]] = and <4 x i16> [[TMP5]], [[TMP3]] -// CHECK: [[TMP7:%.*]] = or <4 x i16> [[TMP4]], [[TMP6]] -// CHECK: [[TMP8:%.*]] = bitcast <4 x i16> [[TMP7]] to <4 x half> -// CHECK: ret <4 x half> [[TMP8]] -float16x4_t test_vbsl_f16(uint16x4_t a, float16x4_t b, float16x4_t c) { - return vbsl_f16(a, b, c); -} - -// CHECK-LABEL: test_vbslq_f16 -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %c to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x i16> -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> -// CHECK: [[TMP4:%.*]] = and <8 x i16> %a, [[TMP2]] -// CHECK: [[TMP5:%.*]] = xor <8 x i16> %a, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1> -// CHECK: [[TMP6:%.*]] = and <8 x i16> [[TMP5]], [[TMP3]] -// CHECK: [[TMP7:%.*]] = or <8 x i16> [[TMP4]], [[TMP6]] -// CHECK: [[TMP8:%.*]] = bitcast <8 x i16> [[TMP7]] to <8 x half> -// CHECK: ret <8 x half> [[TMP8]] -float16x8_t test_vbslq_f16(uint16x8_t a, float16x8_t b, float16x8_t c) { - return vbslq_f16(a, b, c); -} - -// CHECK-LABEL: test_vzip_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 1, i32 5> -// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 2, i32 6, i32 3, i32 7> -// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false) -float16x4x2_t test_vzip_f16(float16x4_t a, float16x4_t b) { - return vzip_f16(a, b); -} - -// CHECK-LABEL: test_vzipq_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11> -// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15> -// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false) -float16x8x2_t test_vzipq_f16(float16x8_t a, float16x8_t b) { - return vzipq_f16(a, b); -} - -// CHECK-LABEL: test_vuzp_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 2, i32 4, i32 6> -// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 3, i32 5, i32 7> -// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false) -float16x4x2_t test_vuzp_f16(float16x4_t a, float16x4_t b) { - return vuzp_f16(a, b); -} - -// CHECK-LABEL: test_vuzpq_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14> -// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15> -// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false) -float16x8x2_t test_vuzpq_f16(float16x8_t a, float16x8_t b) { - return vuzpq_f16(a, b); -} - -// CHECK-LABEL: test_vtrn_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x4x2_t, align 8 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <4 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 2, i32 6> -// CHECK: store <4 x half> [[VZIP0_I]], <4 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <4 x half>, <4 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 5, i32 3, i32 7> -// CHECK: store <4 x half> [[VZIP1_I]], <4 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x4x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x4x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 16, i32 8, i1 false) -float16x4x2_t test_vtrn_f16(float16x4_t a, float16x4_t b) { - return vtrn_f16(a, b); -} - -// CHECK-LABEL: test_vtrnq_f16 -// CHECK: [[RETVAL:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[__RET_I:%.*]] = alloca %struct.float16x8x2_t, align 16 -// CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to <8 x half>* -// CHECK: [[VZIP0_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14> -// CHECK: store <8 x half> [[VZIP0_I]], <8 x half>* [[TMP1]] -// CHECK: [[TMP2:%.*]] = getelementptr inbounds <8 x half>, <8 x half>* [[TMP1]], i32 1 -// CHECK: [[VZIP1_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15> -// CHECK: store <8 x half> [[VZIP1_I]], <8 x half>* [[TMP2]] -// CHECK: [[TMP5:%.*]] = bitcast %struct.float16x8x2_t* [[RETVAL]] to i8* -// CHECK: [[TMP6:%.*]] = bitcast %struct.float16x8x2_t* [[__RET_I]] to i8* -// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[TMP5]], i8* [[TMP6]], i64 32, i32 16, i1 false) -float16x8x2_t test_vtrnq_f16(float16x8_t a, float16x8_t b) { - return vtrnq_f16(a, b); -} - -// CHECK-LABEL: test_vmov_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %a, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %a, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %a, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %a, i32 3 -// CHECK: ret <4 x half> [[TMP3]] -float16x4_t test_vmov_n_f16(float16_t a) { - return vmov_n_f16(a); -} - -// CHECK-LABEL: test_vmovq_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %a, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %a, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %a, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %a, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %a, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %a, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %a, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %a, i32 7 -// CHECK: ret <8 x half> [[TMP7]] -float16x8_t test_vmovq_n_f16(float16_t a) { - return vmovq_n_f16(a); -} - -// CHECK-LABEL: test_vdup_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <4 x half> undef, half %a, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <4 x half> [[TMP0]], half %a, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <4 x half> [[TMP1]], half %a, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> [[TMP2]], half %a, i32 3 -// CHECK: ret <4 x half> [[TMP3]] -float16x4_t test_vdup_n_f16(float16_t a) { - return vdup_n_f16(a); -} - -// CHECK-LABEL: test_vdupq_n_f16 -// CHECK: [[TMP0:%.*]] = insertelement <8 x half> undef, half %a, i32 0 -// CHECK: [[TMP1:%.*]] = insertelement <8 x half> [[TMP0]], half %a, i32 1 -// CHECK: [[TMP2:%.*]] = insertelement <8 x half> [[TMP1]], half %a, i32 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> [[TMP2]], half %a, i32 3 -// CHECK: [[TMP4:%.*]] = insertelement <8 x half> [[TMP3]], half %a, i32 4 -// CHECK: [[TMP5:%.*]] = insertelement <8 x half> [[TMP4]], half %a, i32 5 -// CHECK: [[TMP6:%.*]] = insertelement <8 x half> [[TMP5]], half %a, i32 6 -// CHECK: [[TMP7:%.*]] = insertelement <8 x half> [[TMP6]], half %a, i32 7 -// CHECK: ret <8 x half> [[TMP7]] -float16x8_t test_vdupq_n_f16(float16_t a) { - return vdupq_n_f16(a); -} - -// CHECK-LABEL: test_vdup_lane_f16 -// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <4 x i32> <i32 3, i32 3, i32 3, i32 3> -// CHECK: ret <4 x half> [[SHFL]] -float16x4_t test_vdup_lane_f16(float16x4_t a) { - return vdup_lane_f16(a, 3); -} - -// CHECK-LABEL: test_vdupq_lane_f16 -// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <8 x i32> <i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7, i32 7> -// CHECK: ret <8 x half> [[SHFL]] -float16x8_t test_vdupq_lane_f16(float16x4_t a) { - return vdupq_lane_f16(a, 7); -} - -// CHECK-LABEL: @test_vext_f16( -// CHECK: [[TMP0:%.*]] = bitcast <4 x half> %a to <8 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP0]] to <4 x half> -// CHECK: [[TMP3:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[VEXT:%.*]] = shufflevector <4 x half> [[TMP2]], <4 x half> [[TMP3]], <4 x i32> <i32 2, i32 3, i32 4, i32 5> -// CHECK: ret <4 x half> [[VEXT]] -float16x4_t test_vext_f16(float16x4_t a, float16x4_t b) { - return vext_f16(a, b, 2); -} - -// CHECK-LABEL: @test_vextq_f16( -// CHECK: [[TMP0:%.*]] = bitcast <8 x half> %a to <16 x i8> -// CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP0]] to <8 x half> -// CHECK: [[TMP3:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[VEXT:%.*]] = shufflevector <8 x half> [[TMP2]], <8 x half> [[TMP3]], <8 x i32> <i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12> -// CHECK: ret <8 x half> [[VEXT]] -float16x8_t test_vextq_f16(float16x8_t a, float16x8_t b) { - return vextq_f16(a, b, 5); -} - -// CHECK-LABEL: @test_vrev64_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %a, <4 x i32> <i32 3, i32 2, i32 1, i32 0> -// CHECK: ret <4 x half> [[SHFL]] -float16x4_t test_vrev64_f16(float16x4_t a) { - return vrev64_f16(a); -} - -// CHECK-LABEL: @test_vrev64q_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %a, <8 x i32> <i32 3, i32 2, i32 1, i32 0, i32 7, i32 6, i32 5, i32 4> -// CHECK: ret <8 x half> [[SHFL]] -float16x8_t test_vrev64q_f16(float16x8_t a) { - return vrev64q_f16(a); -} - -// CHECK-LABEL: @test_vzip1_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 1, i32 5> -// CHECK: ret <4 x half> [[SHFL]] -float16x4_t test_vzip1_f16(float16x4_t a, float16x4_t b) { - return vzip1_f16(a, b); -} - -// CHECK-LABEL: @test_vzip1q_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 1, i32 9, i32 2, i32 10, i32 3, i32 11> -// CHECK: ret <8 x half> [[SHFL]] -float16x8_t test_vzip1q_f16(float16x8_t a, float16x8_t b) { - return vzip1q_f16(a, b); -} - -// CHECK-LABEL: @test_vzip2_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 2, i32 6, i32 3, i32 7> -// CHECK: ret <4 x half> [[SHFL]] -float16x4_t test_vzip2_f16(float16x4_t a, float16x4_t b) { - return vzip2_f16(a, b); -} - -// CHECK-LABEL: @test_vzip2q_f16( -// CHECK: [[SHFL:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 4, i32 12, i32 5, i32 13, i32 6, i32 14, i32 7, i32 15> -// CHECK: ret <8 x half> [[SHFL]] -float16x8_t test_vzip2q_f16(float16x8_t a, float16x8_t b) { - return vzip2q_f16(a, b); -} - -// CHECK-LABEL: @test_vuzp1_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 2, i32 4, i32 6> -// CHECK: ret <4 x half> [[SHUFFLE_I]] -float16x4_t test_vuzp1_f16(float16x4_t a, float16x4_t b) { - return vuzp1_f16(a, b); -} - -// CHECK-LABEL: @test_vuzp1q_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14> -// CHECK: ret <8 x half> [[SHUFFLE_I]] -float16x8_t test_vuzp1q_f16(float16x8_t a, float16x8_t b) { - return vuzp1q_f16(a, b); -} - -// CHECK-LABEL: @test_vuzp2_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 3, i32 5, i32 7> -// CHECK: ret <4 x half> [[SHUFFLE_I]] -float16x4_t test_vuzp2_f16(float16x4_t a, float16x4_t b) { - return vuzp2_f16(a, b); -} - -// CHECK-LABEL: @test_vuzp2q_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15> -// CHECK: ret <8 x half> [[SHUFFLE_I]] -float16x8_t test_vuzp2q_f16(float16x8_t a, float16x8_t b) { - return vuzp2q_f16(a, b); -} - -// CHECK-LABEL: @test_vtrn1_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 0, i32 4, i32 2, i32 6> -// CHECK: ret <4 x half> [[SHUFFLE_I]] -float16x4_t test_vtrn1_f16(float16x4_t a, float16x4_t b) { - return vtrn1_f16(a, b); -} - -// CHECK-LABEL: @test_vtrn1q_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 0, i32 8, i32 2, i32 10, i32 4, i32 12, i32 6, i32 14> -// CHECK: ret <8 x half> [[SHUFFLE_I]] -float16x8_t test_vtrn1q_f16(float16x8_t a, float16x8_t b) { - return vtrn1q_f16(a, b); -} - -// CHECK-LABEL: @test_vtrn2_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <4 x half> %a, <4 x half> %b, <4 x i32> <i32 1, i32 5, i32 3, i32 7> -// CHECK: ret <4 x half> [[SHUFFLE_I]] -float16x4_t test_vtrn2_f16(float16x4_t a, float16x4_t b) { - return vtrn2_f16(a, b); -} - -// CHECK-LABEL: @test_vtrn2q_f16( -// CHECK: [[SHUFFLE_I:%.*]] = shufflevector <8 x half> %a, <8 x half> %b, <8 x i32> <i32 1, i32 9, i32 3, i32 11, i32 5, i32 13, i32 7, i32 15> -// CHECK: ret <8 x half> [[SHUFFLE_I]] -float16x8_t test_vtrn2q_f16(float16x8_t a, float16x8_t b) { - return vtrn2q_f16(a, b); -} - diff --git a/test/CodeGen/address-space.c b/test/CodeGen/address-space.c index 54e059385772..28b3954ab7d2 100644 --- a/test/CodeGen/address-space.c +++ b/test/CodeGen/address-space.c @@ -24,11 +24,13 @@ int test2(int i) { return ban[i]; } __attribute__((address_space(2))) int *A, *B; // CHECK-LABEL: define void @test3() -// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @B -// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @B +// X86: load i32 addrspace(2)*, i32 addrspace(2)** @B +// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)**) +// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @B to i32 addrspace(2)* addrspace(4)*) // CHECK: load i32, i32 addrspace(2)* -// GIZ: load i32 addrspace(2)*, i32 addrspace(2)** @A -// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* @A +// X86: load i32 addrspace(2)*, i32 addrspace(2)** @A +// AMDGIZ: load i32 addrspace(2)*, i32 addrspace(2)** addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)**) +// PIZ: load i32 addrspace(2)*, i32 addrspace(2)* addrspace(4)* addrspacecast (i32 addrspace(2)* addrspace(1)* @A to i32 addrspace(2)* addrspace(4)*) // CHECK: store i32 {{.*}}, i32 addrspace(2)* void test3() { *A = *B; diff --git a/test/CodeGen/arm_neon_intrinsics.c b/test/CodeGen/arm_neon_intrinsics.c index b01c90c03a96..62888dd73339 100644 --- a/test/CodeGen/arm_neon_intrinsics.c +++ b/test/CodeGen/arm_neon_intrinsics.c @@ -3896,8 +3896,9 @@ int64x2_t test_vld1q_s64(int64_t const * a) { // CHECK-LABEL: @test_vld1q_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD1:%.*]] = call <8 x half> @llvm.arm.neon.vld1.v8f16.p0i8(i8* [[TMP0]], i32 2) -// CHECK: ret <8 x half> [[VLD1]] +// CHECK: [[VLD1:%.*]] = call <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8* [[TMP0]], i32 2) +// CHECK: [[TMP1:%.*]] = bitcast <8 x i16> [[VLD1]] to <8 x half> +// CHECK: ret <8 x half> [[TMP1]] float16x8_t test_vld1q_f16(float16_t const * a) { return vld1q_f16(a); } @@ -3989,8 +3990,9 @@ int64x1_t test_vld1_s64(int64_t const * a) { // CHECK-LABEL: @test_vld1_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD1:%.*]] = call <4 x half> @llvm.arm.neon.vld1.v4f16.p0i8(i8* [[TMP0]], i32 2) -// CHECK: ret <4 x half> [[VLD1]] +// CHECK: [[VLD1:%.*]] = call <4 x i16> @llvm.arm.neon.vld1.v4i16.p0i8(i8* [[TMP0]], i32 2) +// CHECK: [[TMP1:%.*]] = bitcast <4 x i16> [[VLD1]] to <4 x half> +// CHECK: ret <4 x half> [[TMP1]] float16x4_t test_vld1_f16(float16_t const * a) { return vld1_f16(a); } @@ -4104,11 +4106,12 @@ int64x2_t test_vld1q_dup_s64(int64_t const * a) { // CHECK-LABEL: @test_vld1q_dup_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]], align 2 -// CHECK: [[TMP3:%.*]] = insertelement <8 x half> undef, half [[TMP2]], i32 0 -// CHECK: [[LANE:%.*]] = shufflevector <8 x half> [[TMP3]], <8 x half> [[TMP3]], <8 x i32> zeroinitializer -// CHECK: ret <8 x half> [[LANE]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]], align 2 +// CHECK: [[TMP3:%.*]] = insertelement <8 x i16> undef, i16 [[TMP2]], i32 0 +// CHECK: [[LANE:%.*]] = shufflevector <8 x i16> [[TMP3]], <8 x i16> [[TMP3]], <8 x i32> zeroinitializer +// CHECK: [[TMP4:%.*]] = bitcast <8 x i16> [[LANE]] to <8 x half> +// CHECK: ret <8 x half> [[TMP4]] float16x8_t test_vld1q_dup_f16(float16_t const * a) { return vld1q_dup_f16(a); } @@ -4230,11 +4233,12 @@ int64x1_t test_vld1_dup_s64(int64_t const * a) { // CHECK-LABEL: @test_vld1_dup_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* -// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP2:%.*]] = load half, half* [[TMP1]], align 2 -// CHECK: [[TMP3:%.*]] = insertelement <4 x half> undef, half [[TMP2]], i32 0 -// CHECK: [[LANE:%.*]] = shufflevector <4 x half> [[TMP3]], <4 x half> [[TMP3]], <4 x i32> zeroinitializer -// CHECK: ret <4 x half> [[LANE]] +// CHECK: [[TMP1:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP2:%.*]] = load i16, i16* [[TMP1]], align 2 +// CHECK: [[TMP3:%.*]] = insertelement <4 x i16> undef, i16 [[TMP2]], i32 0 +// CHECK: [[LANE:%.*]] = shufflevector <4 x i16> [[TMP3]], <4 x i16> [[TMP3]], <4 x i32> zeroinitializer +// CHECK: [[TMP4:%.*]] = bitcast <4 x i16> [[LANE]] to <4 x half> +// CHECK: ret <4 x half> [[TMP4]] float16x4_t test_vld1_dup_f16(float16_t const * a) { return vld1_dup_f16(a); } @@ -4361,11 +4365,12 @@ int64x2_t test_vld1q_lane_s64(int64_t const * a, int64x2_t b) { // CHECK-LABEL: @test_vld1q_lane_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]], align 2 -// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x half> [[TMP2]], half [[TMP4]], i32 7 -// CHECK: ret <8 x half> [[VLD1_LANE]] +// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]], align 2 +// CHECK: [[VLD1_LANE:%.*]] = insertelement <8 x i16> [[TMP2]], i16 [[TMP4]], i32 7 +// CHECK: [[TMP5:%.*]] = bitcast <8 x i16> [[VLD1_LANE]] to <8 x half> +// CHECK: ret <8 x half> [[TMP5]] float16x8_t test_vld1q_lane_f16(float16_t const * a, float16x8_t b) { return vld1q_lane_f16(a, b, 7); } @@ -4493,11 +4498,12 @@ int64x1_t test_vld1_lane_s64(int64_t const * a, int64x1_t b) { // CHECK-LABEL: @test_vld1_lane_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: [[TMP4:%.*]] = load half, half* [[TMP3]], align 2 -// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x half> [[TMP2]], half [[TMP4]], i32 3 -// CHECK: ret <4 x half> [[VLD1_LANE]] +// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: [[TMP3:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: [[TMP4:%.*]] = load i16, i16* [[TMP3]], align 2 +// CHECK: [[VLD1_LANE:%.*]] = insertelement <4 x i16> [[TMP2]], i16 [[TMP4]], i32 3 +// CHECK: [[TMP5:%.*]] = bitcast <4 x i16> [[VLD1_LANE]] to <4 x half> +// CHECK: ret <4 x half> [[TMP5]] float16x4_t test_vld1_lane_f16(float16_t const * a, float16x4_t b) { return vld1_lane_f16(a, b, 3); } @@ -4590,7 +4596,7 @@ int32x4x2_t test_vld2q_s32(int32_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x2_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD2Q_V:%.*]] = call { <8 x half>, <8 x half> +// CHECK: [[VLD2Q_V:%.*]] = call { <8 x i16>, <8 x i16> float16x8x2_t test_vld2q_f16(float16_t const * a) { return vld2q_f16(a); } @@ -4695,7 +4701,7 @@ int64x1x2_t test_vld2_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD2_V:%.*]] = call { <4 x half>, <4 x half> +// CHECK: [[VLD2_V:%.*]] = call { <4 x i16>, <4 x i16> float16x4x2_t test_vld2_f16(float16_t const * a) { return vld2_f16(a); } @@ -4800,7 +4806,7 @@ int64x1x2_t test_vld2_dup_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x2_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x2_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half> +// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16> float16x4x2_t test_vld2_dup_f16(float16_t const * a) { return vld2_dup_f16(a); } @@ -4959,9 +4965,9 @@ int32x4x2_t test_vld2q_lane_s32(int32_t const * a, int32x4x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP7:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP8:%.*]] = bitcast <8 x half> [[TMP7]] to <16 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[VLD2Q_LANE_V:%.*]] = call { <8 x half>, <8 x half> +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[VLD2Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16> float16x8x2_t test_vld2q_lane_f16(float16_t const * a, float16x8x2_t b) { return vld2q_lane_f16(a, b, 7); } @@ -5192,9 +5198,9 @@ int32x2x2_t test_vld2_lane_s32(int32_t const * a, int32x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP7:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP8:%.*]] = bitcast <4 x half> [[TMP7]] to <8 x i8> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[VLD2_LANE_V:%.*]] = call { <4 x half>, <4 x half> +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[VLD2_LANE_V:%.*]] = call { <4 x i16>, <4 x i16> float16x4x2_t test_vld2_lane_f16(float16_t const * a, float16x4x2_t b) { return vld2_lane_f16(a, b, 3); } @@ -5331,7 +5337,7 @@ int32x4x3_t test_vld3q_s32(int32_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x3_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD3Q_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half> +// CHECK: [[VLD3Q_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> float16x8x3_t test_vld3q_f16(float16_t const * a) { return vld3q_f16(a); } @@ -5436,7 +5442,7 @@ int64x1x3_t test_vld3_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD3_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half> +// CHECK: [[VLD3_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> float16x4x3_t test_vld3_f16(float16_t const * a) { return vld3_f16(a); } @@ -5541,7 +5547,7 @@ int64x1x3_t test_vld3_dup_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x3_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x3_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half>, <4 x half> +// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> float16x4x3_t test_vld3_dup_f16(float16_t const * a) { return vld3_dup_f16(a); } @@ -5724,10 +5730,10 @@ int32x4x3_t test_vld3q_lane_s32(int32_t const * a, int32x4x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP9:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP10:%.*]] = bitcast <8 x half> [[TMP9]] to <16 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half> -// CHECK: [[VLD3Q_LANE_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16> +// CHECK: [[VLD3Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16> float16x8x3_t test_vld3q_lane_f16(float16_t const * a, float16x8x3_t b) { return vld3q_lane_f16(a, b, 7); } @@ -5998,10 +6004,10 @@ int32x2x3_t test_vld3_lane_s32(int32_t const * a, int32x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP9:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP10:%.*]] = bitcast <4 x half> [[TMP9]] to <8 x i8> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half> -// CHECK: [[VLD3_LANE_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> +// CHECK: [[VLD3_LANE_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16> float16x4x3_t test_vld3_lane_f16(float16_t const * a, float16x4x3_t b) { return vld3_lane_f16(a, b, 3); } @@ -6151,7 +6157,7 @@ int32x4x4_t test_vld4q_s32(int32_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x8x4_t, align 16 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x8x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD4Q_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> +// CHECK: [[VLD4Q_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> float16x8x4_t test_vld4q_f16(float16_t const * a) { return vld4q_f16(a); } @@ -6256,7 +6262,7 @@ int64x1x4_t test_vld4_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD4_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> +// CHECK: [[VLD4_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> float16x4x4_t test_vld4_f16(float16_t const * a) { return vld4_f16(a); } @@ -6361,7 +6367,7 @@ int64x1x4_t test_vld4_dup_s64(int64_t const * a) { // CHECK: [[__RET:%.*]] = alloca %struct.float16x4x4_t, align 8 // CHECK: [[TMP0:%.*]] = bitcast %struct.float16x4x4_t* [[__RET]] to i8* // CHECK: [[TMP1:%.*]] = bitcast half* %a to i8* -// CHECK: [[VLD_DUP:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> +// CHECK: [[VLD_DUP:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> float16x4x4_t test_vld4_dup_f16(float16_t const * a) { return vld4_dup_f16(a); } @@ -6568,11 +6574,11 @@ int32x4x4_t test_vld4q_lane_s32(int32_t const * a, int32x4x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP11:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP12:%.*]] = bitcast <8 x half> [[TMP11]] to <16 x i8> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x half> -// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x half> -// CHECK: [[TMP16:%.*]] = bitcast <16 x i8> [[TMP12]] to <8 x half> -// CHECK: [[VLD4Q_LANE_V:%.*]] = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP6]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP8]] to <8 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP10]] to <8 x i16> +// CHECK: [[TMP16:%.*]] = bitcast <16 x i8> [[TMP12]] to <8 x i16> +// CHECK: [[VLD4Q_LANE_V:%.*]] = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> float16x8x4_t test_vld4q_lane_f16(float16_t const * a, float16x8x4_t b) { return vld4q_lane_f16(a, b, 7); } @@ -6883,11 +6889,11 @@ int32x2x4_t test_vld4_lane_s32(int32_t const * a, int32x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP11:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP12:%.*]] = bitcast <4 x half> [[TMP11]] to <8 x i8> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x half> -// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x half> -// CHECK: [[TMP16:%.*]] = bitcast <8 x i8> [[TMP12]] to <4 x half> -// CHECK: [[VLD4_LANE_V:%.*]] = call { <4 x half>, <4 x half>, <4 x half>, <4 x half> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP6]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP8]] to <4 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP10]] to <4 x i16> +// CHECK: [[TMP16:%.*]] = bitcast <8 x i8> [[TMP12]] to <4 x i16> +// CHECK: [[VLD4_LANE_V:%.*]] = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> float16x4x4_t test_vld4_lane_f16(float16_t const * a, float16x4x4_t b) { return vld4_lane_f16(a, b, 3); } @@ -15778,8 +15784,8 @@ void test_vst1q_s64(int64_t * a, int64x2_t b) { // CHECK-LABEL: @test_vst1q_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst1.p0i8.v8f16(i8* [[TMP0]], <8 x half> [[TMP2]], i32 2) +// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst1.p0i8.v8i16(i8* [[TMP0]], <8 x i16> [[TMP2]], i32 2) // CHECK: ret void void test_vst1q_f16(float16_t * a, float16x8_t b) { vst1q_f16(a, b); @@ -15889,8 +15895,8 @@ void test_vst1_s64(int64_t * a, int64x1_t b) { // CHECK-LABEL: @test_vst1_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst1.p0i8.v4f16(i8* [[TMP0]], <4 x half> [[TMP2]], i32 2) +// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst1.p0i8.v4i16(i8* [[TMP0]], <4 x i16> [[TMP2]], i32 2) // CHECK: ret void void test_vst1_f16(float16_t * a, float16x4_t b) { vst1_f16(a, b); @@ -16012,10 +16018,10 @@ void test_vst1q_lane_s64(int64_t * a, int64x2_t b) { // CHECK-LABEL: @test_vst1q_lane_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <8 x half> %b to <16 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x half> -// CHECK: [[TMP3:%.*]] = extractelement <8 x half> [[TMP2]], i32 7 -// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: store half [[TMP3]], half* [[TMP4]], align 2 +// CHECK: [[TMP2:%.*]] = bitcast <16 x i8> [[TMP1]] to <8 x i16> +// CHECK: [[TMP3:%.*]] = extractelement <8 x i16> [[TMP2]], i32 7 +// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: store i16 [[TMP3]], i16* [[TMP4]], align 2 // CHECK: ret void void test_vst1q_lane_f16(float16_t * a, float16x8_t b) { vst1q_lane_f16(a, b, 7); @@ -16144,10 +16150,10 @@ void test_vst1_lane_s64(int64_t * a, int64x1_t b) { // CHECK-LABEL: @test_vst1_lane_f16( // CHECK: [[TMP0:%.*]] = bitcast half* %a to i8* // CHECK: [[TMP1:%.*]] = bitcast <4 x half> %b to <8 x i8> -// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x half> -// CHECK: [[TMP3:%.*]] = extractelement <4 x half> [[TMP2]], i32 3 -// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to half* -// CHECK: store half [[TMP3]], half* [[TMP4]], align 2 +// CHECK: [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to <4 x i16> +// CHECK: [[TMP3:%.*]] = extractelement <4 x i16> [[TMP2]], i32 3 +// CHECK: [[TMP4:%.*]] = bitcast i8* [[TMP0]] to i16* +// CHECK: store i16 [[TMP3]], i16* [[TMP4]], align 2 // CHECK: ret void void test_vst1_lane_f16(float16_t * a, float16x4_t b) { vst1_lane_f16(a, b, 3); @@ -16349,9 +16355,9 @@ void test_vst2q_s32(int32_t * a, int32x4x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst2.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP8]], <8 x half> [[TMP9]], i32 2) +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst2.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i32 2) // CHECK: ret void void test_vst2q_f16(float16_t * a, float16x8x2_t b) { vst2q_f16(a, b); @@ -16646,9 +16652,9 @@ void test_vst2_s64(int64_t * a, int64x1x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst2.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP8]], <4 x half> [[TMP9]], i32 2) +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst2.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i32 2) // CHECK: ret void void test_vst2_f16(float16_t * a, float16x4x2_t b) { vst2_f16(a, b); @@ -16849,9 +16855,9 @@ void test_vst2q_lane_s32(int32_t * a, int32x4x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <8 x half>], [2 x <8 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP6:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX2]], align 16 // CHECK: [[TMP7:%.*]] = bitcast <8 x half> [[TMP6]] to <16 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP8]], <8 x half> [[TMP9]], i32 7, i32 2) +// CHECK: [[TMP8:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP8]], <8 x i16> [[TMP9]], i32 7, i32 2) // CHECK: ret void void test_vst2q_lane_f16(float16_t * a, float16x8x2_t b) { vst2q_lane_f16(a, b, 7); @@ -17073,9 +17079,9 @@ void test_vst2_lane_s32(int32_t * a, int32x2x2_t b) { // CHECK: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x <4 x half>], [2 x <4 x half>]* [[VAL1]], i32 0, i32 1 // CHECK: [[TMP6:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX2]], align 8 // CHECK: [[TMP7:%.*]] = bitcast <4 x half> [[TMP6]] to <8 x i8> -// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP8]], <4 x half> [[TMP9]], i32 3, i32 2) +// CHECK: [[TMP8:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP9:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst2lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP8]], <4 x i16> [[TMP9]], i32 3, i32 2) // CHECK: ret void void test_vst2_lane_f16(float16_t * a, float16x4x2_t b) { vst2_lane_f16(a, b, 3); @@ -17348,10 +17354,10 @@ void test_vst3q_s32(int32_t * a, int32x4x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst3.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i32 2) +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst3.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i32 2) // CHECK: ret void void test_vst3q_f16(float16_t * a, float16x8x3_t b) { vst3q_f16(a, b); @@ -17699,10 +17705,10 @@ void test_vst3_s64(int64_t * a, int64x1x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst3.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i32 2) +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst3.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i32 2) // CHECK: ret void void test_vst3_f16(float16_t * a, float16x4x3_t b) { vst3_f16(a, b); @@ -17940,10 +17946,10 @@ void test_vst3q_lane_s32(int32_t * a, int32x4x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <8 x half>], [3 x <8 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP8:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX4]], align 16 // CHECK: [[TMP9:%.*]] = bitcast <8 x half> [[TMP8]] to <16 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP10]], <8 x half> [[TMP11]], <8 x half> [[TMP12]], i32 7, i32 2) +// CHECK: [[TMP10:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP10]], <8 x i16> [[TMP11]], <8 x i16> [[TMP12]], i32 7, i32 2) // CHECK: ret void void test_vst3q_lane_f16(float16_t * a, float16x8x3_t b) { vst3q_lane_f16(a, b, 7); @@ -18205,10 +18211,10 @@ void test_vst3_lane_s32(int32_t * a, int32x2x3_t b) { // CHECK: [[ARRAYIDX4:%.*]] = getelementptr inbounds [3 x <4 x half>], [3 x <4 x half>]* [[VAL3]], i32 0, i32 2 // CHECK: [[TMP8:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX4]], align 8 // CHECK: [[TMP9:%.*]] = bitcast <4 x half> [[TMP8]] to <8 x i8> -// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP10]], <4 x half> [[TMP11]], <4 x half> [[TMP12]], i32 3, i32 2) +// CHECK: [[TMP10:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP11:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst3lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP10]], <4 x i16> [[TMP11]], <4 x i16> [[TMP12]], i32 3, i32 2) // CHECK: ret void void test_vst3_lane_f16(float16_t * a, float16x4x3_t b) { vst3_lane_f16(a, b, 3); @@ -18524,11 +18530,11 @@ void test_vst4q_s32(int32_t * a, int32x4x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst4.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i32 2) +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst4.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i32 2) // CHECK: ret void void test_vst4q_f16(float16_t * a, float16x8x4_t b) { vst4q_f16(a, b); @@ -18929,11 +18935,11 @@ void test_vst4_s64(int64_t * a, int64x1x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst4.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i32 2) +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst4.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i32 2) // CHECK: ret void void test_vst4_f16(float16_t * a, float16x4x4_t b) { vst4_f16(a, b); @@ -19208,11 +19214,11 @@ void test_vst4q_lane_s32(int32_t * a, int32x4x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <8 x half>], [4 x <8 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP10:%.*]] = load <8 x half>, <8 x half>* [[ARRAYIDX6]], align 16 // CHECK: [[TMP11:%.*]] = bitcast <8 x half> [[TMP10]] to <16 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x half> -// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x half> -// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x half> -// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x half> -// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v8f16(i8* [[TMP3]], <8 x half> [[TMP12]], <8 x half> [[TMP13]], <8 x half> [[TMP14]], <8 x half> [[TMP15]], i32 7, i32 2) +// CHECK: [[TMP12:%.*]] = bitcast <16 x i8> [[TMP5]] to <8 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <16 x i8> [[TMP7]] to <8 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <16 x i8> [[TMP9]] to <8 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <16 x i8> [[TMP11]] to <8 x i16> +// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v8i16(i8* [[TMP3]], <8 x i16> [[TMP12]], <8 x i16> [[TMP13]], <8 x i16> [[TMP14]], <8 x i16> [[TMP15]], i32 7, i32 2) // CHECK: ret void void test_vst4q_lane_f16(float16_t * a, float16x8x4_t b) { vst4q_lane_f16(a, b, 7); @@ -19514,11 +19520,11 @@ void test_vst4_lane_s32(int32_t * a, int32x2x4_t b) { // CHECK: [[ARRAYIDX6:%.*]] = getelementptr inbounds [4 x <4 x half>], [4 x <4 x half>]* [[VAL5]], i32 0, i32 3 // CHECK: [[TMP10:%.*]] = load <4 x half>, <4 x half>* [[ARRAYIDX6]], align 8 // CHECK: [[TMP11:%.*]] = bitcast <4 x half> [[TMP10]] to <8 x i8> -// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x half> -// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x half> -// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x half> -// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x half> -// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v4f16(i8* [[TMP3]], <4 x half> [[TMP12]], <4 x half> [[TMP13]], <4 x half> [[TMP14]], <4 x half> [[TMP15]], i32 3, i32 2) +// CHECK: [[TMP12:%.*]] = bitcast <8 x i8> [[TMP5]] to <4 x i16> +// CHECK: [[TMP13:%.*]] = bitcast <8 x i8> [[TMP7]] to <4 x i16> +// CHECK: [[TMP14:%.*]] = bitcast <8 x i8> [[TMP9]] to <4 x i16> +// CHECK: [[TMP15:%.*]] = bitcast <8 x i8> [[TMP11]] to <4 x i16> +// CHECK: call void @llvm.arm.neon.vst4lane.p0i8.v4i16(i8* [[TMP3]], <4 x i16> [[TMP12]], <4 x i16> [[TMP13]], <4 x i16> [[TMP14]], <4 x i16> [[TMP15]], i32 3, i32 2) // CHECK: ret void void test_vst4_lane_f16(float16_t * a, float16x4x4_t b) { vst4_lane_f16(a, b, 3); diff --git a/test/CodeGen/bitscan-builtins.c b/test/CodeGen/bitscan-builtins.c index 71e49845f896..5fd3f13fbc73 100644 --- a/test/CodeGen/bitscan-builtins.c +++ b/test/CodeGen/bitscan-builtins.c @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s +// PR33722 +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-unknown -D_MSC_VER -emit-llvm -o - %s | FileCheck %s + #include <immintrin.h> int test_bit_scan_forward(int a) { diff --git a/test/CodeGen/default-address-space.c b/test/CodeGen/default-address-space.c index fc5f55ffd6f4..b7f40585b267 100644 --- a/test/CodeGen/default-address-space.c +++ b/test/CodeGen/default-address-space.c @@ -1,24 +1,24 @@ // RUN: %clang_cc1 -triple amdgcn -emit-llvm < %s | FileCheck -check-prefixes=PIZ,COM %s // RUN: %clang_cc1 -triple amdgcn---amdgiz -emit-llvm < %s | FileCheck -check-prefixes=CHECK,COM %s -// PIZ-DAG: @foo = common addrspace(4) global i32 0 -// CHECK-DAG: @foo = common global i32 0 +// PIZ-DAG: @foo = common addrspace(1) global i32 0 +// CHECK-DAG: @foo = common addrspace(1) global i32 0 int foo; -// PIZ-DAG: @ban = common addrspace(4) global [10 x i32] zeroinitializer -// CHECK-DAG: @ban = common global [10 x i32] zeroinitializer +// PIZ-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer +// CHECK-DAG: @ban = common addrspace(1) global [10 x i32] zeroinitializer int ban[10]; -// PIZ-DAG: @A = common addrspace(4) global i32 addrspace(4)* null -// PIZ-DAG: @B = common addrspace(4) global i32 addrspace(4)* null -// CHECK-DAG: @A = common global i32* null -// CHECK-DAG: @B = common global i32* null +// PIZ-DAG: @A = common addrspace(1) global i32 addrspace(4)* null +// PIZ-DAG: @B = common addrspace(1) global i32 addrspace(4)* null +// CHECK-DAG: @A = common addrspace(1) global i32* null +// CHECK-DAG: @B = common addrspace(1) global i32* null int *A; int *B; // COM-LABEL: define i32 @test1() -// PIZ: load i32, i32 addrspace(4)* @foo -// CHECK: load i32, i32* @foo +// PIZ: load i32, i32 addrspace(4)* addrspacecast{{[^@]+}} @foo +// CHECK: load i32, i32* addrspacecast{{[^@]+}} @foo int test1() { return foo; } // COM-LABEL: define i32 @test2(i32 %i) @@ -30,13 +30,13 @@ int test1() { return foo; } int test2(int i) { return ban[i]; } // COM-LABEL: define void @test3() -// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @B +// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* addrspacecast{{[^@]+}} @B // PIZ: load i32, i32 addrspace(4)* -// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* @A +// PIZ: load i32 addrspace(4)*, i32 addrspace(4)* addrspace(4)* addrspacecast{{[^@]+}} @A // PIZ: store i32 {{.*}}, i32 addrspace(4)* -// CHECK: load i32*, i32** @B +// CHECK: load i32*, i32** addrspacecast{{.*}} @B // CHECK: load i32, i32* -// CHECK: load i32*, i32** @A +// CHECK: load i32*, i32** addrspacecast{{.*}} @A // CHECK: store i32 {{.*}}, i32* void test3() { *A = *B; @@ -50,7 +50,7 @@ void test3() { // PIZ: %[[arrayidx:.*]] = getelementptr inbounds i32, i32 addrspace(4)* %[[r0]] // PIZ: store i32 0, i32 addrspace(4)* %[[arrayidx]] // CHECK-LABEL: define void @test4(i32* %a) -// CHECK: %[[alloca:.*]] = alloca i32*, align 4, addrspace(5) +// CHECK: %[[alloca:.*]] = alloca i32*, align 8, addrspace(5) // CHECK: %[[a_addr:.*]] = addrspacecast{{.*}} %[[alloca]] to i32** // CHECK: store i32* %a, i32** %[[a_addr]] // CHECK: %[[r0:.*]] = load i32*, i32** %[[a_addr]] diff --git a/test/CodeGen/mcount.c b/test/CodeGen/mcount.c index 2839d8ef6af3..2284acac0f8e 100644 --- a/test/CodeGen/mcount.c +++ b/test/CodeGen/mcount.c @@ -8,6 +8,10 @@ // RUN: %clang_cc1 -pg -triple arm-netbsd-eabi -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s // RUN: %clang_cc1 -pg -triple aarch64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s // RUN: %clang_cc1 -pg -triple mips-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s +// RUN: %clang_cc1 -pg -triple mips-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s +// RUN: %clang_cc1 -pg -triple mipsel-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s +// RUN: %clang_cc1 -pg -triple mips64-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s +// RUN: %clang_cc1 -pg -triple mips64el-unknown-gnu-linux -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s // RUN: %clang_cc1 -pg -triple powerpc-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s // RUN: %clang_cc1 -pg -triple powerpc64-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s // RUN: %clang_cc1 -pg -triple powerpc64le-netbsd -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-PREFIXED,NO-MCOUNT1 %s diff --git a/test/CodeGen/ms-barriers-intrinsics.c b/test/CodeGen/ms-barriers-intrinsics.c index b0dfc3042a6e..c7da50cd0d83 100644 --- a/test/CodeGen/ms-barriers-intrinsics.c +++ b/test/CodeGen/ms-barriers-intrinsics.c @@ -13,19 +13,19 @@ typedef __SIZE_TYPE__ size_t; void test_ReadWriteBarrier() { _ReadWriteBarrier(); } // CHECK-LABEL: define void @test_ReadWriteBarrier -// CHECK: fence singlethread seq_cst +// CHECK: fence syncscope("singlethread") seq_cst // CHECK: ret void // CHECK: } void test_ReadBarrier() { _ReadBarrier(); } // CHECK-LABEL: define void @test_ReadBarrier -// CHECK: fence singlethread seq_cst +// CHECK: fence syncscope("singlethread") seq_cst // CHECK: ret void // CHECK: } void test_WriteBarrier() { _WriteBarrier(); } // CHECK-LABEL: define void @test_WriteBarrier -// CHECK: fence singlethread seq_cst +// CHECK: fence syncscope("singlethread") seq_cst // CHECK: ret void // CHECK: } diff --git a/test/CodeGen/no-devirt.cpp b/test/CodeGen/no-devirt.cpp index 4333b7cde7c6..544b1394f421 100644 --- a/test/CodeGen/no-devirt.cpp +++ b/test/CodeGen/no-devirt.cpp @@ -21,7 +21,7 @@ public: struct Wrapper { TmplWithArray<bool, 10> data; bool indexIt(int a) { - if (a > 6) return data[a] ; // Should not devirtualize + if (a > 6) return data[a] ; // Should devirtualize if (a > 4) return data.func1(a); // Should devirtualize return data.func2(a); // Should devirtualize } @@ -53,7 +53,7 @@ bool stuff(int p) } #endif -// CHECK-NOT: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi +// CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EEixEi // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func1Ei // CHECK-DAG: call {{.*}} @_ZN13TmplWithArrayIbLi10EE5func2Ei diff --git a/test/CodeGen/pgo-sample-thinlto-summary.c b/test/CodeGen/pgo-sample-thinlto-summary.c index 51c8faa6be6d..7045db08f22e 100644 --- a/test/CodeGen/pgo-sample-thinlto-summary.c +++ b/test/CodeGen/pgo-sample-thinlto-summary.c @@ -1,9 +1,7 @@ // RUN: %clang_cc1 -O2 -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=SAMPLEPGO // RUN: %clang_cc1 -O2 -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -flto=thin -o - 2>&1 | FileCheck %s -check-prefix=THINLTO // RUN: %clang_cc1 -O2 -fexperimental-new-pass-manager -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -o - 2>&1 | FileCheck %s -check-prefix=SAMPLEPGO -// FIXME: Run the following command once LTOPreLinkDefaultPipeline is -// customized. -// %clang_cc1 -O2 -fexperimental-new-pass-manager -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -flto=thin -o - 2>&1 | FileCheck %s -check-prefix=THINLTO +// RUN: %clang_cc1 -O2 -fexperimental-new-pass-manager -fprofile-sample-use=%S/Inputs/pgo-sample-thinlto-summary.prof %s -emit-llvm -flto=thin -o - 2>&1 | FileCheck %s -check-prefix=THINLTO // Checks if hot call is inlined by normal compile, but not inlined by // thinlto compile. diff --git a/test/CodeGenCXX/amdgcn-automatic-variable.cpp b/test/CodeGenCXX/amdgcn-automatic-variable.cpp index 7df27c28e6d2..a82275206c6d 100644 --- a/test/CodeGenCXX/amdgcn-automatic-variable.cpp +++ b/test/CodeGenCXX/amdgcn-automatic-variable.cpp @@ -15,8 +15,8 @@ void func2(void) { // CHECK: %lv1 = alloca i32, align 4, addrspace(5) // CHECK: %lv2 = alloca i32, align 4, addrspace(5) // CHECK: %la = alloca [100 x i32], align 4, addrspace(5) - // CHECK: %lp1 = alloca i32*, align 4, addrspace(5) - // CHECK: %lp2 = alloca i32*, align 4, addrspace(5) + // CHECK: %lp1 = alloca i32*, align 8, addrspace(5) + // CHECK: %lp2 = alloca i32*, align 8, addrspace(5) // CHECK: %lvc = alloca i32, align 4, addrspace(5) // CHECK: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32* @@ -34,12 +34,12 @@ void func2(void) { la[0] = 3; // CHECK: %[[r3:.*]] = addrspacecast i32* addrspace(5)* %lp1 to i32** - // CHECK: store i32* %[[r0]], i32** %[[r3]], align 4 + // CHECK: store i32* %[[r0]], i32** %[[r3]], align 8 int *lp1 = &lv1; // CHECK: %[[r4:.*]] = addrspacecast i32* addrspace(5)* %lp2 to i32** // CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], [100 x i32]* %[[r2]], i32 0, i32 0 - // CHECK: store i32* %[[arraydecay]], i32** %[[r4]], align 4 + // CHECK: store i32* %[[arraydecay]], i32** %[[r4]], align 8 int *lp2 = la; // CHECK: call void @_Z5func1Pi(i32* %[[r0]]) @@ -80,3 +80,5 @@ void func4(int x) { // CHECK: call void @_Z5func1Pi(i32* %[[r0]]) func1(&x); } + +// CHECK-NOT: !opencl.ocl.version diff --git a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp index 7bab11488ad4..67215ef48fb3 100644 --- a/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp +++ b/test/CodeGenCXX/cxx0x-initializer-stdinitializerlist.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-none-linux-gnu -emit-llvm -o - %s | FileCheck -check-prefixes=X86,CHECK %s +// RUN: %clang_cc1 -std=c++11 -triple amdgcn-amd-amdhsa-amdgiz -DNO_TLS -emit-llvm -o - %s | FileCheck -check-prefixes=AMD,CHECK %s namespace std { typedef decltype(sizeof(int)) size_t; @@ -46,54 +47,72 @@ struct wantslist1 { wantslist1(std::initializer_list<destroyme1>); ~wantslist1(); }; - -// CHECK: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3] -// CHECK: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 } +// X86: @_ZGR15globalInitList1_ = internal constant [3 x i32] [i32 1, i32 2, i32 3] +// X86: @globalInitList1 = global %{{[^ ]+}} { i32* getelementptr inbounds ([3 x i32], [3 x i32]* @_ZGR15globalInitList1_, i32 0, i32 0), i{{32|64}} 3 } +// AMD: @_ZGR15globalInitList1_ = internal addrspace(1) constant [3 x i32] [i32 1, i32 2, i32 3] +// AMD: @globalInitList1 = addrspace(1) global %{{[^ ]+}} { i32* addrspacecast (i32 addrspace(1)* getelementptr inbounds ([3 x i32], [3 x i32] addrspace(1)* @_ZGR15globalInitList1_, i32 0, i32 0) to i32*), i{{32|64}} 3 } std::initializer_list<int> globalInitList1 = {1, 2, 3}; +#ifndef NO_TLS namespace thread_local_global_array { - // FIXME: We should be able to constant-evaluate this even though the - // initializer is not a constant expression (pointers to thread_local - // objects aren't really a problem). - // - // CHECK: @_ZN25thread_local_global_array1xE = thread_local global - // CHECK: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4] - std::initializer_list<int> thread_local x = { 1, 2, 3, 4 }; +// FIXME: We should be able to constant-evaluate this even though the +// initializer is not a constant expression (pointers to thread_local +// objects aren't really a problem). +// +// X86: @_ZN25thread_local_global_array1xE = thread_local global +// X86: @_ZGRN25thread_local_global_array1xE_ = internal thread_local constant [4 x i32] [i32 1, i32 2, i32 3, i32 4] +std::initializer_list<int> thread_local x = {1, 2, 3, 4}; } - -// CHECK: @globalInitList2 = global %{{[^ ]+}} zeroinitializer -// CHECK: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer - -// CHECK: @_ZN15partly_constant1kE = global i32 0, align 4 -// CHECK: @_ZN15partly_constant2ilE = global {{.*}} null, align 8 -// CHECK: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8 -// CHECK: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8 -// CHECK: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4 -// CHECK: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4 -// CHECK: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 - -// CHECK: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4 -// CHECK: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4 +#endif + +// X86: @globalInitList2 = global %{{[^ ]+}} zeroinitializer +// X86: @_ZGR15globalInitList2_ = internal global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer +// AMD: @globalInitList2 = addrspace(1) global %{{[^ ]+}} zeroinitializer +// AMD: @_ZGR15globalInitList2_ = internal addrspace(1) global [2 x %[[WITHARG:[^ ]*]]] zeroinitializer + +// X86: @_ZN15partly_constant1kE = global i32 0, align 4 +// X86: @_ZN15partly_constant2ilE = global {{.*}} null, align 8 +// X86: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal global {{.*}} zeroinitializer, align 8 +// X86: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal global [3 x {{.*}}] zeroinitializer, align 8 +// X86: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +// X86: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal global [2 x i32] zeroinitializer, align 4 +// X86: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 +// AMD: @_ZN15partly_constant1kE = addrspace(1) global i32 0, align 4 +// AMD: @_ZN15partly_constant2ilE = addrspace(2) global {{.*}} null, align 8 +// AMD: @[[PARTLY_CONSTANT_OUTER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global {{.*}} zeroinitializer, align 8 +// AMD: @[[PARTLY_CONSTANT_INNER:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [3 x {{.*}}] zeroinitializer, align 8 +// AMD: @[[PARTLY_CONSTANT_FIRST:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +// AMD: @[[PARTLY_CONSTANT_SECOND:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) global [2 x i32] zeroinitializer, align 4 +// AMD: @[[PARTLY_CONSTANT_THIRD:_ZGRN15partly_constant2ilE.*]] = internal addrspace(2) constant [4 x i32] [i32 5, i32 6, i32 7, i32 8], align 4 + +// X86: @[[REFTMP1:.*]] = private constant [2 x i32] [i32 42, i32 43], align 4 +// X86: @[[REFTMP2:.*]] = private constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4 +// AMD: @[[REFTMP1:.*]] = private addrspace(2) constant [2 x i32] [i32 42, i32 43], align 4 +// AMD: @[[REFTMP2:.*]] = private addrspace(2) constant [3 x %{{.*}}] [%{{.*}} { i32 1 }, %{{.*}} { i32 2 }, %{{.*}} { i32 3 }], align 4 // CHECK: appending global - // thread_local initializer: -// CHECK-LABEL: define internal void -// CHECK: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0), -// CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8 -// CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8 - - -// CHECK-LABEL: define internal void -// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0 -// CHECK: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1 -// CHECK: __cxa_atexit -// CHECK: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0), -// CHECK: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8 -// CHECK: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8 -// CHECK: call void @_ZN10destroyme1D1Ev +// X86-LABEL: define internal void @__cxx_global_var_init +// X86: store i32* getelementptr inbounds ([4 x i32], [4 x i32]* @_ZGRN25thread_local_global_array1xE_, i64 0, i64 0), +// X86: i32** getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 0), align 8 +// X86: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZN25thread_local_global_array1xE, i32 0, i32 1), align 8 + +// CHECK-LABEL: define internal void @__cxx_global_var_init +// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 0 +// X86: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i{{32|64}} 0, i{{32|64}} 1 +// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 0 +// AMD: call void @_ZN8witharg1C1ERK10destroyme1(%[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i{{32|64}} 0, i{{32|64}} 1 +// CHECK: call i32 @__cxa_atexit +// X86: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* @_ZGR15globalInitList2_, i64 0, i64 0), +// X86: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 0), align 8 +// X86: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* @globalInitList2, i32 0, i32 1), align 8 +// AMD: store %[[WITHARG]]* getelementptr inbounds ([2 x %[[WITHARG]]], [2 x %[[WITHARG]]]* addrspacecast ({{[^@]+}} @_ZGR15globalInitList2_ {{[^)]+}}), i64 0, i64 0), +// AMD: %[[WITHARG]]** getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 0), align 8 +// AMD: store i64 2, i64* getelementptr inbounds (%{{.*}}, %{{.*}}* addrspacecast ({{[^@]+}} @globalInitList2 {{[^)]+}}), i32 0, i32 1), align 8 // CHECK: call void @_ZN10destroyme1D1Ev +// CHECK-NEXT: call void @_ZN10destroyme1D1Ev +// CHECK-NEXT: ret void std::initializer_list<witharg1> globalInitList2 = { witharg1(destroyme1()), witharg1(destroyme1()) }; @@ -101,7 +120,9 @@ std::initializer_list<witharg1> globalInitList2 = { void fn1(int i) { // CHECK-LABEL: define void @_Z3fn1i // temporary array - // CHECK: [[array:%[^ ]+]] = alloca [3 x i32] + // X86: [[array:%[^ ]+]] = alloca [3 x i32] + // AMD: [[alloca:%[^ ]+]] = alloca [3 x i32], align 4, addrspace(5) + // AMD: [[array:%[^ ]+]] = addrspacecast [3 x i32] addrspace(5)* [[alloca]] to [3 x i32]* // CHECK: getelementptr inbounds [3 x i32], [3 x i32]* [[array]], i{{32|64}} 0 // CHECK-NEXT: store i32 1, i32* // CHECK-NEXT: getelementptr @@ -175,7 +196,6 @@ void fn6() { destroyme2 dm2; // CHECK: call void @_ZN10destroyme2D1Ev } - void fn7() { // CHECK-LABEL: define void @_Z3fn7v // temps should be destroyed before dm2 @@ -366,37 +386,36 @@ namespace partly_constant { std::initializer_list<std::initializer_list<int>> &&il = { { 1, 2, 3 }, { 4, k }, { 5, 6, 7, 8 } }; // First init list. // CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]], - // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_FIRST]], i64 0, i64 0), - // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 0) - // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0, i32 1) + // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_FIRST]]{{.*}}, i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 0) + // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0, i32 1) // CHECK-NOT: @[[PARTLY_CONSTANT_FIRST]], // // Second init list array (non-constant). - // CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0) - // CHECK: load i32, i32* @_ZN15partly_constant1kE - // CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 1) + // CHECK: store i32 4, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0) + // CHECK: load i32, i32* {{.*}}@_ZN15partly_constant1kE + // CHECK: store i32 {{.*}}, i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 1) // // Second init list. - // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_SECOND]], i64 0, i64 0), - // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 0) - // CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 1, i32 1) + // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_SECOND]]{{.*}}, i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 0) + // CHECK: store i64 2, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 1, i32 1) // // Third init list. // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], - // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_THIRD]], i64 0, i64 0), - // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 2, i32 0) - // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* @_ZGRN15partly_constant2ilE4_, i64 0, i64 2, i32 1) + // CHECK: store i32* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_THIRD]]{{.*}}, i64 0, i64 0), + // CHECK: i32** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 2, i32 0) + // CHECK: store i64 4, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@_ZGRN15partly_constant2ilE4_{{.*}}, i64 0, i64 2, i32 1) // CHECK-NOT: @[[PARTLY_CONSTANT_THIRD]], // // Outer init list. - // CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_INNER]], i64 0, i64 0), - // CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 0) - // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* @[[PARTLY_CONSTANT_OUTER]], i32 0, i32 1) + // CHECK: store {{.*}}* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_INNER]]{{.*}}, i64 0, i64 0), + // CHECK: {{.*}}** getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 0) + // CHECK: store i64 3, i64* getelementptr inbounds ({{.*}}, {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, i32 0, i32 1) // // 'il' reference. - // CHECK: store {{.*}}* @[[PARTLY_CONSTANT_OUTER]], {{.*}}** @_ZN15partly_constant2ilE, align 8 + // CHECK: store {{.*}}* {{.*}}@[[PARTLY_CONSTANT_OUTER]]{{.*}}, {{.*}}** {{.*}}@_ZN15partly_constant2ilE{{.*}}, align 8 } - namespace nested { struct A { A(); ~A(); }; struct B { const A &a; ~B(); }; @@ -463,7 +482,7 @@ namespace PR20445 { template<int x> void f() { new MyClass({42, 43}); } template void f<0>(); // CHECK-LABEL: define {{.*}} @_ZN7PR204451fILi0EEEvv( - // CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* @[[REFTMP1]], i64 0, i64 0) + // CHECK: store i32* getelementptr inbounds ([2 x i32], [2 x i32]* {{.*}}@[[REFTMP1]]{{.*}}, i64 0, i64 0) // CHECK: call void @_ZN7PR204456vectorC1ESt16initializer_listIiE( // CHECK: call void @_ZN7PR204457MyClassC1ERKNS_6vectorE( } @@ -476,9 +495,9 @@ namespace ConstExpr { }; void f(std::initializer_list<C>); void g() { -// CHECK-LABEL: _ZN9ConstExpr1gEv -// CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* @[[REFTMP2]], i64 0, i64 0) -// CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE + // CHECK-LABEL: _ZN9ConstExpr1gEv + // CHECK: store %"class.ConstExpr::C"* getelementptr inbounds ([3 x %"class.ConstExpr::C"], [3 x %"class.ConstExpr::C"]* {{.*}}@[[REFTMP2]]{{.*}}, i64 0, i64 0) + // CHECK: call void @_ZN9ConstExpr1fESt16initializer_listINS_1CEE f({C(1), C(2), C(3)}); } } @@ -498,11 +517,13 @@ namespace B19773010 { void f1() { // CHECK-LABEL: @_ZN9B197730102f1Ev testcase a{{"", ENUM_CONSTANT}}; - // CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8 + // X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8 + // AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(2)* @.ref.tmp{{.*}} to [1 x %"struct.B19773010::pair"] addrspace(2)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** %{{.*}}, align 8 } void f2() { // CHECK-LABEL: @_ZN9B197730102f2Ev - // CHECK: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16 + // X86: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* bitcast ([1 x { i8*, i32 }]* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"]*), i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* @_ZZN9B197730102f2EvE1p, i64 0, i64 1, i32 0), align 16 + // AMD: store %"struct.B19773010::pair"* getelementptr inbounds ([1 x %"struct.B19773010::pair"], [1 x %"struct.B19773010::pair"]* addrspacecast{{.*}} bitcast ([1 x { i8*, i32 }] addrspace(1)* @_ZGRZN9B197730102f2EvE1p_ to [1 x %"struct.B19773010::pair"] addrspace(1)*){{.*}}, i64 0, i64 0), %"struct.B19773010::pair"** getelementptr inbounds ([2 x %"class.std::initializer_list.10"], [2 x %"class.std::initializer_list.10"]* addrspacecast{{.*}}@_ZZN9B197730102f2EvE1p{{.*}}, i64 0, i64 1, i32 0), align 8 static std::initializer_list<pair<const char *, E>> a, p[2] = {a, {{"", ENUM_CONSTANT}}}; } diff --git a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp index b90620ab600f..2ab2f759cfe3 100644 --- a/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp +++ b/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp @@ -241,3 +241,53 @@ namespace Test10 { return static_cast<A *>(b)->f(); } } + +namespace Test11 { + // Check that the definitions of Derived's operators are emitted. + + // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev( + // CHECK: call void @_ZN6Test111SIiE7DerivedclEv( + // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE( + // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv( + // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi( + // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv( + // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE( + // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv( + // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi( + class Base { + public: + virtual void operator()() {} + virtual bool operator==(const Base &other) { return false; } + virtual bool operator!() { return false; } + virtual Base &operator[](int i) { return *this; } + }; + + template<class T> + struct S { + class Derived final : public Base { + public: + void operator()() override {} + bool operator==(const Base &other) override { return true; } + bool operator!() override { return true; } + Base &operator[](int i) override { return *this; } + }; + + Derived *ptr = nullptr, *ptr2 = nullptr; + + void foo1() { + if (ptr && ptr2) { + // These calls get devirtualized. Linkage fails if the definitions of + // the called functions are not emitted. + (*ptr)(); + (void)(*ptr == *ptr2); + (void)(!(*ptr)); + (void)((*ptr)[1]); + } + } + }; + + void foo2() { + S<int> *s = new S<int>; + s->foo1(); + } +} diff --git a/test/CodeGenCXX/dllimport-memptr-global.cpp b/test/CodeGenCXX/dllimport-memptr-global.cpp new file mode 100644 index 000000000000..e64537b8b9f9 --- /dev/null +++ b/test/CodeGenCXX/dllimport-memptr-global.cpp @@ -0,0 +1,58 @@ +// Also check that -Wglobal-constructors does the right thing. Strictly +// speaking, this is a Sema test, but this avoids test case duplication. +// RUN: %clang_cc1 -Wglobal-constructors %s -verify -triple i686-windows-msvc -fms-extensions -std=c++11 +// +// RUN: %clang_cc1 %s -emit-llvm -o - -triple i686-windows-msvc -fms-extensions -std=c++11 | FileCheck %s + +struct __declspec(dllimport) Single { + void nonvirt(); + virtual void virt(); +}; + +struct A { int a; }; +struct B { int b; }; +struct __declspec(dllimport) Multi : A, B { + void nonvirt(); + virtual void virt(); +}; + +struct __declspec(dllimport) Virtual : virtual A { + void nonvirt(); + virtual void virt(); +}; + +struct General; +static_assert(sizeof(void (General::*)()) == 16, "force general memptr model"); +struct __declspec(dllimport) General { + void nonvirt(); + virtual void virt(); +}; + +auto mp_single_nv = &Single::nonvirt; // expected-warning {{global constructor}} +auto mp_multi_nv = &Multi::nonvirt; // expected-warning {{global constructor}} +auto mp_virtual_nv = &Virtual::nonvirt; // expected-warning {{global constructor}} +auto mp_general_nv = &General::nonvirt; // expected-warning {{global constructor}} + +auto mp_single_v = &Single::virt; +auto mp_multi_v = &Multi::virt; +auto mp_virtual_v = &Virtual::virt; +auto mp_general_v = &General::virt; + +// All of the non-virtual globals need dynamic initializers. + +// CHECK: @"\01?mp_single_nv@@3P8Single@@AEXXZQ1@" = global i8* null, align 4 +// CHECK: @"\01?mp_multi_nv@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } zeroinitializer, align 4 +// CHECK: @"\01?mp_virtual_nv@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } zeroinitializer, align 4 +// CHECK: @"\01?mp_general_nv@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } zeroinitializer, align 4 + +// CHECK: @"\01?mp_single_v@@3P8Single@@AEXXZQ1@" = global i8* bitcast (void (%struct.Single*, ...)* @"\01??_9Single@@$BA@AE" to i8*), align 4 +// CHECK: @"\01?mp_multi_v@@3P8Multi@@AEXXZQ1@" = global { i8*, i32 } { i8* bitcast (void (%struct.Multi*, ...)* @"\01??_9Multi@@$BA@AE" to i8*), i32 0 }, align 4 +// CHECK: @"\01?mp_virtual_v@@3P8Virtual@@AEXXZQ1@" = global { i8*, i32, i32 } { i8* bitcast (void (%struct.Virtual*, ...)* @"\01??_9Virtual@@$BA@AE" to i8*), i32 0, i32 0 }, align 4 +// CHECK: @"\01?mp_general_v@@3P8General@@AEXXZQ1@" = global { i8*, i32, i32, i32 } { i8* bitcast (void (%struct.General*, ...)* @"\01??_9General@@$BA@AE" to i8*), i32 0, i32 0, i32 0 }, align 4 + +// CHECK: define internal void @_GLOBAL__sub_I{{.*}}() {{.*}} { +// CHECK: call void @"\01??__Emp_single_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_multi_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_virtual_nv@@YAXXZ"() +// CHECK: call void @"\01??__Emp_general_nv@@YAXXZ"() +// CHECK: } diff --git a/test/CodeGenCXX/vtable-available-externally.cpp b/test/CodeGenCXX/vtable-available-externally.cpp index db99f73d9e72..2e2cdbbfeff5 100644 --- a/test/CodeGenCXX/vtable-available-externally.cpp +++ b/test/CodeGenCXX/vtable-available-externally.cpp @@ -275,9 +275,8 @@ struct C { virtual D& operator=(const D&); }; -// Cannot emit D's vtable available_externally, because we cannot create -// a reference to the inline virtual D::operator= function. -// CHECK-TEST11: @_ZTVN6Test111DE = external unnamed_addr constant +// Can emit D's vtable available_externally. +// CHECK-TEST11: @_ZTVN6Test111DE = available_externally unnamed_addr constant struct D : C { virtual void key(); }; diff --git a/test/CodeGenCXX/windows-itanium-type-info.cpp b/test/CodeGenCXX/windows-itanium-type-info.cpp index ad89318f599e..285b59815da2 100644 --- a/test/CodeGenCXX/windows-itanium-type-info.cpp +++ b/test/CodeGenCXX/windows-itanium-type-info.cpp @@ -32,9 +32,15 @@ void f() { // CHECK-DAG: @_ZTV7derived = dllexport unnamed_addr constant // CHECK-DAG: @_ZTI4base = external dllimport constant -// CHECK-DAG: @_ZTS4base = external dllimport constant -// CHECK-NOT: @_ZTV4base = external dllimport constant // CHECK-EH-IMPORT: @_ZTS4base = linkonce_odr constant // CHECK-EH-IMPORT: @_ZTI4base = linkonce_odr constant +struct __declspec(dllimport) gatekeeper {}; +struct zuul : gatekeeper { + virtual ~zuul(); +}; +zuul::~zuul() {} + +// CHECK-DAG: @_ZTI10gatekeeper = linkonce_odr constant +// CHECK-DAG: @_ZTS10gatekeeper = linkonce_odr constant diff --git a/test/CodeGenOpenCL/address-spaces.cl b/test/CodeGenOpenCL/address-spaces.cl index 7c665286547a..488b8f9d480e 100644 --- a/test/CodeGenOpenCL/address-spaces.cl +++ b/test/CodeGenOpenCL/address-spaces.cl @@ -4,6 +4,8 @@ // RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-opencl -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR // RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-amdgizcl -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,GIZ // RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa-amdgizcl -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20GIZ +// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SPIR %s +// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - | FileCheck --check-prefixes=CHECK,SPIR %s // SPIR: i32* %arg // GIZ: i32 addrspace(5)* %arg diff --git a/test/CodeGenOpenCL/amdgcn-automatic-variable.cl b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl index 29309567ec71..19287c7d8998 100644 --- a/test/CodeGenOpenCL/amdgcn-automatic-variable.cl +++ b/test/CodeGenOpenCL/amdgcn-automatic-variable.cl @@ -22,8 +22,8 @@ void func2(void) { // CHECK: %la = alloca [100 x i32], align 4, addrspace(5) // CL12: %lp1 = alloca i32 addrspace(5)*, align 4, addrspace(5) // CL12: %lp2 = alloca i32 addrspace(5)*, align 4, addrspace(5) - // CL20: %lp1 = alloca i32*, align 4, addrspace(5) - // CL20: %lp2 = alloca i32*, align 4, addrspace(5) + // CL20: %lp1 = alloca i32*, align 8, addrspace(5) + // CL20: %lp2 = alloca i32*, align 8, addrspace(5) // CHECK: %lvc = alloca i32, align 4, addrspace(5) // CHECK: store i32 1, i32 addrspace(5)* %lv1 @@ -39,13 +39,13 @@ void func2(void) { // CL12: store i32 addrspace(5)* %lv1, i32 addrspace(5)* addrspace(5)* %lp1, align 4 // CL20: %[[r0:.*]] = addrspacecast i32 addrspace(5)* %lv1 to i32* - // CL20: store i32* %[[r0]], i32* addrspace(5)* %lp1, align 4 + // CL20: store i32* %[[r0]], i32* addrspace(5)* %lp1, align 8 int *lp1 = &lv1; // CHECK: %[[arraydecay:.*]] = getelementptr inbounds [100 x i32], [100 x i32] addrspace(5)* %la, i32 0, i32 0 // CL12: store i32 addrspace(5)* %[[arraydecay]], i32 addrspace(5)* addrspace(5)* %lp2, align 4 // CL20: %[[r1:.*]] = addrspacecast i32 addrspace(5)* %[[arraydecay]] to i32* - // CL20: store i32* %[[r1]], i32* addrspace(5)* %lp2, align 4 + // CL20: store i32* %[[r1]], i32* addrspace(5)* %lp2, align 8 int *lp2 = la; // CL12: call void @func1(i32 addrspace(5)* %lv1) diff --git a/test/CodeGenOpenCL/amdgpu-nullptr.cl b/test/CodeGenOpenCL/amdgpu-nullptr.cl index 402be5760cf7..69f54fcaa483 100644 --- a/test/CodeGenOpenCL/amdgpu-nullptr.cl +++ b/test/CodeGenOpenCL/amdgpu-nullptr.cl @@ -27,13 +27,13 @@ private char *private_p = 0; // CHECK: @local_p = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4 local char *local_p = 0; -// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4 +// CHECK: @global_p = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8 global char *global_p = 0; -// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4 +// CHECK: @constant_p = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8 constant char *constant_p = 0; -// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4 +// CHECK: @generic_p = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8 generic char *generic_p = 0; // Test NULL as initializer. @@ -44,19 +44,19 @@ private char *private_p_NULL = NULL; // CHECK: @local_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4 local char *local_p_NULL = NULL; -// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4 +// CHECK: @global_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8 global char *global_p_NULL = NULL; -// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4 +// CHECK: @constant_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8 constant char *constant_p_NULL = NULL; -// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4 +// CHECK: @generic_p_NULL = local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8 generic char *generic_p_NULL = NULL; // Test constant folding of null pointer. // A null pointer should be folded to a null pointer in the target address space. -// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 4 +// CHECK: @fold_generic = local_unnamed_addr addrspace(1) global i32 addrspace(4)* null, align 8 generic int *fold_generic = (global int*)(generic float*)(private char*)0; // CHECK: @fold_priv = local_unnamed_addr addrspace(1) global i16* null, align 4 @@ -104,8 +104,8 @@ int fold_int5_local = (int) &((local StructTy1*)0)->p2; // NOOPT: @test_static_var_private.sp3 = internal addrspace(1) global i8* null, align 4 // NOOPT: @test_static_var_private.sp4 = internal addrspace(1) global i8* null, align 4 // NOOPT: @test_static_var_private.sp5 = internal addrspace(1) global i8* null, align 4 -// NOOPT: @test_static_var_private.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4 -// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4 +// NOOPT: @test_static_var_private.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 8 +// NOOPT: @test_static_var_private.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8 void test_static_var_private(void) { static private char *sp1 = 0; @@ -123,8 +123,8 @@ void test_static_var_private(void) { // NOOPT: @test_static_var_local.sp3 = internal addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4 // NOOPT: @test_static_var_local.sp4 = internal addrspace(1) global i8 addrspace(3)* null, align 4 // NOOPT: @test_static_var_local.sp5 = internal addrspace(1) global i8 addrspace(3)* null, align 4 -// NOOPT: @test_static_var_local.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4 -// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 4 +// NOOPT: @test_static_var_local.SS1 = internal addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 8 +// NOOPT: @test_static_var_local.SS2 = internal addrspace(1) global %struct.StructTy2 zeroinitializer, align 8 void test_static_var_local(void) { static local char *sp1 = 0; static local char *sp2 = NULL; @@ -143,9 +143,9 @@ void test_static_var_local(void) { // NOOPT: store i8* null, i8** %sp3, align 4 // NOOPT: store i8* null, i8** %sp4, align 4 // NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8* -// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_private.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false) +// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_private.SS1 to i8 addrspace(2)*), i64 32, i32 8, i1 false) // NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8* -// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 4, i1 false) +// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 8, i1 false) void test_func_scope_var_private(void) { private char *sp1 = 0; private char *sp2 = NULL; @@ -163,9 +163,9 @@ void test_func_scope_var_private(void) { // NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)** %sp3, align 4 // NOOPT: store i8 addrspace(3)* null, i8 addrspace(3)** %sp4, align 4 // NOOPT: %[[SS1:.*]] = bitcast %struct.StructTy1* %SS1 to i8* -// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_local.SS1 to i8 addrspace(2)*), i64 32, i32 4, i1 false) +// NOOPT: call void @llvm.memcpy.p0i8.p2i8.i64(i8* %[[SS1]], i8 addrspace(2)* bitcast (%struct.StructTy1 addrspace(2)* @test_func_scope_var_local.SS1 to i8 addrspace(2)*), i64 32, i32 8, i1 false) // NOOPT: %[[SS2:.*]] = bitcast %struct.StructTy2* %SS2 to i8* -// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 4, i1 false) +// NOOPT: call void @llvm.memset.p0i8.i64(i8* %[[SS2]], i8 0, i64 24, i32 8, i1 false) void test_func_scope_var_local(void) { local char *sp1 = 0; local char *sp2 = NULL; @@ -189,28 +189,28 @@ private char *p1; // CHECK: @p2 = weak local_unnamed_addr addrspace(1) global i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), align 4 local char *p2; -// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 4 +// CHECK: @p3 = common local_unnamed_addr addrspace(1) global i8 addrspace(2)* null, align 8 constant char *p3; -// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 4 +// CHECK: @p4 = common local_unnamed_addr addrspace(1) global i8 addrspace(1)* null, align 8 global char *p4; -// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 4 +// CHECK: @p5 = common local_unnamed_addr addrspace(1) global i8 addrspace(4)* null, align 8 generic char *p5; // Test default initialization of sturcture. -// CHECK: @S1 = weak local_unnamed_addr addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 4 +// CHECK: @S1 = weak local_unnamed_addr addrspace(1) global %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, align 8 StructTy1 S1; -// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 4 +// CHECK: @S2 = common local_unnamed_addr addrspace(1) global %struct.StructTy2 zeroinitializer, align 8 StructTy2 S2; // Test default initialization of array. -// CHECK: @A1 = weak local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }], align 4 +// CHECK: @A1 = weak local_unnamed_addr addrspace(1) global [2 x %struct.StructTy1] [%struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }, %struct.StructTy1 { i8* null, i8 addrspace(3)* addrspacecast (i8 addrspace(4)* null to i8 addrspace(3)*), i8 addrspace(2)* null, i8 addrspace(1)* null, i8 addrspace(4)* null }], align 8 StructTy1 A1[2]; -// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 4 +// CHECK: @A2 = common local_unnamed_addr addrspace(1) global [2 x %struct.StructTy2] zeroinitializer, align 8 StructTy2 A2[2]; // Test comparison with 0. @@ -597,7 +597,7 @@ int test_and_ptr(private char* p1, local char* p2) { // Test folding of null pointer in function scope. // NOOPT-LABEL: test_fold_private // NOOPT: call void @test_fold_callee -// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4 +// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 8 // NOOPT: %{{.*}} = sub i64 %{{.*}}, 0 // NOOPT: call void @test_fold_callee // NOOPT: %{{.*}} = add nsw i64 %{{.*}}, 0 @@ -612,7 +612,7 @@ void test_fold_private(void) { // NOOPT-LABEL: test_fold_local // NOOPT: call void @test_fold_callee -// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 4 +// NOOPT: store i32 addrspace(1)* null, i32 addrspace(1)** %glob, align 8 // NOOPT: %{{.*}} = sub i64 %{{.*}}, 0 // NOOPT: call void @test_fold_callee // NOOPT: %{{.*}} = add nsw i64 %{{.*}}, sext (i32 ptrtoint (i32 addrspace(3)* addrspacecast (i32 addrspace(4)* null to i32 addrspace(3)*) to i32) to i64) diff --git a/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl b/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl new file mode 100644 index 000000000000..a5d438933fa4 --- /dev/null +++ b/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -triple r600 -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s + +#ifdef __AMDGCN__ +#define PTSIZE 8 +#else +#define PTSIZE 4 +#endif + +#ifdef cl_khr_fp64 +#pragma OPENCL EXTENSION cl_khr_fp64 : enable +#endif +#ifdef cl_khr_fp16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable +#endif + +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __INTPTR_TYPE__ intptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; +typedef global void *global_ptr_t; +typedef constant void *constant_ptr_t; +typedef local void *local_ptr_t; +typedef private void *private_ptr_t; + +void check(bool); + +void test() { + // CHECK-NOT: call void @check(i1 zeroext false) + check(sizeof(size_t) == PTSIZE); + check(__alignof__(size_t) == PTSIZE); + check(sizeof(intptr_t) == PTSIZE); + check(__alignof__(intptr_t) == PTSIZE); + check(sizeof(uintptr_t) == PTSIZE); + check(__alignof__(uintptr_t) == PTSIZE); + check(sizeof(ptrdiff_t) == PTSIZE); + check(__alignof__(ptrdiff_t) == PTSIZE); + + check(sizeof(char) == 1); + check(__alignof__(char) == 1); + check(sizeof(short) == 2); + check(__alignof__(short) == 2); + check(sizeof(int) == 4); + check(__alignof__(int) == 4); + check(sizeof(long) == 8); + check(__alignof__(long) == 8); +#ifdef cl_khr_fp16 + check(sizeof(half) == 2); + check(__alignof__(half) == 2); +#endif + check(sizeof(float) == 4); + check(__alignof__(float) == 4); +#ifdef cl_khr_fp64 + check(sizeof(double) == 8); + check(__alignof__(double) == 8); +#endif + + check(sizeof(void*) == (__OPENCL_C_VERSION__ >= 200 ? 8 : 4)); + check(__alignof__(void*) == (__OPENCL_C_VERSION__ >= 200 ? 8 : 4)); + check(sizeof(global_ptr_t) == PTSIZE); + check(__alignof__(global_ptr_t) == PTSIZE); + check(sizeof(constant_ptr_t) == PTSIZE); + check(__alignof__(constant_ptr_t) == PTSIZE); + check(sizeof(local_ptr_t) == 4); + check(__alignof__(private_ptr_t) == 4); +} diff --git a/test/Driver/autocomplete.c b/test/Driver/autocomplete.c index f0bdcce5707c..e9e2e992bae9 100644 --- a/test/Driver/autocomplete.c +++ b/test/Driver/autocomplete.c @@ -36,3 +36,7 @@ // MTHREADMODELALL: posix single // RUN: %clang --autocomplete=-mrelocation-model, | FileCheck %s -check-prefix=MRELOCMODELALL // MRELOCMODELALL: dynamic-no-pic pic ropi ropi-rwpi rwpi static +// RUN: %clang --autocomplete=-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CLANG +// MRELOCMODEL_CLANG-NOT: -mrelocation-model +// RUN: %clang --autocomplete=#-mrelocation-mode | FileCheck %s -check-prefix=MRELOCMODEL_CC1 +// MRELOCMODEL_CC1: -mrelocation-model diff --git a/test/Driver/clang_f_opts.c b/test/Driver/clang_f_opts.c index e4b72d69ca3f..c17cec6eba9b 100644 --- a/test/Driver/clang_f_opts.c +++ b/test/Driver/clang_f_opts.c @@ -356,6 +356,8 @@ // RUN: -ftree-vrp \ // RUN: -fno-devirtualize \ // RUN: -fno-devirtualize-speculatively \ +// RUN: -fslp-vectorize-aggressive \ +// RUN: -fno-slp-vectorize-aggressive \ // RUN: %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s // CHECK-WARNING-DAG: optimization flag '-finline-limit=1000' is not supported // CHECK-WARNING-DAG: optimization flag '-finline-limit' is not supported @@ -422,6 +424,8 @@ // CHECK-WARNING-DAG: optimization flag '-ftree-vrp' is not supported // CHECK-WARNING-DAG: optimization flag '-fno-devirtualize' is not supported // CHECK-WARNING-DAG: optimization flag '-fno-devirtualize-speculatively' is not supported +// CHECK-WARNING-DAG: the flag '-fslp-vectorize-aggressive' has been deprecated and will be ignored +// CHECK-WARNING-DAG: the flag '-fno-slp-vectorize-aggressive' has been deprecated and will be ignored // Test that we mute the warning on these // RUN: %clang -### -finline-limit=1000 -Wno-invalid-command-line-argument \ diff --git a/test/Driver/crash report spaces.c b/test/Driver/crash-report-spaces.c index 9bc4626b48b8..3e95a0de2516 100644 --- a/test/Driver/crash report spaces.c +++ b/test/Driver/crash-report-spaces.c @@ -1,6 +1,7 @@ // RUN: rm -rf "%t" // RUN: mkdir "%t" -// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 %clang -fsyntax-only "%s" 2>&1 | FileCheck "%s" +// RUN: cp "%s" "%t/crash report spaces.c" +// RUN: not env TMPDIR="%t" TEMP="%t" TMP="%t" RC_DEBUG_OPTIONS=1 %clang -fsyntax-only "%t/crash report spaces.c" 2>&1 | FileCheck "%s" // RUN: cat "%t/crash report spaces"-*.c | FileCheck --check-prefix=CHECKSRC "%s" // RUN: cat "%t/crash report spaces"-*.sh | FileCheck --check-prefix=CHECKSH "%s" // REQUIRES: crash-recovery diff --git a/test/Driver/darwin-sdk-vs-os-version.c b/test/Driver/darwin-sdk-vs-os-version.c new file mode 100644 index 000000000000..391f4d5a7305 --- /dev/null +++ b/test/Driver/darwin-sdk-vs-os-version.c @@ -0,0 +1,10 @@ +// REQUIRES: system-darwin + +// Ensure that we never pick a version that's based on the SDK that's newer than +// the system version: +// RUN: rm -rf %t/SDKs/MacOSX10.99.99.sdk +// RUN: mkdir -p %t/SDKs/MacOSX10.99.99.sdk +// RUN: %clang -target x86_64-apple-darwin -isysroot %t/SDKs/MacOSX10.99.99.sdk %s -### 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-MACOSX-SYSTEM-VERSION %s + +// CHECK-MACOSX-SYSTEM-VERSION-NOT: 10.99.99" diff --git a/test/Driver/fuchsia.c b/test/Driver/fuchsia.c index 58c2bbe533c9..64d31cc0d38c 100644 --- a/test/Driver/fuchsia.c +++ b/test/Driver/fuchsia.c @@ -12,7 +12,7 @@ // CHECK: Scrt1.o // CHECK-NOT: crti.o // CHECK-NOT: crtbegin.o -// CHECK: "-L[[SYSROOT]]/lib" +// CHECK: "-L[[SYSROOT]]{{/|\\\\}}lib" // CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a" // CHECK: "-lc" // CHECK-NOT: crtend.o diff --git a/test/Driver/fuchsia.cpp b/test/Driver/fuchsia.cpp index 4490f94d0715..4c3f7d29acd8 100644 --- a/test/Driver/fuchsia.cpp +++ b/test/Driver/fuchsia.cpp @@ -1,9 +1,10 @@ // RUN: %clangxx %s -### -no-canonical-prefixes --target=x86_64-unknown-fuchsia \ // RUN: --sysroot=%S/platform 2>&1 -fuse-ld=ld | FileCheck %s // CHECK: {{.*}}clang{{.*}}" "-cc1" +// CHECK: "-triple" "x86_64-fuchsia" // CHECK: "-fuse-init-array" // CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" -// CHECK: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" +// CHECK: "-internal-isystem" "{{.*[/\\]}}x86_64-fuchsia{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" // CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include" // CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu" // CHECK: "--sysroot=[[SYSROOT]]" @@ -13,7 +14,7 @@ // CHECK: Scrt1.o // CHECK-NOT: crti.o // CHECK-NOT: crtbegin.o -// CHECK: "-L[[SYSROOT]]/lib" +// CHECK: "-L[[SYSROOT]]{{/|\\\\}}lib" // CHECK: "-lc++" "-lc++abi" "-lunwind" "-lm" // CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a" // CHECK: "-lc" diff --git a/test/Driver/mips-features.c b/test/Driver/mips-features.c index 69fc20e1f245..b228a2d5781d 100644 --- a/test/Driver/mips-features.c +++ b/test/Driver/mips-features.c @@ -70,6 +70,18 @@ // RUN: | FileCheck --check-prefix=CHECK-NOMMSA %s // CHECK-NOMMSA: "-target-feature" "-msa" // +// -mmt +// RUN: %clang -target mips-linux-gnu -### -c %s \ +// RUN: -mno-mt -mmt 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-MMT %s +// CHECK-MMT: "-target-feature" "+mt" +// +// -mno-mt +// RUN: %clang -target mips-linux-gnu -### -c %s \ +// RUN: -mmt -mno-mt 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-NOMMT %s +// CHECK-NOMMT: "-target-feature" "-mt" +// // -modd-spreg // RUN: %clang -target mips-linux-gnu -### -c %s -mno-odd-spreg -modd-spreg 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK-MODDSPREG %s @@ -247,3 +259,14 @@ // RUN: | FileCheck --check-prefix=CHECK-IMG-SINGLEFLOAT-FPXX %s // CHECK-IMG-SINGLEFLOAT-FPXX: "-target-feature" "+single-float" // CHECK-IMG-SINGLEFLOAT-FPXX: "-target-feature" "+fpxx" + +// -mlong-call +// RUN: %clang -target mips-img-linux-gnu -### -c %s -mlong-calls 2>&1 \ +// RUN: | FileCheck --check-prefix=LONG-CALLS-ON %s +// RUN: %clang -target mips-img-linux-gnu -### -c %s -mno-long-calls 2>&1 \ +// RUN: | FileCheck --check-prefix=LONG-CALLS-OFF %s +// RUN: %clang -target mips-img-linux-gnu -### -c %s 2>&1 \ +// RUN: | FileCheck --check-prefix=LONG-CALLS-DEF %s +// LONG-CALLS-ON: "-target-feature" "+long-calls" +// LONG-CALLS-OFF: "-target-feature" "-long-calls" +// LONG-CALLS-DEF-NOT: "long-calls" diff --git a/test/FixIt/fixit-add-synthesize-to-property.m b/test/FixIt/fixit-add-synthesize-to-property.m new file mode 100644 index 000000000000..19b2f4b73f01 --- /dev/null +++ b/test/FixIt/fixit-add-synthesize-to-property.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +@protocol P1 + +@property int prop; + +@end + +@interface I <P1> + +@end + +@implementation I +@end // CHECK: fix-it:{{.*}}:{[[@LINE]]:1-[[@LINE]]:1}:"@synthesize prop;\n\n" diff --git a/test/Import/direct/Inputs/S.c b/test/Import/direct/Inputs/S.c new file mode 100644 index 000000000000..b0876d27df44 --- /dev/null +++ b/test/Import/direct/Inputs/S.c @@ -0,0 +1,3 @@ +struct S { + int a; +}; diff --git a/test/Import/direct/test.c b/test/Import/direct/test.c new file mode 100644 index 000000000000..5fac24c015dc --- /dev/null +++ b/test/Import/direct/test.c @@ -0,0 +1,5 @@ +// RUN: clang-import-test -direct -import %S/Inputs/S.c -expression %s +void expr() { + struct S MyS; + MyS.a = 3; +} diff --git a/test/Import/enum/Inputs/S.cpp b/test/Import/enum/Inputs/S.cpp new file mode 100644 index 000000000000..8506c68512db --- /dev/null +++ b/test/Import/enum/Inputs/S.cpp @@ -0,0 +1,4 @@ +enum E { + a = 1, + b = 2 +}; diff --git a/test/Import/enum/test.cpp b/test/Import/enum/test.cpp new file mode 100644 index 000000000000..aa68063cb207 --- /dev/null +++ b/test/Import/enum/test.cpp @@ -0,0 +1,4 @@ +// RUN: clang-import-test -import %S/Inputs/S.cpp -expression %s +void expr() { + static_assert(E::a + E::b == 3); +} diff --git a/test/Import/import-overrides/Inputs/Hierarchy.cpp b/test/Import/import-overrides/Inputs/Hierarchy.cpp new file mode 100644 index 000000000000..3f91be765d18 --- /dev/null +++ b/test/Import/import-overrides/Inputs/Hierarchy.cpp @@ -0,0 +1,9 @@ +class Base { +public: + virtual void foo() {} +}; + +class Derived : public Base { +public: + void foo() override {} +}; diff --git a/test/Import/import-overrides/test.cpp b/test/Import/import-overrides/test.cpp new file mode 100644 index 000000000000..ded29cded2ee --- /dev/null +++ b/test/Import/import-overrides/test.cpp @@ -0,0 +1,7 @@ +// RUN: clang-import-test -dump-ast -import %S/Inputs/Hierarchy.cpp -expression %s | FileCheck %s + +// CHECK: Overrides:{{.*}}Base::foo + +void foo() { + Derived d; +} diff --git a/test/Index/Core/index-source-invalid-name.cpp b/test/Index/Core/index-source-invalid-name.cpp new file mode 100644 index 000000000000..1b4b059cd1b3 --- /dev/null +++ b/test/Index/Core/index-source-invalid-name.cpp @@ -0,0 +1,13 @@ +// RUN: c-index-test core -print-source-symbols -- %s -std=c++1z -target x86_64-apple-macosx10.7 | FileCheck %s + +namespace rdar32474406 { +// CHECK: [[@LINE+1]]:6 | function/C | foo | c:@N@rdar32474406@F@foo# | __ZN12rdar324744063fooEv | Decl,RelChild | rel: 1 +void foo(); +// CHECK: [[@LINE+1]]:16 | type-alias/C | Func_t | c:index-source-invalid-name.cpp@N@rdar32474406@T@Func_t | <no-cgname> | Def,RelChild | rel: 1 +typedef void (*Func_t)(); +// CHECK: [[@LINE+4]]:1 | type-alias/C | Func_t | c:index-source-invalid-name.cpp@N@rdar32474406@T@Func_t | <no-cgname> | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | rdar32474406 | c:@N@rdar32474406 +// CHECK: [[@LINE+2]]:14 | function/C | foo | c:@N@rdar32474406@F@foo# | __ZN12rdar324744063fooEv | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | rdar32474406 | c:@N@rdar32474406 +Func_t[] = { foo }; // invalid decomposition +} diff --git a/test/Index/Core/index-source.cpp b/test/Index/Core/index-source.cpp index 6d20fdd48e50..4864d6cf0150 100644 --- a/test/Index/Core/index-source.cpp +++ b/test/Index/Core/index-source.cpp @@ -496,3 +496,19 @@ void localStructuredBindingAndRef() { } } + +namespace rd33122110 { + +struct Outer { + template<typename T> + struct Nested { }; +}; + +} + +template<> +struct rd33122110::Outer::Nested<int>; +// CHECK: [[@LINE-1]]:8 | namespace/C++ | rd33122110 | c:@N@rd33122110 | <no-cgname> | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | Nested | c:@N@rd33122110@S@Outer@S@Nested>#I +// CHECK: [[@LINE-3]]:20 | struct/C++ | Outer | c:@N@rd33122110@S@Outer | <no-cgname> | Ref,RelCont | rel: 1 +// CHECK-NEXT: RelCont | Nested | c:@N@rd33122110@S@Outer@S@Nested>#I diff --git a/test/Index/Core/index-source.m b/test/Index/Core/index-source.m index a64c34ad2ac1..c911973a70d6 100644 --- a/test/Index/Core/index-source.m +++ b/test/Index/Core/index-source.m @@ -413,3 +413,28 @@ void classReceivers() { (void)ClassReceivers.implicit; // CHECK: [[@LINE-1]]:9 | class/ObjC | ClassReceivers | c:objc(cs)ClassReceivers | _OBJC_CLASS_$_ClassReceivers | Ref,RelCont | rel: 1 } + +@interface ImplicitProperties + +- (int)implicit; +- (void)setImplicit:(int)x; + ++ (int)classImplicit; ++ (void)setClassImplicit:(int)y; + +@end + +void testImplicitProperties(ImplicitProperties *c) { + c.implicit = 0; +// CHECK: [[@LINE-1]]:5 | instance-method/ObjC | setImplicit: | c:objc(cs)ImplicitProperties(im)setImplicit: | -[ImplicitProperties setImplicit:] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2 +// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties + c.implicit; +// CHECK: [[@LINE-1]]:5 | instance-method/ObjC | implicit | c:objc(cs)ImplicitProperties(im)implicit | -[ImplicitProperties implicit] | Ref,Call,Dyn,RelRec,RelCall,RelCont | rel: 2 +// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties + ImplicitProperties.classImplicit = 1; +// CHECK: [[@LINE-1]]:22 | class-method/ObjC | setClassImplicit: | c:objc(cs)ImplicitProperties(cm)setClassImplicit: | +[ImplicitProperties setClassImplicit:] | Ref,Call,RelCall,RelCont | rel: 1 +// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties + ImplicitProperties.classImplicit; +// CHECK: [[@LINE-1]]:22 | class-method/ObjC | classImplicit | c:objc(cs)ImplicitProperties(cm)classImplicit | +[ImplicitProperties classImplicit] | Ref,Call,RelCall,RelCont | rel: 1 +// CHECK-NEXT: RelCall,RelCont | testImplicitProperties | c:@F@testImplicitProperties +} diff --git a/test/Index/Inputs/empty.dia b/test/Index/Inputs/empty.dia new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/test/Index/Inputs/empty.dia diff --git a/test/Index/pipe-size.cl b/test/Index/pipe-size.cl index d07d7067da8c..cfe97935ee63 100644 --- a/test/Index/pipe-size.cl +++ b/test/Index/pipe-size.cl @@ -11,6 +11,6 @@ __kernel void testPipe( pipe int test ) // SPIR: store i32 4, i32* %s, align 4 // SPIR64: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)** %test.addr, align 8 // SPIR64: store i32 8, i32* %s, align 4 - // AMD: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)* addrspace(5)* %test.addr, align 4 + // AMD: store %opencl.pipe_t addrspace(1)* %test, %opencl.pipe_t addrspace(1)* addrspace(5)* %test.addr, align 8 // AMD: store i32 8, i32 addrspace(5)* %s, align 4 } diff --git a/test/Index/print-type-declaration.cpp b/test/Index/print-type-declaration.cpp index 31c0a73fcd06..a0953d1e5638 100644 --- a/test/Index/print-type-declaration.cpp +++ b/test/Index/print-type-declaration.cpp @@ -7,6 +7,13 @@ int main() auto b = a; } +enum RegularEnum {}; + +enum class ScopedEnum {}; + // RUN: c-index-test -test-print-type-declaration -std=c++11 %s | FileCheck %s // CHECK: VarDecl=a:6:8 (Definition) [typedeclaration=Test] [typekind=Record] // CHECK: VarDecl=b:7:8 (Definition) [typedeclaration=Test] [typekind=Record] +// CHECK: EnumDecl=RegularEnum:10:6 (Definition) [typedeclaration=RegularEnum] [typekind=Enum] +// CHECK: EnumDecl=ScopedEnum:12:12 (Definition) (scoped) [typedeclaration=ScopedEnum] [typekind=Enum] + diff --git a/test/Index/read-empty-diags.test b/test/Index/read-empty-diags.test new file mode 100644 index 000000000000..cef751c920ab --- /dev/null +++ b/test/Index/read-empty-diags.test @@ -0,0 +1,2 @@ +// RUN: not c-index-test -read-diagnostics %S/Inputs/empty.dia 2>&1 | FileCheck %s +// CHECK: Trouble deserializing file (Invalid File): Invalid diagnostics signature diff --git a/test/Index/usrs.m b/test/Index/usrs.m index 92c3a3fafee2..d0a860e1afad 100644 --- a/test/Index/usrs.m +++ b/test/Index/usrs.m @@ -119,7 +119,7 @@ int test_multi_declaration(void) { // CHECK: usrs.m c:@SA@MyStruct Extent=[15:9 - 18:2] // CHECK: usrs.m c:@SA@MyStruct@FI@wa Extent=[16:3 - 16:9] // CHECK: usrs.m c:@SA@MyStruct@FI@moo Extent=[17:3 - 17:10] -// CHECK: usrs.m c:usrs.m@T@MyStruct Extent=[15:1 - 18:11] +// CHECK: usrs.m c:@T@MyStruct Extent=[15:1 - 18:11] // CHECK: usrs.m c:@E@Pizza Extent=[20:1 - 23:2] // CHECK: usrs.m c:@E@Pizza@CHEESE Extent=[21:3 - 21:9] // CHECK: usrs.m c:@E@Pizza@MUSHROOMS Extent=[22:3 - 22:12] diff --git a/test/Misc/find-diagnostic-id.c b/test/Misc/find-diagnostic-id.c new file mode 100644 index 000000000000..bef66178f96f --- /dev/null +++ b/test/Misc/find-diagnostic-id.c @@ -0,0 +1,5 @@ +// RUN: diagtool find-diagnostic-id warn_unused_variable | FileCheck %s +// RUN: not diagtool find-diagnostic-id warn_unused_vars 2>&1 | FileCheck --check-prefix=ERROR %s + +// CHECK: {{^[0-9]+$}} +// ERROR: error: invalid diagnostic 'warn_unused_vars' diff --git a/test/Modules/missing-flag.cpp b/test/Modules/missing-flag.cpp new file mode 100644 index 000000000000..560183be59e8 --- /dev/null +++ b/test/Modules/missing-flag.cpp @@ -0,0 +1,4 @@ +// RUN: not %clang_cc1 -x c++-module-map %s -emit-module -fmodule-name=Foo -o %t 2>&1 | FileCheck %s +// CHECK: module compilation requires '-fmodules' +module Foo {} +#pragma clang module contents diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 6e01e989a374..ee45ae529961 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -1339,6 +1339,84 @@ Bravo<char> golf; #endif } +namespace Friend { +#if defined(FIRST) +struct T1 {}; +struct S1 { + friend class T1; +}; +#elif defined(SECOND) +struct T1 {}; +struct S1 { + friend T1; +}; +#else +S1 s1; +// expected-error@second.h:* {{'Friend::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T1'}} +// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T1'}} +#endif + +#if defined(FIRST) +struct T2 {}; +struct S2 { + friend class T2; +}; +#elif defined(SECOND) +struct T2 {}; +struct S2 { + friend struct T2; +}; +#else +S2 s2; +// expected-error@second.h:* {{'Friend::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'struct T2'}} +// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T2'}} +#endif + +#if defined(FIRST) +struct T3 {}; +struct S3 { + friend const T3; +}; +#elif defined(SECOND) +struct T3 {}; +struct S3 { + friend T3; +}; +#else +S3 s3; +// expected-error@second.h:* {{'Friend::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T3'}} +// expected-note@first.h:* {{but in 'FirstModule' found friend 'const Friend::T3'}} +#endif + +#if defined(FIRST) +struct T4 {}; +struct S4 { + friend T4; +}; +#elif defined(SECOND) +struct S4 { + friend void T4(); +}; +#else +S4 s4; +// expected-error@second.h:* {{'Friend::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function}} +// expected-note@first.h:* {{but in 'FirstModule' found friend class}} +#endif + +#if defined(FIRST) +struct S5 { + friend void T5a(); +}; +#elif defined(SECOND) +struct S5 { + friend void T5b(); +}; +#else +S5 s5; +// expected-error@second.h:* {{'Friend::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function 'T5b'}} +// expected-note@first.h:* {{but in 'FirstModule' found friend function 'T5a'}} +#endif +} // Interesting cases that should not cause errors. struct S should not error // while struct T should error at the access specifier mismatch at the end. namespace AllDecls { diff --git a/test/Modules/preprocess-build.cpp b/test/Modules/preprocess-build.cpp index bf9f16162be2..36a0740a0a76 100644 --- a/test/Modules/preprocess-build.cpp +++ b/test/Modules/preprocess-build.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++1z %s -verify +// RUN: %clang_cc1 -std=c++1z -fmodules %s -verify #pragma clang module build baz module baz {} diff --git a/test/Modules/relative-dep-gen.cpp b/test/Modules/relative-dep-gen.cpp index e58dd6eb3596..bfa9471859b8 100644 --- a/test/Modules/relative-dep-gen.cpp +++ b/test/Modules/relative-dep-gen.cpp @@ -2,17 +2,17 @@ // RUN: rm -rf %t // RUN: mkdir %t // -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen.modulemap -dependency-file %t/build.d -MT mod.pcm -o %t/mod.pcm -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -fmodule-file=%t/mod.pcm -dependency-file %t/use-explicit.d -MT use.o relative-dep-gen.cpp -fsyntax-only -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -dependency-file %t/use-implicit.d relative-dep-gen.cpp -MT use.o -fsyntax-only +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen.modulemap -dependency-file %t/build.d -MT mod.pcm -o %t/mod.pcm +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen.modulemap -fmodule-file=%t/mod.pcm -dependency-file %t/use-explicit.d -MT use.o relative-dep-gen.cpp -fsyntax-only +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=Inputs/relative-dep-gen.modulemap -dependency-file %t/use-implicit.d relative-dep-gen.cpp -MT use.o -fsyntax-only // // RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build.d -// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit.d -// RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-implicit.d +// RUN: FileCheck --check-prefix=CHECK-USE --check-prefix=CHECK-EXPLICIT %s < %t/use-explicit.d +// RUN: FileCheck --check-prefix=CHECK-USE --check-prefix=CHECK-IMPLICIT %s < %t/use-implicit.d // -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/build-cwd.d -MT mod.pcm -o %t/mod-cwd.pcm -fmodule-map-file-home-is-cwd -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/use-implicit-cwd.d relative-dep-gen.cpp -MT use.o -fsyntax-only -fmodule-map-file-home-is-cwd +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-name=relative-dep-gen -emit-module -x c++ Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/build-cwd.d -MT mod.pcm -o %t/mod-cwd.pcm -fmodule-map-file-home-is-cwd +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd +// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fmodule-map-file=Inputs/relative-dep-gen-cwd.modulemap -dependency-file %t/use-implicit-cwd.d relative-dep-gen.cpp -MT use.o -fsyntax-only -fmodule-map-file-home-is-cwd // // RUN: FileCheck --check-prefix=CHECK-BUILD %s < %t/build-cwd.d // RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit-cwd.d @@ -23,7 +23,7 @@ // RUN: cp %S/Inputs/relative-dep-gen-1.h %t/Inputs // RUN: cp %s %t // RUN: cd %t -// RUN: %clang_cc1 -cc1 -fno-implicit-modules -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-no-map-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd +// RUN: %clang_cc1 -fmodules -fno-implicit-modules -fmodule-file=%t/mod-cwd.pcm -dependency-file %t/use-explicit-no-map-cwd.d -MT use.o relative-dep-gen.cpp -fsyntax-only -fmodule-map-file-home-is-cwd // RUN: cat %t/use-explicit-no-map-cwd.d // RUN: FileCheck --check-prefix=CHECK-USE %s < %t/use-explicit-no-map-cwd.d @@ -35,4 +35,5 @@ // CHECK-BUILD: {{[ \t]}}Inputs/relative-dep-gen-2.h // CHECK-USE: use.o: // CHECK-USE-DAG: {{[ \t]}}relative-dep-gen.cpp -// CHECK-USE-DAG: {{[ \t]}}Inputs{{[/\\]}}relative-dep-gen-1.h +// CHECK-EXPLICIT-DAG: mod.pcm +// CHECK-IMPLICIT-DAG: {{[ \t]}}Inputs{{[/\\]}}relative-dep-gen-1.h diff --git a/test/OpenMP/taskloop_ast_print.cpp b/test/OpenMP/taskloop_ast_print.cpp index 36f90c95dd33..dd0af85916cf 100644 --- a/test/OpenMP/taskloop_ast_print.cpp +++ b/test/OpenMP/taskloop_ast_print.cpp @@ -20,7 +20,7 @@ T tmain(T argc) { // CHECK-NEXT: for (int i = 0; i < 2; ++i) // CHECK-NEXT: a = 2; #pragma omp parallel -#pragma omp taskloop private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) nogroup num_tasks(N) reduction(min:a) +#pragma omp taskloop private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) nogroup num_tasks(N) for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) for (int j = 0; j < 2; ++j) @@ -33,7 +33,7 @@ T tmain(T argc) { for (int j = 0; j < 2; ++j) foo(); // CHECK-NEXT: #pragma omp parallel - // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) nogroup num_tasks(N) reduction(min: a) + // CHECK-NEXT: #pragma omp taskloop private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) nogroup num_tasks(N) // CHECK-NEXT: for (int i = 0; i < 2; ++i) // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: for (int j = 0; j < 2; ++j) @@ -53,8 +53,8 @@ int main(int argc, char **argv) { int b = argc, c, d, e, f, g; static int a; // CHECK: static int a; -#pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc) reduction(*: g) - // CHECK-NEXT: #pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) nogroup num_tasks(argc) reduction(*: g) +#pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) num_tasks(argc) reduction(*: g) + // CHECK-NEXT: #pragma omp taskloop if(taskloop: a) default(none) shared(a) final(b) priority(5) num_tasks(argc) reduction(*: g) for (int i = 0; i < 2; ++i) a = 2; // CHECK-NEXT: for (int i = 0; i < 2; ++i) diff --git a/test/OpenMP/taskloop_codegen.cpp b/test/OpenMP/taskloop_codegen.cpp index bc7367ce0216..b1b45455802a 100644 --- a/test/OpenMP/taskloop_codegen.cpp +++ b/test/OpenMP/taskloop_codegen.cpp @@ -8,6 +8,7 @@ // CHECK-LABEL: @main int main(int argc, char **argv) { // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]]) +// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) // CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*)) // CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]* // CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0 @@ -19,6 +20,7 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 0, i64 0, i8* null) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) #pragma omp taskloop priority(argc) for (int i = 0; i < 10; ++i) ; @@ -33,10 +35,11 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: [[GRAINSIZE:%.+]] = zext i32 %{{.+}} to i64 -// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 1, i32 1, i64 [[GRAINSIZE]], i8* null) +// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 1, i64 [[GRAINSIZE]], i8* null) #pragma omp taskloop nogroup grainsize(argc) for (int i = 0; i < 10; ++i) ; +// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) // CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*)) // CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]* // CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0 @@ -50,6 +53,7 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 [[IF_INT]], i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 2, i64 4, i8* null) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) int i; #pragma omp taskloop if(argc) shared(argc, argv) collapse(2) num_tasks(4) for (i = 0; i < argc; ++i) diff --git a/test/OpenMP/taskloop_reduction_messages.cpp b/test/OpenMP/taskloop_reduction_messages.cpp new file mode 100644 index 000000000000..7295075c3cb8 --- /dev/null +++ b/test/OpenMP/taskloop_reduction_messages.cpp @@ -0,0 +1,331 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +void foobar(int &ref) { +#pragma omp taskloop reduction(+:ref) + for (int i = 0; i < 10; ++i) + foo(); +} + +struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}} + +public: + S2() : a(0) {} + S2(S2 &s2) : a(s2.a) {} + static float S2s; // expected-note 2 {{static data member is predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}} +S2 b; // expected-note 3 {{'b' defined here}} +const S2 ba[5]; // expected-note 2 {{'ba' defined here}} +class S3 { + int a; + +public: + int b; + S3() : a(0) {} + S3(const S3 &s3) : a(s3.a) {} + S3 operator+(const S3 &arg1) { return arg1; } +}; +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } +S3 c; // expected-note 3 {{'c' defined here}} +const S3 ca[5]; // expected-note 2 {{'ca' defined here}} +extern const int f; // expected-note 4 {{'f' declared here}} +class S4 { + int a; + S4(); // expected-note {{implicitly declared private here}} + S4(const S4 &s4); + S4 &operator+(const S4 &arg) { return (*this); } + +public: + S4(int v) : a(v) {} +}; +S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } +class S5 { + int a:32; + S5() : a(0) {} // expected-note {{implicitly declared private here}} + S5(const S5 &s5) : a(s5.a) {} + S5 &operator+(const S5 &arg); + +public: + S5(int v) : a(v) {} +}; +class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} +#if __cplusplus >= 201103L // C++11 or later +// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}} +#endif + int a; + +public: + S6() : a(6) {} + operator int() { return 6; } +} o; + +struct S7 { + int a: 32; + S7() { +#pragma omp taskloop reduction(+:a) // expected-error {{expected addressable reduction item for the task-based directives}} + for (int i = 0; i < 10; ++i) + ++a; + } +}; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} + +template <class T> // expected-note {{declared here}} +T tmain(T argc) { + const T d = T(); // expected-note 4 {{'d' defined here}} + const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} + T qa[5] = {T()}; + T i; + T &j = i; // expected-note 4 {{'j' defined here}} + S3 &p = k; // expected-note 2 {{'p' defined here}} + const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} + T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} + T fl; +#pragma omp taskloop reduction // expected-error {{expected '(' after 'reduction'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : argc) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(^ : T) // expected-error {{'T' does not refer to a value}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(max : h.b) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : o) // expected-error 2 {{no viable overloaded '='}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(k) +#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 2 {{previously referenced here}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel shared(i) +#pragma omp parallel reduction(min : i) +#pragma omp taskloop reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(fl) +#pragma omp taskloop reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel reduction(* : fl) +#pragma omp taskloop reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); + + return T(); +} + +namespace A { +double x; +#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}} +} +namespace B { +using A::x; +} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = {0}; // expected-note {{'da' defined here}} + int qa[5] = {0}; + S4 e(4); + S5 g(5); + int i; + int &j = i; // expected-note 2 {{'j' defined here}} + S3 &p = k; // expected-note 2 {{'p' defined here}} + const int &r = da[i]; // expected-note {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; +#pragma omp taskloop reduction // expected-error {{expected '(' after 'reduction'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop' are ignored}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(~ : argc) // expected-error {{expected unqualified-id}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : argc) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(max : h.b) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : o) // expected-error {{no viable overloaded '='}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(k) +#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel shared(i) +#pragma omp parallel reduction(min : i) +#pragma omp taskloop reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(fl) +#pragma omp taskloop reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel reduction(* : fl) +#pragma omp taskloop reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); + static int m; +#pragma omp taskloop reduction(+ : m) // OK + for (int i = 0; i < 10; ++i) + m++; +#pragma omp taskloop nogroup reduction(+ : m) // expected-error {{'reduction' clause cannot be used with 'nogroup' clause}} + for (int i = 0; i < 10; ++i) + m++; + + return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}} +} diff --git a/test/OpenMP/taskloop_simd_ast_print.cpp b/test/OpenMP/taskloop_simd_ast_print.cpp index 9bee8f7f93fd..8678b9122e29 100644 --- a/test/OpenMP/taskloop_simd_ast_print.cpp +++ b/test/OpenMP/taskloop_simd_ast_print.cpp @@ -21,7 +21,7 @@ T tmain(T argc) { // CHECK-NEXT: for (int i = 0; i < 2; ++i) // CHECK-NEXT: a = 2; #pragma omp parallel -#pragma omp taskloop simd private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N) reduction(min:a) +#pragma omp taskloop simd private(argc, b), firstprivate(c, d), lastprivate(d, f) collapse(N) shared(g) if (c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N) for (int i = 0; i < 2; ++i) for (int j = 0; j < 2; ++j) for (int j = 0; j < 2; ++j) @@ -34,7 +34,7 @@ T tmain(T argc) { for (int j = 0; j < 2; ++j) foo(); // CHECK-NEXT: #pragma omp parallel - // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N) reduction(min: a) + // CHECK-NEXT: #pragma omp taskloop simd private(argc,b) firstprivate(c,d) lastprivate(d,f) collapse(N) shared(g) if(c) final(d) mergeable priority(f) simdlen(N) nogroup num_tasks(N) // CHECK-NEXT: for (int i = 0; i < 2; ++i) // CHECK-NEXT: for (int j = 0; j < 2; ++j) // CHECK-NEXT: for (int j = 0; j < 2; ++j) @@ -54,8 +54,8 @@ int main(int argc, char **argv) { int b = argc, c, d, e, f, g; static int a; // CHECK: static int a; -#pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b), aligned(argv) nogroup num_tasks(argc) reduction(*: g) - // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b) aligned(argv) nogroup num_tasks(argc) reduction(*: g) +#pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b), aligned(argv) num_tasks(argc) reduction(*: g) + // CHECK-NEXT: #pragma omp taskloop simd if(taskloop: a) default(none) shared(a) final(b) priority(5) safelen(8) linear(b) aligned(argv) num_tasks(argc) reduction(*: g) for (int i = 0; i < 2; ++i) a = 2; // CHECK-NEXT: for (int i = 0; i < 2; ++i) diff --git a/test/OpenMP/taskloop_simd_codegen.cpp b/test/OpenMP/taskloop_simd_codegen.cpp index 60ba5f22129b..48c6f479e9fa 100644 --- a/test/OpenMP/taskloop_simd_codegen.cpp +++ b/test/OpenMP/taskloop_simd_codegen.cpp @@ -8,6 +8,7 @@ // CHECK-LABEL: @main int main(int argc, char **argv) { // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(%ident_t* [[DEFLOC:@.+]]) +// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) // CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 33, i64 72, i64 1, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK1:@.+]] to i32 (i32, i8*)*)) // CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]* // CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0 @@ -19,6 +20,7 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 0, i64 0, i8* null) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) #pragma omp taskloop simd priority(argc) for (int i = 0; i < 10; ++i) ; @@ -33,10 +35,11 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: [[GRAINSIZE:%.+]] = zext i32 %{{.+}} to i64 -// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 1, i32 1, i64 [[GRAINSIZE]], i8* null) +// CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 1, i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 1, i64 [[GRAINSIZE]], i8* null) #pragma omp taskloop simd nogroup grainsize(argc) simdlen(4) for (int i = 0; i < 10; ++i) ; +// CHECK: call void @__kmpc_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) // CHECK: [[TASKV:%.+]] = call i8* @__kmpc_omp_task_alloc(%ident_t* [[DEFLOC]], i32 [[GTID]], i32 1, i64 72, i64 24, i32 (i32, i8*)* bitcast (i32 (i32, [[TDP_TY:%.+]]*)* [[TASK3:@.+]] to i32 (i32, i8*)*)) // CHECK: [[TASK:%.+]] = bitcast i8* [[TASKV]] to [[TDP_TY]]* // CHECK: [[TASK_DATA:%.+]] = getelementptr inbounds [[TDP_TY]], [[TDP_TY]]* [[TASK]], i32 0, i32 0 @@ -50,6 +53,7 @@ int main(int argc, char **argv) { // CHECK: store i64 1, i64* [[ST]], // CHECK: [[ST_VAL:%.+]] = load i64, i64* [[ST]], // CHECK: call void @__kmpc_taskloop(%ident_t* [[DEFLOC]], i32 [[GTID]], i8* [[TASKV]], i32 [[IF_INT]], i64* [[DOWN]], i64* [[UP]], i64 [[ST_VAL]], i32 0, i32 2, i64 4, i8* null) +// CHECK: call void @__kmpc_end_taskgroup(%ident_t* [[DEFLOC]], i32 [[GTID]]) int i; #pragma omp taskloop simd if(argc) shared(argc, argv) collapse(2) num_tasks(4) safelen(32) for (i = 0; i < argc; ++i) diff --git a/test/OpenMP/taskloop_simd_reduction_messages.cpp b/test/OpenMP/taskloop_simd_reduction_messages.cpp new file mode 100644 index 000000000000..f9739f708a28 --- /dev/null +++ b/test/OpenMP/taskloop_simd_reduction_messages.cpp @@ -0,0 +1,331 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -std=c++98 -ferror-limit 150 -o - %s +// RUN: %clang_cc1 -verify -fopenmp -std=c++11 -ferror-limit 150 -o - %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +void foobar(int &ref) { +#pragma omp taskloop simd reduction(+:ref) + for (int i = 0; i < 10; ++i) + foo(); +} + +struct S1; // expected-note {{declared here}} expected-note 4 {{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; + S2 &operator+(const S2 &arg) { return (*this); } // expected-note 3 {{implicitly declared private here}} + +public: + S2() : a(0) {} + S2(S2 &s2) : a(s2.a) {} + static float S2s; // expected-note 2 {{static data member is predetermined as shared}} + static const float S2sc; +}; +const float S2::S2sc = 0; // expected-note 2 {{'S2sc' defined here}} +S2 b; // expected-note 3 {{'b' defined here}} +const S2 ba[5]; // expected-note 2 {{'ba' defined here}} +class S3 { + int a; + +public: + int b; + S3() : a(0) {} + S3(const S3 &s3) : a(s3.a) {} + S3 operator+(const S3 &arg1) { return arg1; } +}; +int operator+(const S3 &arg1, const S3 &arg2) { return 5; } +S3 c; // expected-note 3 {{'c' defined here}} +const S3 ca[5]; // expected-note 2 {{'ca' defined here}} +extern const int f; // expected-note 4 {{'f' declared here}} +class S4 { + int a; + S4(); // expected-note {{implicitly declared private here}} + S4(const S4 &s4); + S4 &operator+(const S4 &arg) { return (*this); } + +public: + S4(int v) : a(v) {} +}; +S4 &operator&=(S4 &arg1, S4 &arg2) { return arg1; } +class S5 { + int a; + S5() : a(0) {} // expected-note {{implicitly declared private here}} + S5(const S5 &s5) : a(s5.a) {} + S5 &operator+(const S5 &arg); + +public: + S5(int v) : a(v) {} +}; +class S6 { // expected-note 3 {{candidate function (the implicit copy assignment operator) not viable: no known conversion from 'int' to 'const S6' for 1st argument}} +#if __cplusplus >= 201103L // C++11 or later +// expected-note@-2 3 {{candidate function (the implicit move assignment operator) not viable}} +#endif + int a; + +public: + S6() : a(6) {} + operator int() { return 6; } +} o; + +struct S7 { + int a: 32; + S7() { +#pragma omp taskloop reduction(+:a) // expected-error {{expected addressable reduction item for the task-based directives}} + for (int i = 0; i < 10; ++i) + ++a; + } +}; + +S3 h, k; +#pragma omp threadprivate(h) // expected-note 2 {{defined as threadprivate or thread local}} + +template <class T> // expected-note {{declared here}} +T tmain(T argc) { + const T d = T(); // expected-note 4 {{'d' defined here}} + const T da[5] = {T()}; // expected-note 2 {{'da' defined here}} + T qa[5] = {T()}; + T i; + T &j = i; // expected-note 4 {{'j' defined here}} + S3 &p = k; // expected-note 2 {{'p' defined here}} + const T &r = da[(int)i]; // expected-note 2 {{'r' defined here}} + T &q = qa[(int)i]; // expected-note 2 {{'q' defined here}} + T fl; +#pragma omp taskloop simd reduction // expected-error {{expected '(' after 'reduction'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(& : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(|| : argc ? i : argc) // expected-error 2 {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(foo : argc) //expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'float'}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max' or declare reduction for type 'int'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : argc) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(^ : T) // expected-error {{'T' does not refer to a value}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 3 {{const-qualified list item cannot be reduction}} expected-error 2 {{'operator+' is a private member of 'S2'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 4 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 3 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(max : h.b) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : h, k) // expected-error {{threadprivate or thread local variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : o) // expected-error 2 {{no viable overloaded '='}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 4 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(k) +#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{variable can appear only once in OpenMP 'reduction' clause}} expected-note 2 {{previously referenced here}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : r) // expected-error 2 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel shared(i) +#pragma omp parallel reduction(min : i) +#pragma omp taskloop simd reduction(max : j) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(fl) +#pragma omp taskloop simd reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel reduction(* : fl) +#pragma omp taskloop simd reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); + + return T(); +} + +namespace A { +double x; +#pragma omp threadprivate(x) // expected-note {{defined as threadprivate or thread local}} +} +namespace B { +using A::x; +} + +int main(int argc, char **argv) { + const int d = 5; // expected-note 2 {{'d' defined here}} + const int da[5] = {0}; // expected-note {{'da' defined here}} + int qa[5] = {0}; + S4 e(4); + S5 g(5); + int i; + int &j = i; // expected-note 2 {{'j' defined here}} + S3 &p = k; // expected-note 2 {{'p' defined here}} + const int &r = da[i]; // expected-note {{'r' defined here}} + int &q = qa[i]; // expected-note {{'q' defined here}} + float fl; +#pragma omp taskloop simd reduction // expected-error {{expected '(' after 'reduction'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction + // expected-error {{expected '(' after 'reduction'}} expected-warning {{extra tokens at the end of '#pragma omp taskloop simd' are ignored}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction( // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(- // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction() // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(*) // expected-warning {{missing ':' after reduction identifier - ignoring}} expected-error {{expected expression}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(\) // expected-error {{expected unqualified-id}} expected-warning {{missing ':' after reduction identifier - ignoring}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(foo : argc // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', '&&', '||', 'min' or 'max'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(| : argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(|| : argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(~ : argc) // expected-error {{expected unqualified-id}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : argc) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(^ : S1) // expected-error {{'S1' does not refer to a value}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{const-qualified list item cannot be reduction}} expected-error {{'operator+' is a private member of 'S2'}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(min : a, b, c, d, f) // expected-error {{a reduction list item with incomplete type 'S1'}} expected-error 2 {{arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of arithmetic type}} expected-error 2 {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(max : h.b) // expected-error {{expected variable name, array element or array section}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : ba) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(* : ca) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(- : da) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(^ : fl) // expected-error {{invalid operands to binary expression ('float' and 'float')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : S2::S2s) // expected-error {{shared variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(&& : S2::S2sc) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(& : e, g) // expected-error {{calling a private constructor of class 'S4'}} expected-error {{invalid operands to binary expression ('S4' and 'S4')}} expected-error {{calling a private constructor of class 'S5'}} expected-error {{invalid operands to binary expression ('S5' and 'S5')}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : h, k, B::x) // expected-error 2 {{threadprivate or thread local variable cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : o) // expected-error {{no viable overloaded '='}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd private(i), reduction(+ : j), reduction(+ : q) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(k) +#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error 2 {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : p), reduction(+ : p) // expected-error {{variable can appear only once in OpenMP 'reduction' clause}} expected-note {{previously referenced here}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp taskloop simd reduction(+ : r) // expected-error {{const-qualified list item cannot be reduction}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel shared(i) +#pragma omp parallel reduction(min : i) +#pragma omp taskloop simd reduction(max : j) // expected-error {{argument of OpenMP clause 'reduction' must reference the same object in all threads}} + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel private(fl) +#pragma omp taskloop simd reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); +#pragma omp parallel reduction(* : fl) +#pragma omp taskloop simd reduction(+ : fl) + for (int i = 0; i < 10; ++i) + foo(); + static int m; +#pragma omp taskloop simd reduction(+ : m) // OK + for (int i = 0; i < 10; ++i) + m++; +#pragma omp taskloop simd reduction(+ : m) nogroup // expected-error {{'reduction' clause cannot be used with 'nogroup' clause}} + for (int i = 0; i < 10; ++i) + m++; + + return tmain(argc) + tmain(fl); // expected-note {{in instantiation of function template specialization 'tmain<int>' requested here}} expected-note {{in instantiation of function template specialization 'tmain<float>' requested here}} +} diff --git a/test/Preprocessor/init.c b/test/Preprocessor/init.c index 0bd9e9784599..0ee7edecb3c4 100644 --- a/test/Preprocessor/init.c +++ b/test/Preprocessor/init.c @@ -2185,13 +2185,13 @@ // ARMV6-CLOUDABI:#define __CloudABI__ 1 // ARMV6-CLOUDABI:#define __arm__ 1 -// RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-netbsd-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NETBSD %s -// +// RUN: %clang -E -dM -ffreestanding -target arm-netbsd-eabi %s -o - | FileCheck -match-full-lines -check-prefix ARM-NETBSD %s + // ARM-NETBSD-NOT:#define _LP64 // ARM-NETBSD:#define __APCS_32__ 1 // ARM-NETBSD-NOT:#define __ARMEB__ 1 // ARM-NETBSD:#define __ARMEL__ 1 -// ARM-NETBSD:#define __ARM_ARCH_4T__ 1 +// ARM-NETBSD:#define __ARM_ARCH_5TE__ 1 // ARM-NETBSD:#define __ARM_DWARF_EH__ 1 // ARM-NETBSD:#define __ARM_EABI__ 1 // ARM-NETBSD-NOT:#define __ARM_BIG_ENDIAN 1 @@ -2333,6 +2333,7 @@ // ARM-NETBSD:#define __SIZE_MAX__ 4294967295UL // ARM-NETBSD:#define __SIZE_TYPE__ long unsigned int // ARM-NETBSD:#define __SIZE_WIDTH__ 32 +// ARM-NETBSD:#define __SOFTFP__ 1 // ARM-NETBSD:#define __UINT16_C_SUFFIX__ // ARM-NETBSD:#define __UINT16_MAX__ 65535 // ARM-NETBSD:#define __UINT16_TYPE__ unsigned short @@ -2377,6 +2378,11 @@ // ARM-NETBSD:#define __arm 1 // ARM-NETBSD:#define __arm__ 1 +// RUN: %clang -E -dM -ffreestanding -target arm-netbsd-eabihf %s -o - | FileCheck -match-full-lines -check-prefix ARMHF-NETBSD %s +// ARMHF-NETBSD:#define __SIZE_WIDTH__ 32 +// ARMHF-NETBSD-NOT:#define __SOFTFP__ 1 +// ARMHF-NETBSD:#define __UINT16_C_SUFFIX__ + // RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s // RUN: %clang_cc1 -E -dM -ffreestanding -triple=arm-none-eabihf < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s // RUN: %clang_cc1 -E -dM -ffreestanding -triple=aarch64-none-eabi < /dev/null | FileCheck -match-full-lines -check-prefix ARM-NONE-EABI %s diff --git a/test/Rewriter/objc-modern-metadata-visibility2.mm b/test/Rewriter/objc-modern-metadata-visibility2.mm new file mode 100644 index 000000000000..4e64ac4beb46 --- /dev/null +++ b/test/Rewriter/objc-modern-metadata-visibility2.mm @@ -0,0 +1,45 @@ +// REQUIRES: abi-breaking-checks +// NOTE: This test has been split from objc-modern-metadata-visibility.mm in +// order to test with -reverse-iterate as this flag is only present with +// ABI_BREAKING_CHECKS. + +// RUN: %clang_cc1 -E %s -o %t.mm -mllvm -reverse-iterate +// RUN: %clang_cc1 -x objective-c++ -fblocks -fms-extensions -rewrite-objc %t.mm -mllvm -reverse-iterate -o - | FileCheck %s +// rdar://11144048 + +@class NSString; + +@interface NSObject { + Class isa; +} +@end + +@interface Sub : NSObject { + int subIvar; + NSString *nsstring; +@private + id PrivateIvar; +} +@end + +@implementation Sub +- (id) MyNSString { return subIvar ? PrivateIvar : nsstring; } +@end + +@interface NSString @end +@implementation NSString @end + +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllimport) unsigned long OBJC_IVAR_$_Sub$subIvar; +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" unsigned long OBJC_IVAR_$_Sub$PrivateIvar; +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllimport) unsigned long OBJC_IVAR_$_Sub$nsstring; +// CHECK: #pragma warning(disable:4273) +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllexport) unsigned long int OBJC_IVAR_$_Sub$subIvar +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" __declspec(dllexport) unsigned long int OBJC_IVAR_$_Sub$nsstring +// CHECK: __declspec(allocate(".objc_ivar$B")) extern "C" unsigned long int OBJC_IVAR_$_Sub$PrivateIvar +// CHECK: extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject; +// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_Sub +// CHECK: extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject; +// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_Sub +// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_NSString; +// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_NSString +// CHECK: extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_NSString diff --git a/test/Sema/address-packed.c b/test/Sema/address-packed.c index 2799e19c48f1..b0519bacd758 100644 --- a/test/Sema/address-packed.c +++ b/test/Sema/address-packed.c @@ -329,3 +329,12 @@ void g13(void) { uint32_t *p32; p32 = &a[0].x; // no-warning } + +struct Invalid0 { + void *x; + struct fwd f; // expected-error {{incomplete type}} expected-note {{forward declaration}} +} __attribute__((packed)); + +void *g14(struct Invalid0 *ivl) { + return &(ivl->x); +} diff --git a/test/Sema/attr-availability.c b/test/Sema/attr-availability.c index e105037c8ed0..1b8cbd256ce9 100644 --- a/test/Sema/attr-availability.c +++ b/test/Sema/attr-availability.c @@ -21,6 +21,9 @@ ATSFontGetPostScriptName(int flags) __attribute__((availability(macosx,introduce extern void PartiallyAvailable() __attribute__((availability(macosx,introduced=10.8))); +#ifdef WARN_PARTIAL +// expected-note@+2 2 {{marked partial here}} +#endif enum __attribute__((availability(macosx,introduced=10.8))) PartialEnum { kPartialEnumConstant, }; @@ -35,11 +38,19 @@ void test_10095131() { PartiallyAvailable(); } +#ifdef WARN_PARTIAL +// FIXME: This note should point to the declaration with the availability +// attribute. +// expected-note@+2 {{marked partial here}} +#endif extern void PartiallyAvailable() ; void with_redeclaration() { - PartiallyAvailable(); // Don't warn. - - // enums should never warn. +#ifdef WARN_PARTIAL + // expected-warning@+4 {{'PartiallyAvailable' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}} + // expected-warning@+4 {{'PartialEnum' is only available on macOS 10.8 or newer}} expected-note@+4 {{__builtin_available}} + // expected-warning@+3 {{'kPartialEnumConstant' is only available on macOS 10.8 or newer}} expected-note@+3 {{__builtin_available}} +#endif + PartiallyAvailable(); enum PartialEnum p = kPartialEnumConstant; } @@ -86,13 +97,13 @@ enum Original { OriginalUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'OriginalUnavailable' has been explicitly marked unavailable here}} }; -enum AllDeprecated { - AllDeprecatedCase, // expected-note + {{'AllDeprecatedCase' has been explicitly marked deprecated here}} +enum AllDeprecated { // expected-note + {{'AllDeprecated' has been explicitly marked deprecated here}} + AllDeprecatedCase, AllDeprecatedUnavailable __attribute__((availability(macosx, unavailable))) // expected-note + {{'AllDeprecatedUnavailable' has been explicitly marked unavailable here}} } __attribute__((availability(macosx, deprecated=10.2))); -enum AllUnavailable { - AllUnavailableCase, // expected-note + {{'AllUnavailableCase' has been explicitly marked unavailable here}} +enum AllUnavailable { // expected-note + {{'AllUnavailable' has been explicitly marked unavailable here}} + AllUnavailableCase, } __attribute__((availability(macosx, unavailable))); enum User { diff --git a/test/Sema/attr-deprecated.c b/test/Sema/attr-deprecated.c index 89c06860fb4e..9eeef5aed57d 100644 --- a/test/Sema/attr-deprecated.c +++ b/test/Sema/attr-deprecated.c @@ -104,9 +104,9 @@ foo_dep test17, // expected-warning {{'foo_dep' is deprecated}} test19; // rdar://problem/8518751 -enum __attribute__((deprecated)) Test20 { // expected-note {{'Test20' has been explicitly marked deprecated here}} +enum __attribute__((deprecated)) Test20 { // expected-note 2 {{'Test20' has been explicitly marked deprecated here}} test20_a __attribute__((deprecated)), // expected-note {{'test20_a' has been explicitly marked deprecated here}} - test20_b // expected-note {{'test20_b' has been explicitly marked deprecated here}} + test20_b }; void test20() { enum Test20 f; // expected-warning {{'Test20' is deprecated}} diff --git a/test/Sema/attr-unavailable-message.c b/test/Sema/attr-unavailable-message.c index 415cb2f079a2..70d5947086f9 100644 --- a/test/Sema/attr-unavailable-message.c +++ b/test/Sema/attr-unavailable-message.c @@ -36,13 +36,13 @@ void unavail(void) { // rdar://10201690 enum foo { - a = 1, // expected-note {{'a' has been explicitly marked deprecated here}} + a = 1, b __attribute__((deprecated())) = 2, // expected-note {{'b' has been explicitly marked deprecated here}} c = 3 -}__attribute__((deprecated())); +}__attribute__((deprecated())); // expected-note {{'foo' has been explicitly marked deprecated here}} -enum fee { // expected-note {{'fee' has been explicitly marked unavailable here}} - r = 1, // expected-note {{'r' has been explicitly marked unavailable here}} +enum fee { // expected-note 2 {{'fee' has been explicitly marked unavailable here}} + r = 1, s = 2, t = 3 }__attribute__((unavailable())); diff --git a/test/Sema/loop-control.c b/test/Sema/loop-control.c index 6c33e8437bd0..1fc35d10218e 100644 --- a/test/Sema/loop-control.c +++ b/test/Sema/loop-control.c @@ -119,3 +119,51 @@ void pr8880_23(int x, int y) { for ( ; ({ ++y; break; y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}} } } + +void pr32648_1(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; switch (y) { case 0: break; } y;}); ++y) {} // no warning + } +} + +void pr32648_2(int x, int y) { + while(x) { + for ( ; ({ ++y; switch (y) { case 0: continue; } y;}); ++y) {} // expected-warning {{'continue' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_3(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; for (; y; y++) { break; } y;}); ++y) {} // no warning + } +} + +void pr32648_4(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; for (({ break; }); y; y++) { } y;}); ++y) {} // expected-warning{{'break' is bound to loop, GCC binds it to switch}} + } +} + +void pr32648_5(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; while (({ break; y; })) {} y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_6(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; do {} while (({ break; y; })); y;}); ++y) {} // expected-warning{{'break' is bound to current loop, GCC binds it to the enclosing loop}} + } +} + +void pr32648_7(int x, int y) { + switch(x) { + case 1: + for ( ; ({ ++y; do { break; } while (y); y;}); ++y) {} // no warning + } +} diff --git a/test/Sema/warn-cast-qual.c b/test/Sema/warn-cast-qual.c index dc11f5717ebe..a682cad75ed6 100644 --- a/test/Sema/warn-cast-qual.c +++ b/test/Sema/warn-cast-qual.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -x c++ -fsyntax-only -Wcast-qual -verify %s #include <stdint.h> @@ -26,4 +27,34 @@ void foo() { const char **charptrptrc; char **charptrptr = (char **)charptrptrc; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + + const char *constcharptr; + char *charptr = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *constcharptr2 = (char *)constcharptr; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} + const char *charptr2 = (char *)charptr; // no warning +} + +void bar_0() { + struct C { + const int a; + int b; + }; + + const struct C S = {0, 0}; + + *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + *(int *)(&S.b) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} +} + +void bar_1() { + struct C { + const int a; + int b; + }; + + struct C S = {0, 0}; + S.b = 0; // no warning + + *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + *(int *)(&S.b) = 0; // no warning } diff --git a/test/Sema/warn-documentation.cpp b/test/Sema/warn-documentation.cpp index 0c92b2aa029f..ccf374ccd060 100644 --- a/test/Sema/warn-documentation.cpp +++ b/test/Sema/warn-documentation.cpp @@ -1186,7 +1186,7 @@ class Predicate /// @brief A C++ wrapper class for providing threaded access to a value /// of type T. /// -/// A template specilization class. +/// A template specialization class. //---------------------------------------------------------------------- template<> class Predicate<int, char> { diff --git a/test/SemaCXX/amdgpu-sizeof-alignof.cpp b/test/SemaCXX/amdgpu-sizeof-alignof.cpp new file mode 100644 index 000000000000..97da71a1a3e2 --- /dev/null +++ b/test/SemaCXX/amdgpu-sizeof-alignof.cpp @@ -0,0 +1,47 @@ +// RUN: %clang_cc1 -triple amdgcn---amdgiz -std=c++11 -fsyntax-only -verify %s +// expected-no-diagnostics +typedef __SIZE_TYPE__ size_t; +typedef __PTRDIFF_TYPE__ ptrdiff_t; +typedef __INTPTR_TYPE__ intptr_t; +typedef __UINTPTR_TYPE__ uintptr_t; +typedef __attribute__((address_space(1))) void *global_ptr_t; +typedef __attribute__((address_space(2))) void *constant_ptr_t; +typedef __attribute__((address_space(3))) void *local_ptr_t; +typedef __attribute__((address_space(5))) void *private_ptr_t; + +void test() { + static_assert(sizeof(size_t) == 8, "bad size"); + static_assert(alignof(size_t) == 8, "bad alignment"); + static_assert(sizeof(intptr_t) == 8, "bad size"); + static_assert(alignof(intptr_t) == 8, "bad alignment"); + static_assert(sizeof(uintptr_t) == 8, "bad size"); + static_assert(alignof(uintptr_t) == 8, "bad alignment"); + static_assert(sizeof(ptrdiff_t) == 8, "bad size"); + static_assert(alignof(ptrdiff_t) == 8, "bad alignment"); + + static_assert(sizeof(char) == 1, "bad size"); + static_assert(alignof(char) == 1, "bad alignment"); + static_assert(sizeof(short) == 2, "bad size"); + static_assert(alignof(short) == 2, "bad alignment"); + static_assert(sizeof(int) == 4, "bad size"); + static_assert(alignof(int) == 4, "bad alignment"); + static_assert(sizeof(long) == 8, "bad size"); + static_assert(alignof(long) == 8, "bad alignment"); + static_assert(sizeof(long long) == 8, "bad size"); + static_assert(alignof(long long) == 8, "bad alignment"); + static_assert(sizeof(float) == 4, "bad size"); + static_assert(alignof(float) == 4, "bad alignment"); + static_assert(sizeof(double) == 8, "bad size"); + static_assert(alignof(double) == 8, "bad alignment"); + + static_assert(sizeof(void*) == 8, "bad size"); + static_assert(alignof(void*) == 8, "bad alignment"); + static_assert(sizeof(global_ptr_t) == 8, "bad size"); + static_assert(alignof(global_ptr_t) == 8, "bad alignment"); + static_assert(sizeof(constant_ptr_t) == 8, "bad size"); + static_assert(alignof(constant_ptr_t) == 8, "bad alignment"); + static_assert(sizeof(local_ptr_t) == 4, "bad size"); + static_assert(alignof(local_ptr_t) == 4, "bad alignment"); + static_assert(sizeof(private_ptr_t) == 4, "bad size"); + static_assert(alignof(private_ptr_t) == 4, "bad alignment"); +} diff --git a/test/SemaCXX/attr-deprecated.cpp b/test/SemaCXX/attr-deprecated.cpp index 1680c5c6760d..5ba55f0c23b5 100644 --- a/test/SemaCXX/attr-deprecated.cpp +++ b/test/SemaCXX/attr-deprecated.cpp @@ -199,8 +199,8 @@ namespace test5 { // rdar://problem/8518751 namespace test6 { - enum __attribute__((deprecated)) A { // expected-note {{'A' has been explicitly marked deprecated here}} - a0 // expected-note {{'a0' has been explicitly marked deprecated here}} + enum __attribute__((deprecated)) A { // expected-note 2 {{'A' has been explicitly marked deprecated here}} + a0 }; void testA() { A x; // expected-warning {{'A' is deprecated}} @@ -218,8 +218,8 @@ namespace test6 { } template <class T> struct C { - enum __attribute__((deprecated)) Enum { // expected-note {{'Enum' has been explicitly marked deprecated here}} - c0 // expected-note {{'c0' has been explicitly marked deprecated here}} + enum __attribute__((deprecated)) Enum { // expected-note 2 {{'Enum' has been explicitly marked deprecated here}} + c0 }; }; void testC() { diff --git a/test/SemaCXX/coroutines.cpp b/test/SemaCXX/coroutines.cpp index 4eedc2162f07..6394829f356a 100644 --- a/test/SemaCXX/coroutines.cpp +++ b/test/SemaCXX/coroutines.cpp @@ -22,8 +22,24 @@ void no_coroutine_traits() { namespace std { namespace experimental { -template <typename... T> -struct coroutine_traits; // expected-note {{declared here}} + +template <class... Args> +struct void_t_imp { + using type = void; +}; +template <class... Args> +using void_t = typename void_t_imp<Args...>::type; + +template <class T, class = void> +struct traits_sfinae_base {}; + +template <class T> +struct traits_sfinae_base<T, void_t<typename T::promise_type>> { + using promise_type = typename T::promise_type; +}; + +template <class Ret, class... Args> +struct coroutine_traits : public traits_sfinae_base<Ret> {}; }} // namespace std::experimental template<typename Promise> struct coro {}; @@ -50,8 +66,9 @@ struct suspend_never { void await_resume() {} }; -void no_specialization() { - co_await a; // expected-error {{implicit instantiation of undefined template 'std::experimental::coroutine_traits<void>'}} +struct DummyVoidTag {}; +DummyVoidTag no_specialization() { // expected-error {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<DummyVoidTag>' has no member named 'promise_type'}} + co_await a; } template <typename... T> @@ -905,3 +922,243 @@ void test_dependent_param(T t, U) { co_return 42; } template void test_dependent_param(NoCopy<0>, NoCopy<1>); // expected-note {{requested here}} + +namespace CoroHandleMemberFunctionTest { +struct CoroMemberTag {}; +struct BadCoroMemberTag {}; + +template <class T, class U> +constexpr bool IsSameV = false; +template <class T> +constexpr bool IsSameV<T, T> = true; + +template <class T> +struct TypeTest { + template <class U> + static constexpr bool IsSame = IsSameV<T, U>; + + template <class... Args> + static constexpr bool MatchesArgs = IsSameV<T, + std::experimental::coroutine_traits<CoroMemberTag, Args...>>; +}; + +template <class T> +struct AwaitReturnsType { + bool await_ready() const; + void await_suspend(...) const; + T await_resume() const; +}; + +template <class... CoroTraitsArgs> +struct CoroMemberPromise { + using TraitsT = std::experimental::coroutine_traits<CoroTraitsArgs...>; + using TypeTestT = TypeTest<TraitsT>; + using AwaitTestT = AwaitReturnsType<TypeTestT>; + + CoroMemberTag get_return_object(); + suspend_always initial_suspend(); + suspend_always final_suspend(); + + AwaitTestT yield_value(int); + + void return_void(); + void unhandled_exception(); +}; + +} // namespace CoroHandleMemberFunctionTest + +template <class... Args> +struct ::std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::CoroMemberTag, Args...> { + using promise_type = CoroHandleMemberFunctionTest::CoroMemberPromise<CoroHandleMemberFunctionTest::CoroMemberTag, Args...>; +}; + +namespace CoroHandleMemberFunctionTest { +struct TestType { + + CoroMemberTag test_qual() { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType &>, ""); + static_assert(!TC.MatchesArgs<TestType>, ""); + static_assert(!TC.MatchesArgs<TestType *>, ""); + } + + CoroMemberTag test_sanity(int *) const { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}} + static_assert(TC.MatchesArgs<const TestType &>, ""); // expected-error {{static_assert failed}} + static_assert(TC.MatchesArgs<const TestType &, int *>, ""); + } + + CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<const TestType &, int *, const float &&, volatile void *volatile>, ""); + } + + CoroMemberTag test_qual() const volatile { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<const volatile TestType &>, ""); + } + + CoroMemberTag test_ref_qual() & { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType &>, ""); + } + CoroMemberTag test_ref_qual() const & { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType const &>, ""); + } + CoroMemberTag test_ref_qual() && { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType &&>, ""); + } + CoroMemberTag test_ref_qual(const char *&) const volatile && { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType const volatile &&, const char *&>, ""); + } + + CoroMemberTag test_args(int) { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType &, int>, ""); + } + CoroMemberTag test_args(int, long &, void *) const { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<TestType const &, int, long &, void *>, ""); + } + + template <class... Args> + CoroMemberTag test_member_template(Args...) const && { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<TestType const &&, Args...>, ""); + } + + static CoroMemberTag test_static() { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<>, ""); + static_assert(!TC.MatchesArgs<TestType>, ""); + static_assert(!TC.MatchesArgs<TestType &>, ""); + static_assert(!TC.MatchesArgs<TestType *>, ""); + } + + static CoroMemberTag test_static(volatile void *const, char &&) { + auto TC = co_yield 0; + static_assert(TC.MatchesArgs<volatile void *const, char &&>, ""); + } + + template <class Dummy> + static CoroMemberTag test_static_template(const char *volatile &, unsigned) { + auto TC = co_yield 0; + using TCT = decltype(TC); + static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, ""); + static_assert(!TCT::MatchesArgs<TestType &, const char *volatile &, unsigned>, ""); + } + + BadCoroMemberTag test_diagnostics() { + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, CoroHandleMemberFunctionTest::TestType &>' has no member named 'promise_type'}} + co_return; + } + BadCoroMemberTag test_diagnostics(int) const && { + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, const CoroHandleMemberFunctionTest::TestType &&, int>' has no member named 'promise_type'}} + co_return; + } + + static BadCoroMemberTag test_static_diagnostics(long *) { + // expected-error@-1 {{this function cannot be a coroutine: 'std::experimental::coroutine_traits<CoroHandleMemberFunctionTest::BadCoroMemberTag, long *>' has no member named 'promise_type'}} + co_return; + } +}; + +template CoroMemberTag TestType::test_member_template(long, const char *) const &&; +template CoroMemberTag TestType::test_static_template<void>(const char *volatile &, unsigned); + +template <class... Args> +struct DepTestType { + + CoroMemberTag test_sanity(int *) const { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<const DepTestType &>, ""); // expected-error {{static_assert failed}} + static_assert(TC.template MatchesArgs<>, ""); // expected-error {{static_assert failed}} + static_assert(TC.template MatchesArgs<const DepTestType &, int *>, ""); + } + + CoroMemberTag test_qual() { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType &>, ""); + static_assert(!TC.template MatchesArgs<DepTestType>, ""); + static_assert(!TC.template MatchesArgs<DepTestType *>, ""); + } + + CoroMemberTag test_qual(int *, const float &&, volatile void *volatile) const { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<const DepTestType &, int *, const float &&, volatile void *volatile>, ""); + } + + CoroMemberTag test_qual() const volatile { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<const volatile DepTestType &>, ""); + } + + CoroMemberTag test_ref_qual() & { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType &>, ""); + } + CoroMemberTag test_ref_qual() const & { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType const &>, ""); + } + CoroMemberTag test_ref_qual() && { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType &&>, ""); + } + CoroMemberTag test_ref_qual(const char *&) const volatile && { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType const volatile &&, const char *&>, ""); + } + + CoroMemberTag test_args(int) { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType &, int>, ""); + } + CoroMemberTag test_args(int, long &, void *) const { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType const &, int, long &, void *>, ""); + } + + template <class... UArgs> + CoroMemberTag test_member_template(UArgs...) const && { + auto TC = co_yield 0; + static_assert(TC.template MatchesArgs<DepTestType const &&, UArgs...>, ""); + } + + static CoroMemberTag test_static() { + auto TC = co_yield 0; + using TCT = decltype(TC); + static_assert(TCT::MatchesArgs<>, ""); + static_assert(!TCT::MatchesArgs<DepTestType>, ""); + static_assert(!TCT::MatchesArgs<DepTestType &>, ""); + static_assert(!TCT::MatchesArgs<DepTestType *>, ""); + + // Ensure diagnostics are actually being generated here + static_assert(TCT::MatchesArgs<int>, ""); // expected-error {{static_assert failed}} + } + + static CoroMemberTag test_static(volatile void *const, char &&) { + auto TC = co_yield 0; + using TCT = decltype(TC); + static_assert(TCT::MatchesArgs<volatile void *const, char &&>, ""); + } + + template <class Dummy> + static CoroMemberTag test_static_template(const char *volatile &, unsigned) { + auto TC = co_yield 0; + using TCT = decltype(TC); + static_assert(TCT::MatchesArgs<const char *volatile &, unsigned>, ""); + static_assert(!TCT::MatchesArgs<DepTestType &, const char *volatile &, unsigned>, ""); + } +}; + +template struct DepTestType<int>; // expected-note {{requested here}} +template CoroMemberTag DepTestType<int>::test_member_template(long, const char *) const &&; + +template CoroMemberTag DepTestType<int>::test_static_template<void>(const char *volatile &, unsigned); + +} // namespace CoroHandleMemberFunctionTest diff --git a/test/SemaCXX/dllimport-memptr.cpp b/test/SemaCXX/dllimport-memptr.cpp new file mode 100644 index 000000000000..35bf5b8610b5 --- /dev/null +++ b/test/SemaCXX/dllimport-memptr.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -verify -std=c++11 %s + +// expected-no-diagnostics + +struct __declspec(dllimport) Foo { int get_a(); }; +template <int (Foo::*Getter)()> struct HasValue { }; +HasValue<&Foo::get_a> hv; diff --git a/test/SemaCXX/modules-ts.cppm b/test/SemaCXX/modules-ts.cppm index 29122ec7dab5..2ea4958bffda 100644 --- a/test/SemaCXX/modules-ts.cppm +++ b/test/SemaCXX/modules-ts.cppm @@ -13,7 +13,13 @@ export module foo; // expected-note@modules-ts.cppm:* {{loaded from}} #endif -static int m; // ok, internal linkage, so no redefinition error +static int m; +#if TEST == 2 // FIXME: 'm' has internal linkage, so there should be no error here +// expected-error@-2 {{redefinition of '}} +// expected-note@-3 {{unguarded header; consider using #ifdef guards or #pragma once}} +// FIXME: We should drop the "header from" in this diagnostic. +// expected-note-re@modules-ts.cppm:1 {{'{{.*}}modules-ts.cppm' included multiple times, additional include site in header from module 'foo'}} +#endif int n; #if TEST >= 2 // expected-error@-2 {{redefinition of '}} diff --git a/test/SemaCXX/warn-cast-qual.cpp b/test/SemaCXX/warn-cast-qual.cpp new file mode 100644 index 000000000000..d1f0cc73a63d --- /dev/null +++ b/test/SemaCXX/warn-cast-qual.cpp @@ -0,0 +1,140 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -Wcast-qual -verify %s + +#include <stdint.h> + +// do *NOT* warn on const_cast<>() +// use clang-tidy's cppcoreguidelines-pro-type-const-cast for that. +void foo_ptr() { + const char *const ptr = 0; + char *t0 = const_cast<char *>(ptr); // no warning + + volatile char *ptr2 = 0; + char *t1 = const_cast<char *>(ptr2); // no warning + + const volatile char *ptr3 = 0; + char *t2 = const_cast<char *>(ptr3); // no warning +} + +void cstr() { + void* p0 = (void*)(const void*)"txt"; // expected-warning {{cast from 'const void *' to 'void *' drops const qualifier}} + void* p1 = (void*)"txt"; // FIXME + char* p2 = (char*)"txt"; // expected-warning {{cast from 'const char *' to 'char *' drops const qualifier}} +} + +void foo_0() { + const int a = 0; + + const int &a0 = a; // no warning + const int &a1 = (const int &)a; // no warning + + int &a2 = (int &)a; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + const int &a3 = (int &)a; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + int &a4 = (int &)((const int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + int &a5 = (int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + const int &a6 = (int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + const int &a7 = (int &)((const int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + const int &a8 = (const int &)((int &)a); // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} +} + +void foo_1() { + volatile int a = 0; + + volatile int &a0 = a; // no warning + volatile int &a1 = (volatile int &)a; // no warning + + int &a2 = (int &)a; // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + volatile int &a3 = (int &)a; // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + int &a4 = (int &)((volatile int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + int &a5 = (int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + volatile int &a6 = (int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + volatile int &a7 = (int &)((volatile int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} + volatile int &a8 = (volatile int &)((int &)a); // expected-warning {{cast from 'volatile int' to 'int &' drops volatile qualifier}} +} + +void foo_2() { + const volatile int a = 0; + + const volatile int &a0 = a; // no warning + const volatile int &a1 = (const volatile int &)a; // no warning + + int &a2 = (int &)a; // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + const volatile int &a3 = (int &)a; // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + int &a4 = (int &)((const volatile int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + int &a5 = (int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + const volatile int &a6 = (int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + const volatile int &a7 = (int &)((const volatile int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} + const volatile int &a8 = (const volatile int &)((int &)a); // expected-warning {{cast from 'const volatile int' to 'int &' drops const and volatile qualifiers}} +} + +void bar_0() { + const int *_a = 0; + const int **a = &_a; + + int **a0 = (int **)((const int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + int **a1 = (int **)((int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + + // const int **a2 = (int **)((int **)a); + // const int **a3 = (int **)((const int **)a); + + const int **a4 = (const int **)((int **)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} expected-warning {{cast from 'int **' to 'const int **' must have all intermediate pointers const qualified to be safe}} + const int **a5 = (const int **)((const int **)a); // no warning +} + +void bar_1() { + const int *_a = 0; + const int *&a = _a; + + int *&a0 = (int *&)((const int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + int *&a1 = (int *&)((int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + + // const int *&a2 = (int *&)((int *&)a); + // const int *&a3 = (int *&)((const int *&)a); + + const int *&a4 = (const int *&)((int *&)a); // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} expected-warning {{cast from 'int *' to 'const int *&' must have all intermediate pointers const qualified to be safe}} + const int *&a5 = (const int *&)((const int *&)a); // no warning +} + +void baz_0() { + struct C { + void A() {} + void B() const {} + }; + + const C S; + S.B(); + + ((C &)S).B(); // expected-warning {{cast from 'const C' to 'C &' drops const qualifier}} + ((C &)S).A(); // expected-warning {{cast from 'const C' to 'C &' drops const qualifier}} + + ((C *)&S)->B(); // expected-warning {{cast from 'const C *' to 'C *' drops const qualifier}} + ((C *)&S)->A(); // expected-warning {{cast from 'const C *' to 'C *' drops const qualifier}} +} + +void baz_1() { + struct C { + const int a; + int b; + + C() : a(0) {} + }; + + { + C S; + S.b = 0; + + (int &)(S.a) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + (int &)(S.b) = 0; // no warning + + *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + *(int *)(&S.b) = 0; // no warning + } + { + const C S; + + (int &)(S.a) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + (int &)(S.b) = 0; // expected-warning {{cast from 'const int' to 'int &' drops const qualifier}} + + *(int *)(&S.a) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + *(int *)(&S.b) = 0; // expected-warning {{cast from 'const int *' to 'int *' drops const qualifier}} + } +} diff --git a/test/SemaCXX/warn-loop-analysis.cpp b/test/SemaCXX/warn-loop-analysis.cpp index 25ec7a7862ed..2934003848a2 100644 --- a/test/SemaCXX/warn-loop-analysis.cpp +++ b/test/SemaCXX/warn-loop-analysis.cpp @@ -202,6 +202,12 @@ void test7() { if (true) continue; i--; } + + // But do warn if the continue is in a nested loop. + for (;;i--) { // expected-note{{decremented here}} + for (int j = 0; j < 10; ++j) continue; + i--; // expected-warning{{decremented both}} + } } struct iterator { @@ -259,6 +265,12 @@ void test8() { if (true) continue; i--; } + + // But do warn if the continue is in a nested loop. + for (;;i--) { // expected-note{{decremented here}} + for (int j = 0; j < 10; ++j) continue; + i--; // expected-warning{{decremented both}} + } } int f(int); diff --git a/test/SemaCXX/warn-throw-out-noexcept-func.cpp b/test/SemaCXX/warn-throw-out-noexcept-func.cpp index fc2919a1e327..67ffbd93940a 100644 --- a/test/SemaCXX/warn-throw-out-noexcept-func.cpp +++ b/test/SemaCXX/warn-throw-out-noexcept-func.cpp @@ -2,8 +2,8 @@ struct A_ShouldDiag { ~A_ShouldDiag(); // implicitly noexcept(true) }; -A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor or deallocator has a (possibly implicit) non-throwing excepton specification}} - throw 1; // expected-warning {{has a non-throwing exception specification but can still throw, resulting in unexpected program termination}} +A_ShouldDiag::~A_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but can still throw}} } struct B_ShouldDiag { int i; @@ -11,7 +11,7 @@ struct B_ShouldDiag { }; struct R_ShouldDiag : A_ShouldDiag { B_ShouldDiag b; - ~R_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~R_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; @@ -30,18 +30,18 @@ struct N_ShouldDiag { ~N_ShouldDiag(); //implicitly noexcept(true) }; -N_ShouldDiag::~N_ShouldDiag() { // expected-note {{destructor or deallocator has a}} +N_ShouldDiag::~N_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } struct X_ShouldDiag { B_ShouldDiag b; - ~X_ShouldDiag() noexcept { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~X_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; struct Y_ShouldDiag : A_ShouldDiag { - ~Y_ShouldDiag() noexcept(true) { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~Y_ShouldDiag() noexcept(true) { // expected-note {{destructor has a non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; struct C_ShouldNotDiag { @@ -54,7 +54,7 @@ struct D_ShouldNotDiag { throw 1; } }; -struct E_ShouldNotDiag { +struct E_ShouldNotDiag { C_ShouldNotDiag c; ~E_ShouldNotDiag(); //implicitly noexcept(false) }; @@ -68,7 +68,7 @@ class A1_ShouldDiag { T b; public: - ~A1_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~A1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; @@ -81,19 +81,19 @@ template <typename T> struct R1_ShouldDiag : A1_ShouldDiag<T> //expected-note {{in instantiation of member function}} { B1_ShouldDiag<T> b; - ~R1_ShouldDiag() { // expected-note {{destructor or deallocator has a}} + ~R1_ShouldDiag() { // expected-note {{destructor has a implicit non-throwing exception specification}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; template <typename T> struct S1_ShouldDiag : A1_ShouldDiag<T> { B1_ShouldDiag<T> b; - ~S1_ShouldDiag() noexcept { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~S1_ShouldDiag() noexcept { // expected-note {{destructor has a non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; -void operator delete(void *ptr) noexcept { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} +void operator delete(void *ptr) noexcept { // expected-note {{deallocator has a non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } struct except_fun { static const bool i = false; @@ -109,18 +109,18 @@ struct dependent_warn { }; template <typename T> struct dependent_warn_noexcept { - ~dependent_warn_noexcept() noexcept(T::i) { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~dependent_warn_noexcept() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; template <typename T> struct dependent_warn_both { - ~dependent_warn_both() noexcept(T::i) { // expected-note {{destructor or deallocator has a}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} + ~dependent_warn_both() noexcept(T::i) { // expected-note {{destructor has a non-throwing exception specification}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } }; -void foo() noexcept { //expected-note {{non-throwing function declare here}} - throw 1; // expected-warning {{has a non-throwing exception specification but}} +void foo() noexcept { //expected-note {{function declared non-throwing here}} + throw 1; // expected-warning {{has a non-throwing exception specification but}} } struct Throws { ~Throws() noexcept(false); @@ -128,14 +128,14 @@ struct Throws { struct ShouldDiagnose { Throws T; - ~ShouldDiagnose() noexcept { //expected-note {{destructor or deallocator has a}} + ~ShouldDiagnose() noexcept { //expected-note {{destructor has a non-throwing exception specification}} throw; // expected-warning {{has a non-throwing exception specification but}} } }; struct ShouldNotDiagnose { Throws T; - ~ShouldNotDiagnose() { - throw; + ~ShouldNotDiagnose() { + throw; } }; @@ -158,21 +158,21 @@ void g_ShouldNotDiag() noexcept { } } -void h_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void h_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; // expected-warning {{has a non-throwing exception specification but}} } catch (const char *) { } } -void i_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void i_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; } catch (int) { throw; // expected-warning {{has a non-throwing exception specification but}} } } -void j_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void j_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; } catch (int) { @@ -180,7 +180,7 @@ void j_ShouldDiag() noexcept { //expected-note {{non-throwing function declare h } } -void k_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void k_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw 12; } catch (...) { @@ -188,7 +188,7 @@ void k_ShouldDiag() noexcept { //expected-note {{non-throwing function declare h } } -void loo_ShouldDiag(int i) noexcept { //expected-note {{non-throwing function declare here}} +void loo_ShouldDiag(int i) noexcept { //expected-note {{function declared non-throwing here}} if (i) try { throw 12; @@ -203,13 +203,13 @@ void loo1_ShouldNotDiag() noexcept { throw 12; } -void loo2_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void loo2_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} if (1) throw 12; // expected-warning {{has a non-throwing exception specification but}} } struct S {}; -void l_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void l_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw S{}; //expected-warning {{has a non-throwing exception specification but}} } catch (S *s) { @@ -222,7 +222,6 @@ void m_ShouldNotDiag() noexcept { throw s; } catch (S s) { } - } void n_ShouldNotDiag() noexcept { try { @@ -231,7 +230,7 @@ void n_ShouldNotDiag() noexcept { } catch (const S &s) { } } -void o_ShouldDiag() noexcept { //expected-note {{non-throwing function declare here}} +void o_ShouldDiag() noexcept { //expected-note {{function declared non-throwing here}} try { throw; //expected-warning {{has a non-throwing exception specification but}} } catch (...) { @@ -239,7 +238,7 @@ void o_ShouldDiag() noexcept { //expected-note {{non-throwing function declare h } #define NOEXCEPT noexcept -void with_macro() NOEXCEPT { //expected-note {{non-throwing function declare here}} +void with_macro() NOEXCEPT { //expected-note {{function declared non-throwing here}} throw 1; // expected-warning {{has a non-throwing exception specification but}} } @@ -248,8 +247,8 @@ void with_try_block() try { } catch (...) { } -void with_try_block1() noexcept try { //expected-note {{non-throwing function declare here}} - throw 2; // expected-warning {{has a non-throwing exception specification but}} +void with_try_block1() noexcept try { //expected-note {{function declared non-throwing here}} + throw 2; // expected-warning {{has a non-throwing exception specification but}} } catch (char *) { } @@ -272,20 +271,20 @@ void goodPointer() noexcept { throw &d; } catch (B *) {} } -void badPlain() noexcept { // expected-note {{non-throwing function declare here}} +void badPlain() noexcept { //expected-note {{function declared non-throwing here}} try { - throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw, resulting in unexpected program termination}} + throw B(); // expected-warning {{'badPlain' has a non-throwing exception specification but can still throw}} } catch (D) {} } -void badReference() noexcept { // expected-note {{non-throwing function declare here}} +void badReference() noexcept { //expected-note {{function declared non-throwing here}} try { - throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw, resulting in unexpected program termination}} + throw B(); // expected-warning {{'badReference' has a non-throwing exception specification but can still throw}} } catch (D &) {} } -void badPointer() noexcept { // expected-note {{non-throwing function declare here}} +void badPointer() noexcept { //expected-note {{function declared non-throwing here}} B b; try { - throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw, resulting in unexpected program termination}} + throw &b; // expected-warning {{'badPointer' has a non-throwing exception specification but can still throw}} } catch (D *) {} } } diff --git a/test/SemaObjC/attr-availability.m b/test/SemaObjC/attr-availability.m index 02b7c5c81491..1245ac7409b8 100644 --- a/test/SemaObjC/attr-availability.m +++ b/test/SemaObjC/attr-availability.m @@ -13,7 +13,7 @@ @interface A <P> - (void)method __attribute__((availability(macosx,introduced=10.1,deprecated=10.2))); // expected-note {{'method' has been explicitly marked deprecated here}} #if defined(WARN_PARTIAL) - // expected-note@+2 {{'partialMethod' has been explicitly marked partial here}} + // expected-note@+2 2 {{'partialMethod' has been explicitly marked partial here}} #endif - (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); @@ -66,7 +66,10 @@ void f(A *a, B *b) { @end void f_after_redecl(A *a, B *b) { - [a partialMethod]; // no warning +#ifdef WARN_PARTIAL + // expected-warning@+2{{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}} +#endif + [a partialMethod]; [b partialMethod]; // no warning [a partial_proto_method]; // no warning [b partial_proto_method]; // no warning @@ -133,6 +136,10 @@ id NSNibOwner, topNibObjects; @end @interface PartialI <PartialProt> +#ifdef WARN_PARTIAL +// expected-note@+3{{marked partial here}} +// expected-note@+3{{marked partial here}} +#endif - (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); + (void)partialMethod __attribute__((availability(macosx,introduced=10.8))); @end @@ -160,14 +167,20 @@ id NSNibOwner, topNibObjects; @end void partialfun(PartialI* a) { - [a partialMethod]; // no warning +#ifdef WARN_PARTIAL + // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2{{@available}} +#endif + [a partialMethod]; [a ipartialMethod1]; // no warning #if defined(WARN_PARTIAL) // expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}} #endif [a ipartialMethod2]; [a ppartialMethod]; // no warning - [PartialI partialMethod]; // no warning +#ifdef WARN_PARTIAL + // expected-warning@+2 {{'partialMethod' is only available on macOS 10.8 or newer}} expected-note@+2 {{@available}} +#endif + [PartialI partialMethod]; [PartialI ipartialMethod1]; // no warning #if defined(WARN_PARTIAL) // expected-warning@+2 {{'ipartialMethod2' is only available on macOS 10.8 or newer}} expected-note@+2 {{enclose 'ipartialMethod2' in an @available check to silence this warning}} @@ -177,20 +190,23 @@ void partialfun(PartialI* a) { } #if defined(WARN_PARTIAL) - // expected-note@+2 {{'PartialI2' has been explicitly marked partial here}} + // expected-note@+2 2 {{'PartialI2' has been explicitly marked partial here}} #endif __attribute__((availability(macosx, introduced = 10.8))) @interface PartialI2 @end #if defined(WARN_PARTIAL) - // expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{explicitly redeclare 'PartialI2' to silence this warning}} +// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter1' with an availability attribute to silence}} #endif void partialinter1(PartialI2* p) { } @class PartialI2; -void partialinter2(PartialI2* p) { // no warning +#ifdef WARN_PARTIAL +// expected-warning@+2 {{'PartialI2' is partial: introduced in macOS 10.8}} expected-note@+2 {{annotate 'partialinter2' with an availability attribute to silence}} +#endif +void partialinter2(PartialI2* p) { } diff --git a/test/SemaObjC/default-synthesize-3.m b/test/SemaObjC/default-synthesize-3.m index fe2b35f61523..9a05408aa060 100644 --- a/test/SemaObjC/default-synthesize-3.m +++ b/test/SemaObjC/default-synthesize-3.m @@ -173,13 +173,13 @@ typedef NSObject<Fooing> FooObject; @end @implementation Okay // expected-warning {{auto property synthesis will not synthesize property 'muahahaha' declared in protocol 'Fooing'}} expected-warning {{auto property synthesis will not synthesize property 'hoho' declared in protocol 'SubFooling'}} -@end +@end // expected-note 2 {{add a '@synthesize' directive}} @interface Fail : FooObject @end @implementation Fail // expected-warning {{auto property synthesis will not synthesize property 'muahahaha' declared in protocol 'Fooing'}} expected-warning {{auto property synthesis will not synthesize property 'hoho' declared in protocol 'SubFooling'}} -@end +@end // expected-note 2 {{add a '@synthesize' directive}} // rdar://16089191 @class NSURL; diff --git a/test/SemaObjC/default-synthesize.m b/test/SemaObjC/default-synthesize.m index 3f0ae0261daf..61ce9317c519 100644 --- a/test/SemaObjC/default-synthesize.m +++ b/test/SemaObjC/default-synthesize.m @@ -137,7 +137,7 @@ @end @implementation MyClass // expected-warning {{auto property synthesis will not synthesize property 'requiredString' declared in protocol 'MyProtocol'}} -@end +@end // expected-note {{add a '@synthesize' directive}} // rdar://18152478 @protocol NSObject @end diff --git a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m index c235e32316a9..583bb4dd891d 100644 --- a/test/SemaObjC/forward-protocol-incomplete-impl-warn.m +++ b/test/SemaObjC/forward-protocol-incomplete-impl-warn.m @@ -17,4 +17,4 @@ @implementation IBImageCatalogDocument // expected-warning {{auto property synthesis will not synthesize property 'Prop' declared in protocol 'DVTInvalidation'}} \ // expected-warning {{method 'invalidate' in protocol 'DVTInvalidation' not implemented}} -@end +@end // expected-note {{add a '@synthesize' directive}} diff --git a/test/SemaObjC/objc-container-subscripting-1.m b/test/SemaObjC/objc-container-subscripting-1.m index a58a7c3bda81..b5ed5a68dd84 100644 --- a/test/SemaObjC/objc-container-subscripting-1.m +++ b/test/SemaObjC/objc-container-subscripting-1.m @@ -16,8 +16,7 @@ id oldObject = array[10]; // expected-warning {{instance method '-objectAtIndexe array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}} id<P> p_array; -oldObject = p_array[10]; // expected-warning {{instance method '-objectAtIndexedSubscript:' not found (return type defaults to 'id')}} +oldObject = p_array[10]; // expected-error {{expected method to read array element not found on object of type 'id<P>'}} -p_array[10] = 0; // expected-warning {{instance method '-setObject:atIndexedSubscript:' not found (return type defaults to 'id')}} +p_array[10] = 0; // expected-error {{expected method to write array element not found on object of type 'id<P>'}} } - diff --git a/test/SemaObjC/objc-container-subscripting-2.m b/test/SemaObjC/objc-container-subscripting-2.m index 62320fcebb77..6e7ee7c40e58 100644 --- a/test/SemaObjC/objc-container-subscripting-2.m +++ b/test/SemaObjC/objc-container-subscripting-2.m @@ -28,3 +28,22 @@ void test_unused() { dict[array]; // expected-warning {{container access result unused - container access should not be used for side effects}} } +void testQualifiedId(id<P> qualifiedId) { + id object = qualifiedId[10]; // expected-error {{expected method to read array element not found on object of type 'id<P>'}} + qualifiedId[10] = qualifiedId; // expected-error {{expected method to write array element not found on object of type 'id<P>'}} +} + +void testUnqualifiedId(id unqualId) { + id object = unqualId[10]; + unqualId[10] = object; +} + +@protocol Subscriptable +- (id)objectAtIndexedSubscript:(size_t)index; +- (void)setObject:(id)object atIndexedSubscript:(size_t)index; +@end + +void testValidQualifiedId(id<Subscriptable> qualifiedId) { + id object = qualifiedId[10]; + qualifiedId[10] = object; +} diff --git a/test/SemaObjC/unguarded-availability-new.m b/test/SemaObjC/unguarded-availability-new.m index 33baedebc279..9c44b164d541 100644 --- a/test/SemaObjC/unguarded-availability-new.m +++ b/test/SemaObjC/unguarded-availability-new.m @@ -96,16 +96,16 @@ typedef int AVAILABLE_NEXT new_int; FUNC_AVAILABLE new_int x; #ifndef NO_WARNING #ifdef MAC - // expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{explicitly redeclare 'new_int' to silence this warning}} + // expected-warning@-3 {{'new_int' is partial: introduced in macOS 10.14}} expected-note@-3 {{annotate 'x' with an availability attribute to silence}} #endif #ifdef IOS - // expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{explicitly redeclare 'new_int' to silence this warning}} + // expected-warning@-6 {{'new_int' is partial: introduced in iOS 12}} expected-note@-6 {{annotate 'x' with an availability attribute to silence}} #endif #ifdef TVOS - // expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{explicitly redeclare 'new_int' to silence this warning}} + // expected-warning@-9 {{'new_int' is partial: introduced in tvOS 13}} expected-note@-9 {{annotate 'x' with an availability attribute to silence}} #endif #ifdef WATCHOS - // expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{explicitly redeclare 'new_int' to silence this warning}} + // expected-warning@-12 {{'new_int' is partial: introduced in watchOS 5}} expected-note@-12 {{annotate 'x' with an availability attribute to silence}} #endif #endif diff --git a/test/SemaObjC/unguarded-availability.m b/test/SemaObjC/unguarded-availability.m index 5febee038e3c..139b79158afe 100644 --- a/test/SemaObjC/unguarded-availability.m +++ b/test/SemaObjC/unguarded-availability.m @@ -5,6 +5,8 @@ #define AVAILABLE_10_11 __attribute__((availability(macos, introduced = 10.11))) #define AVAILABLE_10_12 __attribute__((availability(macos, introduced = 10.12))) +typedef int AVAILABLE_10_12 new_int; // expected-note + {{marked partial here}} + int func_10_11() AVAILABLE_10_11; // expected-note 4 {{'func_10_11' has been explicitly marked partial here}} #ifdef OBJCPP @@ -70,9 +72,9 @@ void use_typedef() { } __attribute__((objc_root_class)) -AVAILABLE_10_11 @interface Class_10_11 { +AVAILABLE_10_11 @interface Class_10_11 { // expected-note{{annotate 'Class_10_11' with an availability attribute to silence}} int_10_11 foo; - int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}} + int_10_12 bar; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} } - (void)method1; - (void)method2; @@ -125,7 +127,7 @@ void test_blocks() { }; } -void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}} +void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{annotate 'test_params' with an availability attribute to silence}} void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn @@ -234,3 +236,54 @@ void functionInFunction() { } #endif + +struct InStruct { // expected-note{{annotate 'InStruct' with an availability attribute to silence}} + new_int mem; // expected-warning{{'new_int' is partial}} + + struct { new_int mem; } anon; // expected-warning{{'new_int' is partial}} expected-note{{annotate anonymous struct with an availability attribute}} +}; + +#ifdef OBJCPP +static constexpr int AVAILABLE_10_12 SomeConstexprValue = 2; // expected-note{{marked partial here}} +typedef enum { // expected-note{{annotate anonymous enum with an availability attribute}} + SomeValue = SomeConstexprValue // expected-warning{{'SomeConstexprValue' is partial}} +} SomeEnum; +#endif + +@interface InInterface +-(new_int)meth; // expected-warning{{'new_int' is partial}} expected-note{{annotate 'meth' with an availability attribute}} +@end + +@interface Proper // expected-note{{annotate 'Proper' with an availability attribute}} +@property (class) new_int x; // expected-warning{{'new_int' is partial}} +@end + +void with_local_struct() { + struct local { // expected-note{{annotate 'local' with an availability attribute}} + new_int x; // expected-warning{{'new_int' is partial}} + }; +} + +// rdar://33156429: +// Avoid the warning on protocol requirements. + +AVAILABLE_10_12 +@protocol NewProtocol // expected-note {{'NewProtocol' has been explicitly marked partial here}} +@end + +@protocol ProtocolWithNewProtocolRequirement <NewProtocol> // expected-note {{annotate 'ProtocolWithNewProtocolRequirement' with an availability attribute to silence}} + +@property(copy) id<NewProtocol> prop; // expected-warning {{'NewProtocol' is partial: introduced in macOS 10.12}} + +@end + +@interface BaseClass +@end + +@interface ClassWithNewProtocolRequirement : BaseClass <NewProtocol> + +@end + +@interface BaseClass (CategoryWithNewProtocolRequirement) <NewProtocol> + +@end diff --git a/test/SemaOpenCL/cl20-device-side-enqueue.cl b/test/SemaOpenCL/cl20-device-side-enqueue.cl index bafbe447ee28..3f6527afeadc 100644 --- a/test/SemaOpenCL/cl20-device-side-enqueue.cl +++ b/test/SemaOpenCL/cl20-device-side-enqueue.cl @@ -19,19 +19,19 @@ kernel void enqueue_kernel_tests() { return 0; }); - enqueue_kernel(vptr, flags, ndrange, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'queue_t' argument type}} + enqueue_kernel(vptr, flags, ndrange, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'queue_t' argument type}} return 0; }); - enqueue_kernel(default_queue, vptr, ndrange, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'kernel_enqueue_flags_t' (i.e. uint) argument type}} + enqueue_kernel(default_queue, vptr, ndrange, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'kernel_enqueue_flags_t' (i.e. uint) argument type}} return 0; }); - enqueue_kernel(default_queue, flags, vptr, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected 'ndrange_t' argument type}} + enqueue_kernel(default_queue, flags, vptr, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected 'ndrange_t' argument type}} return 0; }); - enqueue_kernel(default_queue, flags, ndrange, vptr); // expected-error{{illegal call to enqueue_kernel, expected block argument}} + enqueue_kernel(default_queue, flags, ndrange, vptr); // expected-error{{illegal call to 'enqueue_kernel', expected block argument}} enqueue_kernel(default_queue, flags, ndrange, ^(int i) { // expected-error{{blocks with parameters are not accepted in this prototype of enqueue_kernel call}} return 0; @@ -46,21 +46,21 @@ kernel void enqueue_kernel_tests() { return 0; }); - enqueue_kernel(default_queue, flags, ndrange, vptr, &event_wait_list, &evt, ^(void) { // expected-error{{illegal call to enqueue_kernel, expected integer argument type}} + enqueue_kernel(default_queue, flags, ndrange, vptr, &event_wait_list, &evt, ^(void) { // expected-error{{illegal call to 'enqueue_kernel', expected integer argument type}} return 0; }); - enqueue_kernel(default_queue, flags, ndrange, 1, vptr, &evt, ^(void) // expected-error{{illegal call to enqueue_kernel, expected 'clk_event_t *' argument type}} + enqueue_kernel(default_queue, flags, ndrange, 1, vptr, &evt, ^(void) // expected-error{{illegal call to 'enqueue_kernel', expected 'clk_event_t *' argument type}} { return 0; }); - enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, vptr, ^(void) // expected-error{{illegal call to enqueue_kernel, expected 'clk_event_t *' argument type}} + enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, vptr, ^(void) // expected-error{{illegal call to 'enqueue_kernel', expected 'clk_event_t *' argument type}} { return 0; }); - enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, &evt, vptr); // expected-error{{illegal call to enqueue_kernel, expected block argument}} + enqueue_kernel(default_queue, flags, ndrange, 1, &event_wait_list, &evt, vptr); // expected-error{{illegal call to 'enqueue_kernel', expected block argument}} // Testing the third overload type enqueue_kernel(default_queue, flags, ndrange, diff --git a/test/SemaOpenCL/images.cl b/test/SemaOpenCL/images.cl index f963de4e1359..9d6092c8c916 100644 --- a/test/SemaOpenCL/images.cl +++ b/test/SemaOpenCL/images.cl @@ -1,9 +1,32 @@ -// RUN: %clang_cc1 %s -verify -pedantic -fsyntax-only +// RUN: %clang_cc1 %s -cl-std=CL2.0 -verify -pedantic -fsyntax-only -void img2d_ro(__read_only image2d_t img) {} // expected-note{{passing argument to parameter 'img' here}} expected-note{{passing argument to parameter 'img' here}} +void img2d_ro(read_only image2d_t); // expected-note 3{{passing argument to parameter here}} +void img2d_wo(write_only image2d_t); // expected-note 2{{passing argument to parameter here}} +void img2d_rw(read_write image2d_t); // expected-note 2{{passing argument to parameter here}} +void img2d_default(image2d_t); // expected-note 2{{passing argument to parameter here}} -void imgage_access_test(image2d_t img2dro, write_only image2d_t img2dwo, image3d_t img3dro) { - img2d_ro(img2dro); - img2d_ro(img2dwo); // expected-error{{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}} +void imgage_access_test(image2d_t img2dro, image3d_t img3dro) { + img2d_ro(img2dro); // read_only = read_only img2d_ro(img3dro); // expected-error{{passing '__read_only image3d_t' to parameter of incompatible type '__read_only image2d_t'}} } + +kernel void read_only_access_test(read_only image2d_t img) { + img2d_ro(img); // read_only = read_only + img2d_wo(img); // expected-error {{passing '__read_only image2d_t' to parameter of incompatible type '__write_only image2d_t'}} + img2d_rw(img); // expected-error {{passing '__read_only image2d_t' to parameter of incompatible type '__read_write image2d_t'}} + img2d_default(img); // read_only = read_only +} + +kernel void write_only_access_test(write_only image2d_t img) { + img2d_ro(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}} + img2d_wo(img); // write_only = write_only + img2d_rw(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_write image2d_t'}} + img2d_default(img); // expected-error {{passing '__write_only image2d_t' to parameter of incompatible type '__read_only image2d_t'}} +} + +kernel void read_write_access_test(read_write image2d_t img) { + img2d_ro(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__read_only image2d_t'}} + img2d_wo(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__write_only image2d_t'}} + img2d_rw(img); //read_write = read_write + img2d_default(img); // expected-error {{passing '__read_write image2d_t' to parameter of incompatible type '__read_only image2d_t'}} +} diff --git a/test/SemaTemplate/constexpr-instantiate.cpp b/test/SemaTemplate/constexpr-instantiate.cpp index dfb8a07d3b7d..31dbdb617a6a 100644 --- a/test/SemaTemplate/constexpr-instantiate.cpp +++ b/test/SemaTemplate/constexpr-instantiate.cpp @@ -191,7 +191,7 @@ namespace Unevaluated { static constexpr bool f() { return sizeof(T) < U::size; } template<typename U> - static typename enable_if<f<U>(), void>::type g() {} // expected-note {{disabled by 'enable_if'}} + static typename enable_if<f<U>(), void>::type g() {} // expected-note {{requirement 'f<Unevaluated::PR13423::U>()' was not satisfied}} }; struct U { static constexpr int size = 2; }; diff --git a/test/SemaTemplate/overload-candidates.cpp b/test/SemaTemplate/overload-candidates.cpp index c0abb5b17488..de998d74f9af 100644 --- a/test/SemaTemplate/overload-candidates.cpp +++ b/test/SemaTemplate/overload-candidates.cpp @@ -47,7 +47,7 @@ namespace boost { template<bool, typename = void> struct enable_if {}; template<typename T> struct enable_if<true, T> { typedef T type; }; } -template<typename T> typename boost::enable_if<sizeof(T) == 4, int>::type if_size_4(); // expected-note{{candidate template ignored: disabled by 'enable_if' [with T = char]}} +template<typename T> typename boost::enable_if<sizeof(T) == 4, int>::type if_size_4(); // expected-note{{candidate template ignored: requirement 'sizeof(char) == 4' was not satisfied [with T = char]}} int k = if_size_4<char>(); // expected-error{{no matching function}} namespace llvm { @@ -61,7 +61,7 @@ void test_if_int() { } template<typename T> struct NonTemplateFunction { - typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{no type named 'type' in 'boost::enable_if<false, int>'; 'enable_if' cannot be used to disable this declaration}} + typename boost::enable_if<sizeof(T) == 4, int>::type f(); // expected-error{{failed requirement 'sizeof(char) == 4'; 'enable_if' cannot be used to disable this declaration}} }; NonTemplateFunction<char> NTFC; // expected-note{{here}} @@ -100,7 +100,7 @@ namespace PR15673 { #if __cplusplus <= 199711L // expected-warning@-2 {{default template arguments for a function template are a C++11 extension}} #endif - // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}} + // expected-note@+1 {{candidate template ignored: requirement 'a_trait<int>::value' was not satisfied [with T = int]}} void foo() {} void bar() { foo<int>(); } // expected-error {{no matching function for call to 'foo'}} @@ -128,7 +128,7 @@ namespace PR15673 { #if __cplusplus <= 199711L // expected-warning@-2 {{alias declarations are a C++11 extension}} #endif - // expected-note@-4 {{candidate template ignored: disabled by 'enable_if' [with T = int]}} + // expected-note@+7 {{candidate template ignored: requirement 'some_trait<int>::value' was not satisfied [with T = int]}} template<typename T, typename Requires = unicorns<T> > @@ -137,4 +137,30 @@ namespace PR15673 { #endif void wibble() {} void wobble() { wibble<int>(); } // expected-error {{no matching function for call to 'wibble'}} + + template<typename T> + struct some_passing_trait : std::true_type {}; + +#if __cplusplus <= 199711L + // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}} + // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}} +#endif + template<typename T, + int n = 42, + typename std::enable_if<n == 43 || (some_passing_trait<T>::value && some_trait<T>::value), int>::type = 0> + void almost_rangesv3(); // expected-note{{candidate template ignored: requirement '42 == 43 || (some_passing_trait<int>::value && some_trait<int>::value)' was not satisfied}} + void test_almost_rangesv3() { almost_rangesv3<int>(); } // expected-error{{no matching function for call to 'almost_rangesv3'}} + + #define CONCEPT_REQUIRES_(...) \ + int x = 42, \ + typename std::enable_if<(x == 43) || (__VA_ARGS__)>::type = 0 + +#if __cplusplus <= 199711L + // expected-warning@+4 {{default template arguments for a function template are a C++11 extension}} + // expected-warning@+3 {{default template arguments for a function template are a C++11 extension}} +#endif + template<typename T, + CONCEPT_REQUIRES_(some_passing_trait<T>::value && some_trait<T>::value)> + void rangesv3(); // expected-note{{candidate template ignored: requirement 'some_trait<int>::value' was not satisfied [with T = int, x = 42]}} + void test_rangesv3() { rangesv3<int>(); } // expected-error{{no matching function for call to 'rangesv3'}} } diff --git a/test/Unit/lit.cfg b/test/Unit/lit.cfg index 39fad0099ceb..90eb2ac604a5 100644 --- a/test/Unit/lit.cfg +++ b/test/Unit/lit.cfg @@ -4,6 +4,7 @@ import os import platform +import subprocess import lit.formats import lit.util @@ -65,8 +66,8 @@ if config.test_exec_root is None: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() + llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip() + llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip() clang_src_root = os.path.join(llvm_src_root, "tools", "clang") clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang") diff --git a/test/lit.cfg b/test/lit.cfg index e72eca6bd397..28026578299b 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -148,8 +148,8 @@ if config.test_exec_root is None: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() + llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip() + llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip() clang_src_root = os.path.join(llvm_src_root, "tools", "clang") clang_obj_root = os.path.join(llvm_obj_root, "tools", "clang") diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 1e925569dd95..cf3581e259f7 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -804,6 +804,8 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { printf(" (const)"); if (clang_CXXMethod_isPureVirtual(Cursor)) printf(" (pure)"); + if (clang_EnumDecl_isScoped(Cursor)) + printf(" (scoped)"); if (clang_Cursor_isVariadic(Cursor)) printf(" (variadic)"); if (clang_Cursor_isObjCOptional(Cursor)) diff --git a/tools/clang-import-test/clang-import-test.cpp b/tools/clang-import-test/clang-import-test.cpp index db4dc76eded5..6b724e9cf5fa 100644 --- a/tools/clang-import-test/clang-import-test.cpp +++ b/tools/clang-import-test/clang-import-test.cpp @@ -182,14 +182,6 @@ BuildCompilerInstance(ArrayRef<const char *> ClangArgv) { return Ins; } -std::unique_ptr<CompilerInstance> -BuildCompilerInstance(ArrayRef<std::string> ClangArgs) { - std::vector<const char *> ClangArgv(ClangArgs.size()); - std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(), - [](const std::string &s) -> const char * { return s.data(); }); - return init_convenience::BuildCompilerInstance(ClangArgv); -} - std::unique_ptr<ASTContext> BuildASTContext(CompilerInstance &CI, SelectorTable &ST, Builtin::Context &BC) { auto AST = llvm::make_unique<ASTContext>( @@ -313,14 +305,8 @@ int main(int argc, const char **argv) { std::vector<std::unique_ptr<CompilerInstance>> IndirectCIs; if (!Direct) { for (auto &ImportCI : ImportCIs) { - llvm::Expected<std::unique_ptr<CompilerInstance>> IndirectCI = - BuildIndirect(ImportCI); - if (auto E = IndirectCI.takeError()) { - llvm::errs() << llvm::toString(std::move(E)); - exit(-1); - } else { - IndirectCIs.push_back(std::move(*IndirectCI)); - } + std::unique_ptr<CompilerInstance> IndirectCI = BuildIndirect(ImportCI); + IndirectCIs.push_back(std::move(IndirectCI)); } } llvm::Expected<std::unique_ptr<CompilerInstance>> ExpressionCI = diff --git a/tools/diagtool/CMakeLists.txt b/tools/diagtool/CMakeLists.txt index e88c2ab6e8c3..3f7d80385a82 100644 --- a/tools/diagtool/CMakeLists.txt +++ b/tools/diagtool/CMakeLists.txt @@ -6,6 +6,7 @@ add_clang_executable(diagtool diagtool_main.cpp DiagTool.cpp DiagnosticNames.cpp + FindDiagnosticID.cpp ListWarnings.cpp ShowEnabledWarnings.cpp TreeView.cpp diff --git a/tools/diagtool/FindDiagnosticID.cpp b/tools/diagtool/FindDiagnosticID.cpp new file mode 100644 index 000000000000..167b9925eedc --- /dev/null +++ b/tools/diagtool/FindDiagnosticID.cpp @@ -0,0 +1,58 @@ +//===- FindDiagnosticID.cpp - diagtool tool for finding diagnostic id -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DiagTool.h" +#include "DiagnosticNames.h" +#include "clang/Basic/AllDiagnostics.h" +#include "llvm/Support/CommandLine.h" + +DEF_DIAGTOOL("find-diagnostic-id", "Print the id of the given diagnostic", + FindDiagnosticID) + +using namespace clang; +using namespace diagtool; + +static Optional<DiagnosticRecord> +findDiagnostic(ArrayRef<DiagnosticRecord> Diagnostics, StringRef Name) { + for (const auto &Diag : Diagnostics) { + StringRef DiagName = Diag.getName(); + if (DiagName == Name) + return Diag; + } + return None; +} + +int FindDiagnosticID::run(unsigned int argc, char **argv, + llvm::raw_ostream &OS) { + static llvm::cl::OptionCategory FindDiagnosticIDOptions( + "diagtool find-diagnostic-id options"); + + static llvm::cl::opt<std::string> DiagnosticName( + llvm::cl::Positional, llvm::cl::desc("<diagnostic-name>"), + llvm::cl::Required, llvm::cl::cat(FindDiagnosticIDOptions)); + + std::vector<const char *> Args; + Args.push_back("find-diagnostic-id"); + for (const char *A : llvm::makeArrayRef(argv, argc)) + Args.push_back(A); + + llvm::cl::HideUnrelatedOptions(FindDiagnosticIDOptions); + llvm::cl::ParseCommandLineOptions((int)Args.size(), Args.data(), + "Diagnostic ID mapping utility"); + + ArrayRef<DiagnosticRecord> AllDiagnostics = getBuiltinDiagnosticsByName(); + Optional<DiagnosticRecord> Diag = + findDiagnostic(AllDiagnostics, DiagnosticName); + if (!Diag) { + llvm::errs() << "error: invalid diagnostic '" << DiagnosticName << "'\n"; + return 1; + } + OS << Diag->DiagID << "\n"; + return 0; +} diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index deaab3608e62..236f264c1758 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -7086,8 +7086,10 @@ CXLinkageKind clang_getCursorLinkage(CXCursor cursor) { switch (ND->getLinkageInternal()) { case NoLinkage: case VisibleNoLinkage: return CXLinkage_NoLinkage; + case ModuleInternalLinkage: case InternalLinkage: return CXLinkage_Internal; case UniqueExternalLinkage: return CXLinkage_UniqueExternal; + case ModuleLinkage: case ExternalLinkage: return CXLinkage_External; }; @@ -7805,6 +7807,15 @@ unsigned clang_CXXMethod_isVirtual(CXCursor C) { return (Method && Method->isVirtual()) ? 1 : 0; } +unsigned clang_EnumDecl_isScoped(CXCursor C) { + if (!clang_isDeclaration(C.kind)) + return 0; + + const Decl *D = cxcursor::getCursorDecl(C); + auto *Enum = dyn_cast_or_null<EnumDecl>(D); + return (Enum && Enum->isScoped()) ? 1 : 0; +} + //===----------------------------------------------------------------------===// // Attribute introspection. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CXIndexDataConsumer.cpp b/tools/libclang/CXIndexDataConsumer.cpp index 9cd5ff4f505f..a2ef68be49de 100644 --- a/tools/libclang/CXIndexDataConsumer.cpp +++ b/tools/libclang/CXIndexDataConsumer.cpp @@ -423,11 +423,13 @@ bool CXIndexDataConsumer::isFunctionLocalDecl(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { switch (ND->getFormalLinkage()) { case NoLinkage: - case VisibleNoLinkage: case InternalLinkage: return true; + case VisibleNoLinkage: + case ModuleInternalLinkage: case UniqueExternalLinkage: llvm_unreachable("Not a sema linkage"); + case ModuleLinkage: case ExternalLinkage: return false; } diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index e78899e4c759..e0d178a5291a 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -12,6 +12,7 @@ clang_CXXMethod_isConst clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual +clang_EnumDecl_isScoped clang_Cursor_getArgument clang_Cursor_getNumTemplateArguments clang_Cursor_getTemplateArgumentKind diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index dfaa441cd764..58c26eafd7e0 100644 --- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -666,6 +666,12 @@ TEST(Matcher, IntegerLiterals) { EXPECT_TRUE(notMatches("int i = 'a';", HasIntLiteral)); EXPECT_TRUE(notMatches("int i = 1e10;", HasIntLiteral)); EXPECT_TRUE(notMatches("int i = 10.0;", HasIntLiteral)); + + // Negative integers. + EXPECT_TRUE( + matches("int i = -10;", + unaryOperator(hasOperatorName("-"), + hasUnaryOperand(integerLiteral(equals(10)))))); } TEST(Matcher, FloatLiterals) { diff --git a/unittests/Format/CMakeLists.txt b/unittests/Format/CMakeLists.txt index 5c04ba1143c6..fa7e32c33d9f 100644 --- a/unittests/Format/CMakeLists.txt +++ b/unittests/Format/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_unittest(FormatTests FormatTestObjC.cpp FormatTestProto.cpp FormatTestSelective.cpp + FormatTestTextProto.cpp NamespaceEndCommentsFixerTest.cpp SortImportsTestJS.cpp SortIncludesTest.cpp diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index b5f959f9c1f7..937362f5c9d7 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -825,12 +825,35 @@ TEST_F(FormatTest, FormatsSwitchStatement) { " case A:\n" " f();\n" " break;\n" - " // On B:\n" + " // fallthrough\n" " case B:\n" " g();\n" " break;\n" " }\n" "});"); + EXPECT_EQ("DEBUG({\n" + " switch (x) {\n" + " case A:\n" + " f();\n" + " break;\n" + " // On B:\n" + " case B:\n" + " g();\n" + " break;\n" + " }\n" + "});", + format("DEBUG({\n" + " switch (x) {\n" + " case A:\n" + " f();\n" + " break;\n" + " // On B:\n" + " case B:\n" + " g();\n" + " break;\n" + " }\n" + "});", + getLLVMStyle())); verifyFormat("switch (a) {\n" "case (b):\n" " return;\n" diff --git a/unittests/Format/FormatTestComments.cpp b/unittests/Format/FormatTestComments.cpp index fdb5a08e7a21..7916e65e5114 100644 --- a/unittests/Format/FormatTestComments.cpp +++ b/unittests/Format/FormatTestComments.cpp @@ -805,6 +805,70 @@ TEST_F(FormatTestComments, ParsesCommentsAdjacentToPPDirectives) { format("namespace {}\n /* Test */ #define A")); } +TEST_F(FormatTestComments, KeepsLevelOfCommentBeforePPDirective) { + // Keep the current level if the comment was originally not aligned with + // the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + " /* comment */\n" + "#ifdef A\n" + " int j;\n" + "}")); + + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}")); + + // Keep the current level if there is an empty line between the comment and + // the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + " /* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + "/* comment */\n" + "\n" + "#ifdef A\n" + " int j;\n" + "}")); + + // Align with the preprocessor directive if the comment was originally aligned + // with the preprocessor directive. + EXPECT_EQ("void f() {\n" + " int i;\n" + "/* comment */\n" + "#ifdef A\n" + " int j;\n" + "}", + format("void f() {\n" + " int i;\n" + "/* comment */\n" + "#ifdef A\n" + " int j;\n" + "}")); +} + TEST_F(FormatTestComments, SplitsLongLinesInComments) { EXPECT_EQ("/* This is a long\n" " * comment that\n" diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index e84f470687ec..11e386a1c7c7 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -930,6 +930,14 @@ TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) { " aaa\n" "];", getGoogleJSStyleWithColumns(12)); + verifyFormat("class X {\n" + " readonly ratherLongField =\n" + " 1;\n" + "}", + "class X {\n" + " readonly ratherLongField = 1;\n" + "}", + getGoogleJSStyleWithColumns(20)); } TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) { @@ -1622,6 +1630,7 @@ TEST_F(FormatTestJS, NestedTemplateStrings) { TEST_F(FormatTestJS, TaggedTemplateStrings) { verifyFormat("var x = html`<ul>`;"); + verifyFormat("yield `hello`;"); } TEST_F(FormatTestJS, CastSyntax) { diff --git a/unittests/Format/FormatTestProto.cpp b/unittests/Format/FormatTestProto.cpp index 2e3b9311d12c..639da87c6ea9 100644 --- a/unittests/Format/FormatTestProto.cpp +++ b/unittests/Format/FormatTestProto.cpp @@ -199,11 +199,11 @@ TEST_F(FormatTestProto, FormatsOptions) { "};"); verifyFormat("option (MyProto.options) = {\n" " field_c: \"OK\"\n" - " msg_field{field_d: 123}\n" + " msg_field {field_d: 123}\n" "};"); verifyFormat("option (MyProto.options) = {\n" " field_a: OK\n" - " field_b{field_c: OK}\n" + " field_b {field_c: OK}\n" " field_d: OKOKOK\n" " field_e: OK\n" "}"); @@ -216,7 +216,7 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = {\n" " field_a: OK\n" - " field_b<field_c: OK>\n" + " field_b <field_c: OK>\n" " field_d: OKOKOK\n" " field_e: OK\n" "}"); @@ -255,7 +255,7 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = <\n" " field_a: \"OK\"\n" - " msg_field<\n" + " msg_field <\n" " field_b: OK\n" " field_c: OK\n" " field_d: OK\n" @@ -267,7 +267,7 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = <\n" " field_a: \"OK\"\n" - " msg_field<\n" + " msg_field <\n" " field_b: OK,\n" " field_c: OK,\n" " field_d: OK,\n" @@ -303,7 +303,7 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = <\n" " field_a: \"OK\"\n" - " msg_field{\n" + " msg_field {\n" " field_b: OK\n" " field_c: OK\n" " field_d: OK\n" @@ -315,7 +315,7 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = {\n" " field_a: \"OK\"\n" - " msg_field<\n" + " msg_field <\n" " field_b: OK\n" " field_c: OK\n" " field_d: OK\n" @@ -339,18 +339,18 @@ TEST_F(FormatTestProto, FormatsOptions) { verifyFormat("option (MyProto.options) = <\n" " field_a: \"OK\"\n" - " msg_field{\n" + " msg_field {\n" " field_b: OK\n" " field_c: OK\n" " field_d: OK\n" - " msg_field<\n" + " msg_field <\n" " field_A: 1\n" " field_B: 2\n" " field_C: 3\n" " field_D: 4\n" " field_E: 5\n" " >\n" - " msg_field<field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n" + " msg_field <field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n" " field_e: OK\n" " field_f: OK\n" " }\n" diff --git a/unittests/Format/FormatTestTextProto.cpp b/unittests/Format/FormatTestTextProto.cpp new file mode 100644 index 000000000000..2de7e181f2cb --- /dev/null +++ b/unittests/Format/FormatTestTextProto.cpp @@ -0,0 +1,250 @@ +//===- unittest/Format/FormatTestProto.cpp --------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FormatTestUtils.h" +#include "clang/Format/Format.h" +#include "llvm/Support/Debug.h" +#include "gtest/gtest.h" + +#define DEBUG_TYPE "format-test" + +namespace clang { +namespace format { + +class FormatTestTextProto : public ::testing::Test { +protected: + static std::string format(llvm::StringRef Code, unsigned Offset, + unsigned Length, const FormatStyle &Style) { + DEBUG(llvm::errs() << "---\n"); + DEBUG(llvm::errs() << Code << "\n\n"); + std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); + tooling::Replacements Replaces = reformat(Style, Code, Ranges); + auto Result = applyAllReplacements(Code, Replaces); + EXPECT_TRUE(static_cast<bool>(Result)); + DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); + return *Result; + } + + static std::string format(llvm::StringRef Code) { + FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto); + Style.ColumnLimit = 60; // To make writing tests easier. + return format(Code, 0, Code.size(), Style); + } + + static void verifyFormat(llvm::StringRef Code) { + EXPECT_EQ(Code.str(), format(test::messUp(Code))); + } +}; + +TEST_F(FormatTestTextProto, KeepsTopLevelEntriesFittingALine) { + verifyFormat("field_a: OK field_b: OK field_c: OK field_d: OK field_e: OK"); +} + +TEST_F(FormatTestTextProto, SupportsMessageFields) { + verifyFormat("msg_field: {}"); + + verifyFormat("msg_field: {field_a: A}"); + + verifyFormat("msg_field: {field_a: \"OK\" field_b: 123}"); + + verifyFormat("msg_field: {\n" + " field_a: 1\n" + " field_b: OK\n" + " field_c: \"OK\"\n" + " field_d: 123\n" + " field_e: 23\n" + "}"); + + verifyFormat("msg_field {}"); + + verifyFormat("msg_field {field_a: A}"); + + verifyFormat("msg_field {field_a: \"OK\" field_b: 123}"); + + verifyFormat("msg_field {\n" + " field_a: 1\n" + " field_b: OK\n" + " field_c: \"OK\"\n" + " field_d: 123\n" + " field_e: 23.0\n" + " field_f: false\n" + " field_g: 'lala'\n" + " field_h: 1234.567e-89\n" + "}"); + + verifyFormat("msg_field: {msg_field {field_a: 1}}"); + + verifyFormat("id: \"ala.bala\"\n" + "item {type: ITEM_A rank: 1 score: 90.0}\n" + "item {type: ITEM_B rank: 2 score: 70.5}\n" + "item {\n" + " type: ITEM_A\n" + " rank: 3\n" + " score: 20.0\n" + " description: \"the third item has a description\"\n" + "}"); +} + +TEST_F(FormatTestTextProto, AvoidsTopLevelBinPacking) { + verifyFormat("field_a: OK\n" + "field_b: OK\n" + "field_c: OK\n" + "field_d: OK\n" + "field_e: OK\n" + "field_f: OK"); + + verifyFormat("field_a: OK\n" + "field_b: \"OK\"\n" + "field_c: \"OK\"\n" + "msg_field: {field_d: 123}\n" + "field_e: OK\n" + "field_f: OK"); + + verifyFormat("field_a: OK\n" + "field_b: \"OK\"\n" + "field_c: \"OK\"\n" + "msg_field: {field_d: 123 field_e: OK}"); + + verifyFormat("a: {\n" + " field_a: OK\n" + " field_b {field_c: OK}\n" + " field_d: OKOKOK\n" + " field_e: OK\n" + "}"); + + verifyFormat("field_a: OK,\n" + "field_b {field_c: OK},\n" + "field_d: OKOKOK,\n" + "field_e: OK"); +} + +TEST_F(FormatTestTextProto, AddsNewlinesAfterTrailingComments) { + verifyFormat("field_a: OK // Comment\n" + "field_b: 1"); + + verifyFormat("field_a: OK\n" + "msg_field: {\n" + " field_b: OK // Comment\n" + "}"); + + verifyFormat("field_a: OK\n" + "msg_field {\n" + " field_b: OK // Comment\n" + "}"); +} + +TEST_F(FormatTestTextProto, SupportsAngleBracketMessageFields) { + // Single-line tests + verifyFormat("msg_field <>"); + verifyFormat("msg_field: <>"); + verifyFormat("msg_field <field_a: OK>"); + verifyFormat("msg_field: <field_a: 123>"); + verifyFormat("msg_field <field_a <>>"); + verifyFormat("msg_field <field_a <field_b <>>>"); + verifyFormat("msg_field: <field_a <field_b: <>>>"); + verifyFormat("msg_field <field_a: OK, field_b: \"OK\">"); + verifyFormat("msg_field <field_a: OK field_b: <>, field_c: OK>"); + verifyFormat("msg_field <field_a {field_b: 1}, field_c: <field_d: 2>>"); + verifyFormat("msg_field: <field_a: OK, field_b: \"OK\">"); + verifyFormat("msg_field: <field_a: OK field_b: <>, field_c: OK>"); + verifyFormat("msg_field: <field_a {field_b: 1}, field_c: <field_d: 2>>"); + verifyFormat("field_a: \"OK\", msg_field: <field_b: 123>, field_c: {}"); + verifyFormat("field_a <field_b: 1>, msg_field: <field_b: 123>, field_c <>"); + verifyFormat("field_a <field_b: 1> msg_field: <field_b: 123> field_c <>"); + verifyFormat("field <field <field: <>>, field <>> field: <field: 1>"); + + // Multiple lines tests + verifyFormat("msg_field <\n" + " field_a: OK\n" + " field_b: \"OK\"\n" + " field_c: 1\n" + " field_d: 12.5\n" + " field_e: OK\n" + ">"); + + verifyFormat("msg_field: <>\n" + "field_c: \"OK\",\n" + "msg_field: <field_d: 123>\n" + "field_e: OK\n" + "msg_field: <field_d: 12>"); + + verifyFormat("field_a: OK,\n" + "field_b <field_c: OK>,\n" + "field_d: <12.5>,\n" + "field_e: OK"); + + verifyFormat("field_a: OK\n" + "field_b <field_c: OK>\n" + "field_d: <12.5>\n" + "field_e: OKOKOK"); + + verifyFormat("msg_field <\n" + " field_a: OK,\n" + " field_b <field_c: OK>,\n" + " field_d: <12.5>,\n" + " field_e: OK\n" + ">"); + + verifyFormat("msg_field <\n" + " field_a: <field: OK>,\n" + " field_b <field_c: OK>,\n" + " field_d: <12.5>,\n" + " field_e: OK,\n" + ">"); + + verifyFormat("msg_field: <\n" + " field_a: \"OK\"\n" + " msg_field: {field_b: OK}\n" + " field_g: OK\n" + " field_g: OK\n" + " field_g: OK\n" + ">"); + + verifyFormat("field_a {\n" + " field_d: ok\n" + " field_b: <field_c: 1>\n" + " field_d: ok\n" + " field_d: ok\n" + "}"); + + verifyFormat("field_a: {\n" + " field_d: ok\n" + " field_b: <field_c: 1>\n" + " field_d: ok\n" + " field_d: ok\n" + "}"); + + verifyFormat("field_a: <f1: 1, f2: <>>\n" + "field_b <\n" + " field_b1: <>\n" + " field_b2: ok,\n" + " field_b3: <\n" + " field_x {} // Comment\n" + " field_y: {field_z: 1}\n" + " field_w: ok\n" + " >\n" + " field {\n" + " field_x <> // Comment\n" + " field_y: <field_z: 1>\n" + " field_w: ok\n" + " msg_field: <\n" + " field: <>\n" + " field: <field: 1>\n" + " field: <field: 2>\n" + " field: <field: 3>\n" + " field: <field: 4>\n" + " field: ok\n" + " >\n" + " }\n" + ">\n" + "field: OK,\n" + "field_c <field <field <>>>"); +} +} // end namespace tooling +} // end namespace clang diff --git a/unittests/Tooling/RecursiveASTVisitorTest.cpp b/unittests/Tooling/RecursiveASTVisitorTest.cpp index 74c9c3db34d8..63dbd1475454 100644 --- a/unittests/Tooling/RecursiveASTVisitorTest.cpp +++ b/unittests/Tooling/RecursiveASTVisitorTest.cpp @@ -244,4 +244,62 @@ TEST(RecursiveASTVisitor, InitListExprIsPostOrderNoQueueVisitedTwice) { InitListExprPostOrderNoQueueVisitor::Lang_C)); } +// Check to ensure that nested name specifiers are visited. +class NestedNameSpecifiersVisitor + : public ExpectedLocationVisitor<NestedNameSpecifiersVisitor> { +public: + bool VisitRecordTypeLoc(RecordTypeLoc RTL) { + if (!RTL) + return true; + Match(RTL.getDecl()->getName(), RTL.getNameLoc()); + return true; + } + + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + if (!NNS) + return true; + if (const NamespaceDecl *ND = + NNS.getNestedNameSpecifier()->getAsNamespace()) + Match(ND->getName(), NNS.getLocalBeginLoc()); + return ExpectedLocationVisitor::TraverseNestedNameSpecifierLoc(NNS); + } +}; + +TEST(RecursiveASTVisitor, + NestedNameSpecifiersForTemplateSpecializationsAreVisited) { + StringRef Source = R"( +namespace ns { +struct Outer { + template<typename T, typename U> + struct Nested { }; + + template<typename T> + static T x; +}; +} + +template<> +struct ns::Outer::Nested<int, int>; + +template<> +struct ns::Outer::Nested<int, int> { }; + +template<typename T> +struct ns::Outer::Nested<int, T> { }; + +template<> +int ns::Outer::x<int> = 0; +)"; + NestedNameSpecifiersVisitor Visitor; + Visitor.ExpectMatch("ns", 13, 8); + Visitor.ExpectMatch("ns", 16, 8); + Visitor.ExpectMatch("ns", 19, 8); + Visitor.ExpectMatch("ns", 22, 5); + Visitor.ExpectMatch("Outer", 13, 12); + Visitor.ExpectMatch("Outer", 16, 12); + Visitor.ExpectMatch("Outer", 19, 12); + Visitor.ExpectMatch("Outer", 22, 9); + EXPECT_TRUE(Visitor.runOver(Source, NestedNameSpecifiersVisitor::Lang_CXX14)); +} + } // end anonymous namespace diff --git a/utils/TableGen/NeonEmitter.cpp b/utils/TableGen/NeonEmitter.cpp index 62fcccbacb55..49c1edce3220 100644 --- a/utils/TableGen/NeonEmitter.cpp +++ b/utils/TableGen/NeonEmitter.cpp @@ -860,10 +860,6 @@ void Type::applyModifier(char Mod) { Float = true; ElementBitwidth = 64; break; - case 'H': - Float = true; - ElementBitwidth = 16; - break; case 'g': if (AppliedQuad) Bitwidth /= 2; @@ -1010,7 +1006,7 @@ std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const { } static bool isFloatingPointProtoModifier(char Mod) { - return Mod == 'F' || Mod == 'f' || Mod == 'H'; + return Mod == 'F' || Mod == 'f'; } std::string Intrinsic::getBuiltinTypeStr() { diff --git a/utils/bash-autocomplete.sh b/utils/bash-autocomplete.sh index 775b1f45351a..1e38bcfcaad7 100755 --- a/utils/bash-autocomplete.sh +++ b/utils/bash-autocomplete.sh @@ -1,45 +1,75 @@ # Please add "source /path/to/bash-autocomplete.sh" to your .bashrc to use this. + +_clang_filedir() +{ + # _filedir function provided by recent versions of bash-completion package is + # better than "compgen -f" because the former honors spaces in pathnames while + # the latter doesn't. So we use compgen only when _filedir is not provided. + _filedir 2> /dev/null || COMPREPLY=( $( compgen -f ) ) +} + _clang() { - local cur prev words cword arg flags - _init_completion -n : || return + local cur prev words cword arg flags w1 w2 + # If latest bash-completion is not supported just initialize COMPREPLY and + # initialize variables by setting manualy. + _init_completion -n 2> /dev/null + if [[ "$?" != 0 ]]; then + COMPREPLY=() + cword=$COMP_CWORD + cur="${COMP_WORDS[$cword]}" + fi # bash always separates '=' as a token even if there's no space before/after '='. # On the other hand, '=' is just a regular character for clang options that # contain '='. For example, "-stdlib=" is defined as is, instead of "-stdlib" and "=". # So, we need to partially undo bash tokenization here for integrity. - local w1="${COMP_WORDS[$cword - 1]}" - local w2="${COMP_WORDS[$cword - 2]}" + w1="${COMP_WORDS[$cword - 1]}" + if [[ $cword > 1 ]]; then + w2="${COMP_WORDS[$cword - 2]}" + # Clang want to know if -cc1 or -Xclang option is specified or not, because we don't want to show + # cc1 options otherwise. + if [[ "${COMP_WORDS[1]}" == "-cc1" || "$w1" == "-Xclang" ]]; then + arg="#" + fi if [[ "$cur" == -* ]]; then # -foo<tab> - arg="$cur" + arg="$arg$cur" elif [[ "$w1" == -* && "$cur" == '=' ]]; then # -foo=<tab> - arg="$w1=," + arg="$arg$w1=," + elif [[ "$cur" == -*= ]]; then + # -foo=<tab> + arg="$arg$cur," elif [[ "$w1" == -* ]]; then # -foo <tab> or -foo bar<tab> - arg="$w1,$cur" + arg="$arg$w1,$cur" elif [[ "$w2" == -* && "$w1" == '=' ]]; then # -foo=bar<tab> - arg="$w2=,$cur" + arg="$arg$w2=,$cur" + elif [[ ${cur: -1} != '=' && ${cur/=} != $cur ]]; then + # -foo=bar<tab> + arg="$arg${cur%=*}=,${cur#*=}" fi - flags=$( "${COMP_WORDS[0]}" --autocomplete="$arg" 2>/dev/null ) + # expand ~ to $HOME + eval local path=${COMP_WORDS[0]} + flags=$( "$path" --autocomplete="$arg" 2>/dev/null ) # If clang is old that it does not support --autocomplete, # fall back to the filename completion. if [[ "$?" != 0 ]]; then - _filedir + _clang_filedir return fi if [[ "$cur" == '=' ]]; then COMPREPLY=( $( compgen -W "$flags" -- "") ) elif [[ "$flags" == "" || "$arg" == "" ]]; then - _filedir + _clang_filedir else # Bash automatically appends a space after '=' by default. # Disable it so that it works nicely for options in the form of -foo=bar. - [[ "${flags: -1}" == '=' ]] && compopt -o nospace + [[ "${flags: -1}" == '=' ]] && compopt -o nospace 2> /dev/null COMPREPLY=( $( compgen -W "$flags" -- "$cur" ) ) fi } diff --git a/utils/perf-training/lit.cfg b/utils/perf-training/lit.cfg index edae551bed3f..671d44f83b94 100644 --- a/utils/perf-training/lit.cfg +++ b/utils/perf-training/lit.cfg @@ -3,13 +3,14 @@ from lit import Test import lit.formats import lit.util +import subprocess def getSysrootFlagsOnDarwin(config, lit_config): # On Darwin, support relocatable SDKs by providing Clang with a # default system root path. if 'darwin' in config.target_triple: try: - out = lit.util.capture(['xcrun', '--show-sdk-path']).strip() + out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip() res = 0 except OSError: res = -1 diff --git a/utils/perf-training/order-files.lit.cfg b/utils/perf-training/order-files.lit.cfg index a4fd81232a46..93904ec84a41 100644 --- a/utils/perf-training/order-files.lit.cfg +++ b/utils/perf-training/order-files.lit.cfg @@ -4,13 +4,14 @@ from lit import Test import lit.formats import lit.util import os +import subprocess def getSysrootFlagsOnDarwin(config, lit_config): # On Darwin, support relocatable SDKs by providing Clang with a # default system root path. if 'darwin' in config.target_triple: try: - out = lit.util.capture(['xcrun', '--show-sdk-path']).strip() + out = subprocess.check_output(['xcrun', '--show-sdk-path']).strip() res = 0 except OSError: res = -1 diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html index 93c98913fdc2..cdc2496b99ca 100644 --- a/www/analyzer/checker_dev_manual.html +++ b/www/analyzer/checker_dev_manual.html @@ -279,8 +279,8 @@ void ento::registerSimpleStreamChecker(CheckerManager &mgr) { } </pre> <li>A package was selected for the checker and the checker was defined in the -table of checkers at <tt>lib/StaticAnalyzer/Checkers/Checkers.td</tt>. Since all -checkers should first be developed as "alpha", and the SimpleStreamChecker +table of checkers at <tt>include/clang/StaticAnalyzer/Checkers/Checkers.td</tt>. +Since all checkers should first be developed as "alpha", and the SimpleStreamChecker performs UNIX API checks, the correct package is "alpha.unix", and the following was added to the corresponding <tt>UnixAlpha</tt> section of <tt>Checkers.td</tt>: <pre class="code_example"> diff --git a/www/analyzer/scripts/expandcollapse.js b/www/analyzer/scripts/expandcollapse.js index 593a9831c8b0..c3ae2864670e 100644 --- a/www/analyzer/scripts/expandcollapse.js +++ b/www/analyzer/scripts/expandcollapse.js @@ -81,7 +81,7 @@ function initExpandCollapse() { expander.onclick = function() { expandCollapse(this.id); // Hack for Opera - onmouseout callback is not invoked when page - // content changes dinamically and mouse pointer goes out of an element. + // content changes dynamically and mouse pointer goes out of an element. this.src = imgPath + (getCellInfo(this.id).expanded ? "arrows_light.gif" : "ellipses_light.gif"); diff --git a/www/cxx_status.html b/www/cxx_status.html index c67bf65322a1..23d95bda67c0 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -14,6 +14,7 @@ span:target { background-color: #FFFFBB; outline: #DDDD55 solid thin; } th { background-color: #FFDDAA } td { vertical-align: middle } + tt { white-space: nowrap } </style> </head> <body> @@ -25,7 +26,7 @@ <!--*************************************************************************--> <h1>C++ Support in Clang</h1> <!--*************************************************************************--> -<p>Last updated: $Date: 2017-05-28 19:35:23 +0200 (Sun, 28 May 2017) $</p> +<p>Last updated: $Date: 2017-07-06 02:29:13 +0200 (Thu, 06 Jul 2017) $</p> <p>Clang fully implements all published ISO C++ standards (<a href="#cxx98">C++98 / C++03</a>, <a @@ -832,7 +833,7 @@ and library features that are not part of standard C++.</p> <tr> <td>[DRAFT TS] Coroutines</td> <td><a href="https://isocpp.org/files/papers/N4663.pdf">N4663</a></td> - <td><tt>‑fcoroutines‑ts<br>-stdlib=libc++</tt></td> + <td><tt>-fcoroutines-ts<br>-stdlib=libc++</tt></td> <td class="svn" align="center">SVN</td> </tr> <tr> @@ -849,7 +850,7 @@ and library features that are not part of standard C++.</p> </tr> <tr> <td>[DRAFT TS] Modules</td> - <td><a href="http://wg21.link/n4592">N4592</a></td> + <td><a href="http://wg21.link/n4667">N4667</a></td> <td><tt>-fmodules-ts</tt></td> <td class="none" align="center">WIP</td> </tr> |